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

test

parent 5bdbffd6
Loading
Loading
Loading
Loading
+43 −6
Original line number Diff line number Diff line
@@ -3914,10 +3914,23 @@ size_t libhttppp::HttpResponse::parse(const char *data, size_t inlen) {
            key[i] = static_cast<char>(std::tolower(static_cast<unsigned char>(key[i])));
        }

        HeaderData* ncontent = setHeaderData(key.c_str());
        // Use getHeaderData first so that repeated header lines (e.g. multiple
        // Set-Cookie: lines) APPEND values instead of clobbering earlier ones.
        HeaderData* ncontent = getHeaderData(key);
        if (!ncontent) ncontent = setHeaderData(key.c_str());
        if (!ncontent)
            continue;

        if (key == "set-cookie") {
            // Set-Cookie must never be comma-split: its own value legitimately
            // contains commas (e.g. "Expires=Wed, 21 Oct 2026 07:28:00 GMT"),
            // and RFC 7230 Sec3.2.2 singles it out as the header that cannot
            // be combined/split as a comma list. Each physical line is exactly
            // one cookie.
            ncontent->push_back(value);
            continue;
        }

        // Split value on commas (HTTP list headers: TE, Accept, etc.)
        size_t oldiv = 0;
        size_t iv = 0;
@@ -4394,7 +4407,11 @@ size_t libhttppp::HttpRequest::parseH1() {
      }

      // store header: split value on ';' into tokens (preserving case)
      HeaderData* ncontent = setHeaderData(key);
      // Use getHeaderData first so that duplicate header lines (e.g. repeated
      // Cookie: lines) APPEND values instead of clobbering earlier ones --
      // matches parseH2/parseH3 behaviour.
      HeaderData* ncontent = getHeaderData(key);
      if (!ncontent) ncontent = setHeaderData(key);
      if (!ncontent) continue;

      size_t oldiv = 0, iv = 0;
@@ -4461,15 +4478,35 @@ void libhttppp::HttpRequest::printHeader(std::string &buffer){
  buffer.append(_cachedRequestVersion);
  buffer.append("\r\n");

  // One "Key: value\r\n" line per value -- see HttpResponse::printHeader's twin above for why
  // folding multiple values of the same header onto one "; "-joined line is wrong (breaks any
  // multi-instance header whose values may contain ";"/",", not just Set-Cookie, which never
  // appears on a request but the same serialization is shared logic).
  // One "Key: value\r\n" line per value for most headers -- a request has no
  // Set-Cookie, so there's no comma/semicolon-in-value hazard to protect
  // against by keeping instances on separate lines (see HttpResponse::printHeader).
  // Cookie is the one request header that must NOT be split across multiple
  // lines: RFC 6265 Sec5.4 requires a user agent to send exactly one Cookie
  // header field, with pairs joined by "; ". parseH2/parseH3 split an incoming
  // multi-cookie header into separate Values on ';', so re-serializing those as
  // separate "Cookie:" lines to an H1 upstream breaks the round trip -- the
  // upstream's own H1 parser then keeps only the last line's cookie.
  for(HeaderData *curdat=getfirstHeaderData(); curdat; curdat=curdat->nextHeaderData()){
    // Skip pseudo-headers and response pseudo-headers in H1 output
    const std::string &key = curdat->getkey();
    if (!key.empty() && key[0] == ':') continue;

    if (key == "cookie") {
      std::string joined;
      for(HeaderData::Values *cval=curdat->getfirstValue(); cval; cval=cval->nextvalue()){
        if (!joined.empty()) joined.append("; ");
        joined.append(cval->getvalue());
      }
      if (!joined.empty()) {
        buffer.append(key);
        buffer.append(": ");
        buffer.append(joined);
        buffer.append("\r\n");
      }
      continue;
    }

    for(HeaderData::Values *cval=curdat->getfirstValue(); cval; cval=cval->nextvalue()){
      buffer.append(key);
      buffer.append(": ");