]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/seastar/src/http/response_parser.rl
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / seastar / src / http / response_parser.rl
index 95ad8c644235eb816be100dac24512e1b01f4c26..d51ae7501d19fd779226c65e53921d02be82e218 100644 (file)
@@ -53,11 +53,28 @@ action store_value {
     _value = str();
 }
 
+action trim_trailing_whitespace_and_store_value {
+    _value = str();
+    trim_trailing_spaces_and_tabs(_value);
+    g.mark_start(nullptr);
+}
+
 action assign_field {
-    _rsp->_headers[_field_name] = std::move(_value);
+    auto [iter, inserted] = _rsp->_headers.try_emplace(_field_name, std::move(_value));
+    if (!inserted) {
+        // RFC 7230, section 3.2.2.  Field Parsing:
+        // A recipient MAY combine multiple header fields with the same field name into one
+        // "field-name: field-value" pair, without changing the semantics of the message,
+        // by appending each subsequent field value to the combined field value in order, separated by a comma.
+        iter->second += sstring(",") + std::move(_value);
+    }
 }
 
 action extend_field  {
+    // RFC 7230, section 3.2.4.  Field Order:
+    // A server that receives an obs-fold in a request message that is not
+    // within a message/http container MUST either reject the message [...]
+    // or replace each received obs-fold with one or more SP octets [...]
     _rsp->_headers[_field_name] += sstring(" ") + std::move(_value);
 }
 
@@ -83,14 +100,22 @@ sp_ht = sp | ht;
 
 http_version = 'HTTP/' (digit '.' digit) >mark %store_version;
 
+obs_text = 0x80..0xFF; # defined in RFC 7230, Section 3.2.6.
+field_vchar = (graph | obs_text);
+# RFC 9110, Section 5.5 allows single ' '/'\t' separators between
+# field_vchar words. We are less strict and allow any number of spaces
+# between words.
+# Trailing spaces are trimmed in postprocessing.
+field_content = (field_vchar | sp_ht)*;
+
 field = tchar+ >mark %store_field_name;
-value = any* >mark %store_value;
+value = field_content >mark %trim_trailing_whitespace_and_store_value;
 status_code = (digit digit digit) >mark %store_status;
 start_line = http_version space status_code space (any - cr - lf)* crlf;
-header_1st = (field sp_ht* ':' value :> crlf) %assign_field;
-header_cont = (sp_ht+ value sp_ht* crlf) %extend_field;
+header_1st = (field ':' sp_ht* <: value crlf) %assign_field;
+header_cont = (sp_ht+ <: value crlf) %extend_field;
 header = header_1st header_cont*;
-main := start_line header* :> (crlf @done);
+main := start_line header* (crlf @done);
 
 }%%
 
@@ -129,7 +154,13 @@ public:
 #pragma clang diagnostic pop
 #endif
         if (!done) {
-            p = nullptr;
+            if (p == eof) {
+                _state = state::eof;
+            } else if (p != pe) {
+                _state = state::error;
+            } else {
+                p = nullptr;
+            }
         } else {
             _state = state::done;
         }
@@ -141,6 +172,9 @@ public:
     bool eof() const {
         return _state == state::eof;
     }
+    bool failed() const {
+        return _state == state::error;
+    }
 };
 
 }