Commit 9a8cfc9f authored by jan.koester's avatar jan.koester
Browse files

test

parent 2807a6b2
Loading
Loading
Loading
Loading
+23 −5
Original line number Diff line number Diff line
@@ -679,7 +679,9 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe
            }

            if (chunk_size == 0) {
                for (;;) {
                // Consume trailers (limit to 128 to prevent unbounded
                // memory growth from a malicious server).
                for (int trailer_i = 0; trailer_i < 128; ++trailer_i) {
                    std::string tline = read_line();
                    if (tline.empty()) break;
                }
@@ -1299,6 +1301,10 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) {
            }
        };

        // Iterative loop: avoids tail-recursion when a new chunk is parsed
        // but no data is returned yet (chunk header consumed, data follows).
        for (;;) {

        // If we're in the middle of a chunk, continue reading chunk data
        if (_streamChunkRemaining > 0) {
            size_t want = (std::min)(bufsize, _streamChunkRemaining);
@@ -1356,8 +1362,9 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) {
        }

        if (chunk_size == 0) {
            // Final chunk — consume trailers
            for (;;) {
            // Final chunk — consume trailers (limit to 128 to prevent
            // unbounded memory growth from a malicious server).
            for (int trailer_i = 0; trailer_i < 128; ++trailer_i) {
                std::string tline = readLine();
                if (tline.empty()) break;
            }
@@ -1367,8 +1374,10 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) {
        }

        _streamChunkRemaining = chunk_size;
        // Recurse to actually read data from this chunk
        return readBodyChunk(buf, bufsize);
        // Loop back to read data from this new chunk (iterative instead of
        // recursive to avoid stack overflow on many consecutive chunks).
        continue;
        } // end for(;;)
    }

    // ── EOF mode (no content-length, not chunked) ──
@@ -2319,7 +2328,16 @@ const std::vector<char> libhttppp::HttpClient::_h2Request(
            }
        };

        // Overall response deadline: prevents infinite loops when a
        // malicious server sends endless non-terminal frames (e.g. PINGs).
        auto h2_response_deadline = std::chrono::steady_clock::now() + std::chrono::seconds(120);

        while (!got_end_stream) {
            if (std::chrono::steady_clock::now() >= h2_response_deadline) {
                HTTPException ee;
                ee[HTTPException::Error] << "HTTP/2 response timeout: no END_STREAM received";
                throw ee;
            }
            // Read frame header (9 bytes)
            ensure_bytes(H2C_FRAME_HEADER_LEN);

+10 −1
Original line number Diff line number Diff line
@@ -757,6 +757,7 @@ bool libhttppp::HttpEvent::Http2RequestEvent(netplus::con &curcon,
    std::string out;
    out.reserve(4096);  // Pre-allocate to avoid repeated reallocations
    size_t off = 0;
    int reprocess_count = 0;

    // Consume HTTP/2 client connection preface if present
    if (cureq.RecvData.size() >= H2_CLIENT_PREFACE_LEN &&
@@ -1063,7 +1064,10 @@ done:
    // Only reprocess if we actually made progress (consumed frames or
    // generated output). Otherwise we'd spin forever on an incomplete
    // frame that needs more network data to arrive.
    if ((!out.empty() || off > 0) && cureq.RecvData.size() >= H2_FRAME_HEADER_LEN) {
    // Guard: limit reprocessing iterations to prevent infinite spin when
    // frames continuously generate output (e.g. ACKs) without consuming data.
    if (reprocess_count < 16 && (!out.empty() || off > 0) && cureq.RecvData.size() >= H2_FRAME_HEADER_LEN) {
        ++reprocess_count;
        out.clear();
        out.reserve(4096);
        off = 0;
@@ -1377,6 +1381,11 @@ void libhttppp::HttpEvent::RequestEvent(netplus::con &curcon,const int tid,ULONG
        }

REQUESTHANDLING:
        // Guard: only loop for HTTP/1.x; HTTP/2 and HTTP/3 parse() always
        // returns 1, which would cause an infinite loop here.
        if (cureq._httpProtocol != 0) {
            return;
        }
        switch(cureq.getRequestType()){
            case PARSEREQUEST:
                if(cureq.parse()!=0)