Commit cbcea9b4 authored by jan.koester's avatar jan.koester
Browse files

test

parent 6aaf9605
Loading
Loading
Loading
Loading
+79 −55
Original line number Diff line number Diff line
@@ -4104,8 +4104,12 @@ size_t libhttppp::HttpRequest::parseH2(const std::vector<hpack::HeaderField> &he
  SendData.pos = 0;

  // Store ALL headers (including pseudo-headers) in _firstHeaderData.
  // Split values by ';' (matching parseH1 behaviour) so that cookie
  // parsing and other code that iterates individual Values works.
  // Only Cookie's grammar (RFC 6265 SS4.2.1) packs several "name=value"
  // pairs into one field separated by ';' -- every other header (User-Agent
  // above all) is one value per HPACK field, full stop. Blanket-splitting
  // on ';' shredded semicolon-heavy values like User-Agent into bogus
  // fragments that then got re-serialized as literal duplicate header
  // fields when forwarded upstream. See HttpResponse::parse()'s fix.
  auto trim = [](std::string& s) {
    size_t i = 0;
    while (i < s.size() && (s[i] == ' ' || s[i] == '\t')) ++i;
@@ -4123,6 +4127,7 @@ size_t libhttppp::HttpRequest::parseH2(const std::vector<hpack::HeaderField> &he
    if (!hd) hd = setHeaderData(h.name);
    if (!hd) continue;
    const std::string &val = h.value;
    if (h.name == "cookie") {
      size_t oldiv = 0, iv = 0;
      while (iv < val.size()) {
        if (val[iv] == ';') {
@@ -4139,6 +4144,9 @@ size_t libhttppp::HttpRequest::parseH2(const std::vector<hpack::HeaderField> &he
      std::string token = val.substr(oldiv);
      trim(token);
      if (!token.empty()) hd->push_back(token);
    } else if (!val.empty()) {
      hd->push_back(val);
    }
  }

  // Store :authority as host header too (RFC 7540 §8.1.2.3)
@@ -4175,8 +4183,12 @@ size_t libhttppp::HttpRequest::parseH3(const std::vector<qpack::HeaderField> &he
  SendData.pos = 0;

  // Store ALL headers (including pseudo-headers) in _firstHeaderData.
  // Split values by ';' (matching parseH1 behaviour) so that cookie
  // parsing and other code that iterates individual Values works.
  // Only Cookie's grammar (RFC 6265 SS4.2.1) packs several "name=value"
  // pairs into one field separated by ';' -- every other header (User-Agent
  // above all) is one value per QPACK field, full stop. Blanket-splitting
  // on ';' shredded semicolon-heavy values like User-Agent into bogus
  // fragments that then got re-serialized as literal duplicate header
  // fields when forwarded upstream. See HttpResponse::parse()'s fix.
  auto trim = [](std::string& s) {
    size_t i = 0;
    while (i < s.size() && (s[i] == ' ' || s[i] == '\t')) ++i;
@@ -4194,6 +4206,7 @@ size_t libhttppp::HttpRequest::parseH3(const std::vector<qpack::HeaderField> &he
    if (!hd) hd = setHeaderData(h.name);
    if (!hd) continue;
    const std::string &val = h.value;
    if (h.name == "cookie") {
      size_t oldiv = 0, iv = 0;
      while (iv < val.size()) {
        if (val[iv] == ';') {
@@ -4210,6 +4223,9 @@ size_t libhttppp::HttpRequest::parseH3(const std::vector<qpack::HeaderField> &he
      std::string token = val.substr(oldiv);
      trim(token);
      if (!token.empty()) hd->push_back(token);
    } else if (!val.empty()) {
      hd->push_back(val);
    }
  }

  // Store :authority as host header too (RFC 9114 §4.3.1)
@@ -4400,7 +4416,6 @@ size_t libhttppp::HttpRequest::parseH1() {
        key[it] = static_cast<char>(std::tolower(static_cast<unsigned char>(key[it])));
      }

      // store header: split value on ';' into tokens (preserving case)
      // Use getHeaderData first so that duplicate header lines (e.g. repeated
      // Cookie: lines) APPEND values instead of clobbering earlier ones --
      // matches parseH2/parseH3 behaviour.
@@ -4408,12 +4423,20 @@ size_t libhttppp::HttpRequest::parseH1() {
      if (!ncontent) ncontent = setHeaderData(key);
      if (!ncontent) continue;

      // Only Cookie's grammar (RFC 6265 SS4.2.1) actually packs several
      // "name=value" pairs into one line separated by ';'. Every other
      // header -- User-Agent above all, which is full of semicolons
      // ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...") -- is a single
      // value per physical line. Blanket-splitting on ';' (as this used to
      // do for every header) shredded those into bogus fragments that then
      // got re-serialized as literal duplicate header lines when forwarded
      // upstream. See HttpResponse::parse()'s identical fix above.
      if (key == "cookie") {
        size_t oldiv = 0, iv = 0;
        while (iv < value.size()) {
          if (value[iv] == ';') {
          // substring [oldiv, iv)
            std::string token = value.substr(oldiv, iv - oldiv);
          trim_inplace(token);             // remove leading/trailing spaces
            trim_inplace(token);
            if (!token.empty()) {
              ncontent->push_back(token);
            }
@@ -4427,13 +4450,14 @@ size_t libhttppp::HttpRequest::parseH1() {
          }
        }

      // last token (after last ';' or whole value if no ';')
        std::string token = value.substr(oldiv);
        trim_inplace(token);
        if (!token.empty()) {
          ncontent->push_back(token);
        }

      } else if (!value.empty()) {
        ncontent->push_back(value);
      }
    }

  } catch (netplus::NetException& e) {