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

test

parent d6b8cf97
Loading
Loading
Loading
Loading
+60 −4
Original line number Diff line number Diff line
@@ -1604,10 +1604,38 @@ size_t libhttppp::HttpRequest::parseH2(const std::vector<hpack::HeaderField> &he
  _h2BodyBytesSent = 0;
  SendData.pos = 0;

  // Store ALL headers (including pseudo-headers) in _firstHeaderData
  // 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.
  auto trim = [](std::string& s) {
    size_t i = 0;
    while (i < s.size() && (s[i] == ' ' || s[i] == '\t')) ++i;
    if (i) s.erase(0, i);
    size_t e = s.size();
    while (e && (s[e-1] == ' ' || s[e-1] == '\t')) --e;
    if (e != s.size()) s.erase(e);
  };

  for (const auto &h : headers) {
    auto *hd = setHeaderData(h.name);
    if (hd) hd->push_back(h.value);
    if (!hd) continue;
    const std::string &val = h.value;
    size_t oldiv = 0, iv = 0;
    while (iv < val.size()) {
      if (val[iv] == ';') {
        std::string token = val.substr(oldiv, iv - oldiv);
        trim(token);
        if (!token.empty()) hd->push_back(token);
        ++iv;
        while (iv < val.size() && val[iv] == ' ') ++iv;
        oldiv = iv;
      } else {
        ++iv;
      }
    }
    std::string token = val.substr(oldiv);
    trim(token);
    if (!token.empty()) hd->push_back(token);
  }

  // Store :authority as host header too (RFC 7540 §8.1.2.3)
@@ -1638,10 +1666,38 @@ size_t libhttppp::HttpRequest::parseH3(const std::vector<qpack::HeaderField> &he
  _httpProtocol = 2;
  SendData.pos = 0;

  // Store ALL headers (including pseudo-headers) in _firstHeaderData
  // 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.
  auto trim = [](std::string& s) {
    size_t i = 0;
    while (i < s.size() && (s[i] == ' ' || s[i] == '\t')) ++i;
    if (i) s.erase(0, i);
    size_t e = s.size();
    while (e && (s[e-1] == ' ' || s[e-1] == '\t')) --e;
    if (e != s.size()) s.erase(e);
  };

  for (const auto &h : headers) {
    auto *hd = setHeaderData(h.name);
    if (hd) hd->push_back(h.value);
    if (!hd) continue;
    const std::string &val = h.value;
    size_t oldiv = 0, iv = 0;
    while (iv < val.size()) {
      if (val[iv] == ';') {
        std::string token = val.substr(oldiv, iv - oldiv);
        trim(token);
        if (!token.empty()) hd->push_back(token);
        ++iv;
        while (iv < val.size() && val[iv] == ' ') ++iv;
        oldiv = iv;
      } else {
        ++iv;
      }
    }
    std::string token = val.substr(oldiv);
    trim(token);
    if (!token.empty()) hd->push_back(token);
  }

  // Store :authority as host header too (RFC 9114 §4.3.1)
+30 −5
Original line number Diff line number Diff line
@@ -193,10 +193,11 @@ static uint64_t h3DecodeVarInt(const uint8_t *data, size_t len, size_t &bytes_re

static std::vector<uint8_t> h3BuildResponse(uint16_t status_code,
                                            const std::string &body,
                                            const std::string &content_type) {
                                            const std::string &content_type,
                                            const std::vector<libhttppp::qpack::HeaderField> &extra = {}) {
    std::vector<uint8_t> out;
    std::vector<uint8_t> headers = libhttppp::qpack::Encoder::encodeResponseHeaders(
        status_code, content_type, body.size());
        status_code, content_type, body.size(), extra);

    out.push_back(0x01);
    uint8_t len_buf[8];
@@ -434,8 +435,15 @@ bool libhttppp::HttpEvent::Http2RequestEvent(netplus::con &curcon,
                    if (key == ":res-valid" || key == ":res-status" ||
                        key == ":res-content-type" || key == ":res-content-length") continue;
                    std::string realKey = key.substr(5);
                    if (hd->getfirstValue())
                        extra.push_back({realKey, hd->getfirstValue()->getvalue()});
                    // Join all Values with "; " to reconstruct the full
                    // header value (e.g. set-cookie attributes).
                    std::string joined;
                    for (auto *v = hd->getfirstValue(); v; v = v->nextvalue()) {
                        if (!joined.empty()) joined += "; ";
                        joined += v->getvalue();
                    }
                    if (!joined.empty())
                        extra.push_back({realKey, joined});
                }

                // Build HPACK-encoded HEADERS frame
@@ -604,9 +612,26 @@ void libhttppp::HttpEvent::Http3StreamEvent(netplus::socket *sock,
                    }
                }

                // Collect extra :res-* headers (e.g. set-cookie)
                std::vector<libhttppp::qpack::HeaderField> extra;
                for (auto *hd = tempreq.getfirstHeaderData(); hd; hd = hd->nextHeaderData()) {
                    const std::string &ekey = hd->getkey();
                    if (ekey.substr(0, 5) != ":res-") continue;
                    if (ekey == ":res-valid" || ekey == ":res-status" ||
                        ekey == ":res-content-type" || ekey == ":res-content-length") continue;
                    std::string realKey = ekey.substr(5);
                    std::string joined;
                    for (auto *v = hd->getfirstValue(); v; v = v->nextvalue()) {
                        if (!joined.empty()) joined += "; ";
                        joined += v->getvalue();
                    }
                    if (!joined.empty())
                        extra.push_back({realKey, joined});
                }

                std::vector<uint8_t> response = h3BuildResponse(
                    status_code, body,
                    content_type.empty() ? "text/html" : content_type);
                    content_type.empty() ? "text/html" : content_type, extra);
                q->sendStreamData(stream_id, response, true);

                // Clean up :res-* pseudo-headers