Commit 001b347b authored by jan.koester's avatar jan.koester
Browse files

NEW FEARURES

parent cf8eae4f
Loading
Loading
Loading
Loading
+67 −7
Changes for src/http.cpp: 67 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -867,8 +867,12 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest
            bool got_headers = false;
            _streamH3Sid = stream_id;

            // pumpNetwork() returns normally (never throws) when a non-blocking
            // read simply found no datagrams, so looping a fixed N times used
            // to always burn N non-blocking recv syscalls on every idle wait.
            // Stop as soon as our stream actually has something to show for it.
            auto h3_pump = [&]() {
                for (int pump_i = 0; pump_i < 16; ++pump_i) {
                for (int pump_i = 0; pump_i < 4; ++pump_i) {
                    try {
                        q->pumpNetwork(MSG_DONTWAIT);
                    } catch (netplus::NetException &e) {
@@ -876,6 +880,8 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest
                            throw;
                        break;
                    }
                    if (q->hasStreamData(stream_id) || q->isStreamComplete(stream_id))
                        break;
                }
            };

@@ -1793,9 +1799,12 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) {
            return 0;
        }

        // Pump network and read stream data
        // Pump network and read stream data. pumpNetwork() returns normally
        // (never throws) on an empty non-blocking read, so a fixed 256-iteration
        // loop used to always cost 256 non-blocking recv syscalls per call --
        // stop as soon as our stream actually has something to show for it.
        auto h3_pump = [&]() {
            for (int pump_i = 0; pump_i < 256; ++pump_i) {
            for (int pump_i = 0; pump_i < 4; ++pump_i) {
                try {
                    q->pumpNetwork(MSG_DONTWAIT);
                } catch (netplus::NetException &e) {
@@ -1803,6 +1812,8 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) {
                        throw;
                    break;
                }
                if (q->hasStreamData(_streamH3Sid) || q->isStreamComplete(_streamH3Sid))
                    break;
            }
        };

@@ -2017,8 +2028,11 @@ size_t libhttppp::HttpClient::readBodyChunkNonBlocking(char *buf, size_t bufsize
            return static_cast<size_t>(-1);
        }

        // Non-blocking pump and drain all available stream data
        for (int pump_i = 0; pump_i < 256; ++pump_i) {
        // Non-blocking pump and drain all available stream data. pumpNetwork()
        // returns normally (never throws) on an empty non-blocking read, so a
        // fixed 256-iteration loop used to always cost 256 non-blocking recv
        // syscalls per call regardless of whether anything arrived.
        for (int pump_i = 0; pump_i < 4; ++pump_i) {
            try {
                q->pumpNetwork(MSG_DONTWAIT);
            } catch (netplus::NetException &e) {
@@ -2026,6 +2040,8 @@ size_t libhttppp::HttpClient::readBodyChunkNonBlocking(char *buf, size_t bufsize
                    throw;
                break;
            }
            if (q->hasStreamData(_streamH3Sid) || q->isStreamComplete(_streamH3Sid))
                break;
        }

        {
@@ -2840,10 +2856,14 @@ const std::vector<char> libhttppp::HttpClient::_h2Request(
        return got_any;
      };

      // Helper: pump QUIC network layer (process incoming UDP datagrams)
      // Helper: pump QUIC network layer (process incoming UDP datagrams).
      // pumpNetwork() returns normally (never throws) on an empty non-blocking
      // read, so a fixed 256-iteration loop used to always cost 256 non-blocking
      // recv syscalls per call regardless of whether anything arrived. Stop as
      // soon as our stream actually has something to show for it.
      auto pumpQuic = [&]() {
        bool pumped_any = false;
        for (int pump_i = 0; pump_i < 256; ++pump_i) {
        for (int pump_i = 0; pump_i < 4; ++pump_i) {
          try {
            q->pumpNetwork(MSG_DONTWAIT);
            pumped_any = true;
@@ -2855,6 +2875,8 @@ const std::vector<char> libhttppp::HttpClient::_h2Request(
            }
            break;
          }
          if (q->hasStreamData(stream_id) || q->isStreamComplete(stream_id))
            break;
        }
        return pumped_any;
      };
@@ -3893,6 +3915,44 @@ size_t libhttppp::HttpResponse::parse(const char *data, size_t inlen) {
    return bytes_consumed;
}

// Shared by parseH2/parseH3 below: HPACK/QPACK already split each field into
// a clean name/value pair, so ingestion here is a straight copy into the
// header list -- no CRLF/colon scanning, and (unlike the old synthetic-text
// approach) no way for a value to be misinterpreted as introducing new
// header lines.
template <typename HeaderFieldT>
static size_t ingestDecodedHeaders(libhttppp::HttpResponse &resp,
                                    const std::vector<HeaderFieldT> &headers,
                                    const std::string &httpVersion) {
    int statusCode = 0;
    for (const auto &h : headers) {
        if (h.name == ":status") {
            try { statusCode = std::stoi(h.value); } catch (...) { statusCode = 0; }
            break;
        }
    }
    resp.setResponseLine(httpVersion, statusCode);

    for (const auto &h : headers) {
        if (h.name.empty() || h.name[0] == ':') continue;
        std::string key = h.name;
        for (char &c : key)
            c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
        resp.setHeaderData(key)->push_back(h.value);
    }

    resp.refreshCachedHeaders();
    return headers.size();
}

size_t libhttppp::HttpResponse::parseH2(const std::vector<hpack::HeaderField> &headers) {
    return ingestDecodedHeaders(*this, headers, "HTTP/2");
}

size_t libhttppp::HttpResponse::parseH3(const std::vector<qpack::HeaderField> &headers) {
    return ingestDecodedHeaders(*this, headers, "HTTP/3");
}

void libhttppp::HttpResponse::setTransferEncoding(const std ::string &enc){
  _TransferEncoding=setHeaderData("transfer-encoding");
  _TransferEncoding->push_back(enc);
+10 −0
Changes for src/http.h: 10 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -358,6 +358,16 @@ namespace libhttppp {
    /*client method*/
    size_t   parse(const char *in,size_t inlen);

    // Ingest already-decoded HPACK/QPACK header fields directly (client
    // side, HTTP/2 and HTTP/3). Avoids building a synthetic HTTP/1.1-style
    // text block and reparsing it -- besides the redundant copy/reparse,
    // that round-trip had no way to reject a header value containing an
    // embedded "\r\n", letting a malicious/compromised peer inject extra
    // header lines (including a premature blank line truncating the block).
    // Returns the number of header fields ingested.
    size_t parseH2(const std::vector<hpack::HeaderField> &headers);
    size_t parseH3(const std::vector<qpack::HeaderField> &headers);

  private:
    bool _storeResponseInfo(netplus::con &curconnection, int datalen);