Loading src/http.cpp +47 −14 Original line number Diff line number Diff line Loading @@ -807,6 +807,7 @@ static constexpr uint8_t H2C_FRAME_SETTINGS = 0x04; static constexpr uint8_t H2C_FRAME_PING = 0x06; static constexpr uint8_t H2C_FRAME_GOAWAY = 0x07; static constexpr uint8_t H2C_FRAME_WINDOW_UPDATE = 0x08; static constexpr uint8_t H2C_FRAME_CONTINUATION = 0x09; static constexpr uint8_t H2C_FLAG_END_STREAM = 0x01; static constexpr uint8_t H2C_FLAG_ACK = 0x01; Loading Loading @@ -2625,6 +2626,33 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( if (!_h2Decoder) _h2Decoder = std::make_unique<hpack::Decoder>(); hpack::Decoder &decoder = *_h2Decoder; // RFC 7540 §6.2/§6.10: a HEADERS frame whose END_HEADERS flag isn't // set is only the first fragment of the block -- the rest arrives in // one or more CONTINUATION frames. Accumulate raw bytes here and only // decode once END_HEADERS is finally seen; decoding a lone HEADERS // frame's payload as if it were the whole block (the previous // behavior) hands decodeString() a truncated buffer, which silently // returns "" for any header whose value got cut at the frame boundary // -- e.g. a long Content-Security-Policy pushing a response's header // block past one frame, corrupting Content-Type along with it. std::vector<uint8_t> pendingHpack; bool pendingEndStream = false; auto finishHeaders = [&]() { auto headers = decoder.decode(pendingHpack.data(), pendingHpack.size()); pendingHpack.clear(); got_headers = true; _lastResponse = std::make_unique<HttpResponse>(); _lastResponse->parseH2(headers); _lastStatusCode = _lastResponse->getStatusCode(); _lastContentType = _lastResponse->getContentType(); _lastLocation.clear(); try { auto *loc = _lastResponse->getHeaderData("location"); if (loc && loc->getfirstValue()) _lastLocation = loc->getfirstValue()->getvalue(); } catch (...) {} }; // Read enough data into raw buffer auto ensure_bytes = [&](size_t need) { while (raw.size() < need) { Loading Loading @@ -2681,20 +2709,25 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( case H2C_FRAME_HEADERS: { if (frame_stream == stream_id) { auto headers = decoder.decode(payload, frame_len); got_headers = true; _lastResponse = std::make_unique<HttpResponse>(); _lastResponse->parseH2(headers); _lastStatusCode = _lastResponse->getStatusCode(); _lastContentType = _lastResponse->getContentType(); _lastLocation.clear(); try { auto *loc = _lastResponse->getHeaderData("location"); if (loc && loc->getfirstValue()) _lastLocation = loc->getfirstValue()->getvalue(); } catch (...) {} if (frame_flags & H2C_FLAG_END_STREAM) { got_end_stream = true; pendingHpack.assign(payload, payload + frame_len); pendingEndStream = (frame_flags & H2C_FLAG_END_STREAM) != 0; if (frame_flags & H2C_FLAG_END_HEADERS) { finishHeaders(); if (pendingEndStream) got_end_stream = true; } // else: block continues in CONTINUATION frame(s) below } break; } case H2C_FRAME_CONTINUATION: { // RFC 7540 §6.10: more HPACK data for a HEADERS block // whose END_HEADERS wasn't set yet. if (frame_stream == stream_id) { pendingHpack.insert(pendingHpack.end(), payload, payload + frame_len); if (frame_flags & H2C_FLAG_END_HEADERS) { finishHeaders(); if (pendingEndStream) got_end_stream = true; } } break; Loading Loading
src/http.cpp +47 −14 Original line number Diff line number Diff line Loading @@ -807,6 +807,7 @@ static constexpr uint8_t H2C_FRAME_SETTINGS = 0x04; static constexpr uint8_t H2C_FRAME_PING = 0x06; static constexpr uint8_t H2C_FRAME_GOAWAY = 0x07; static constexpr uint8_t H2C_FRAME_WINDOW_UPDATE = 0x08; static constexpr uint8_t H2C_FRAME_CONTINUATION = 0x09; static constexpr uint8_t H2C_FLAG_END_STREAM = 0x01; static constexpr uint8_t H2C_FLAG_ACK = 0x01; Loading Loading @@ -2625,6 +2626,33 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( if (!_h2Decoder) _h2Decoder = std::make_unique<hpack::Decoder>(); hpack::Decoder &decoder = *_h2Decoder; // RFC 7540 §6.2/§6.10: a HEADERS frame whose END_HEADERS flag isn't // set is only the first fragment of the block -- the rest arrives in // one or more CONTINUATION frames. Accumulate raw bytes here and only // decode once END_HEADERS is finally seen; decoding a lone HEADERS // frame's payload as if it were the whole block (the previous // behavior) hands decodeString() a truncated buffer, which silently // returns "" for any header whose value got cut at the frame boundary // -- e.g. a long Content-Security-Policy pushing a response's header // block past one frame, corrupting Content-Type along with it. std::vector<uint8_t> pendingHpack; bool pendingEndStream = false; auto finishHeaders = [&]() { auto headers = decoder.decode(pendingHpack.data(), pendingHpack.size()); pendingHpack.clear(); got_headers = true; _lastResponse = std::make_unique<HttpResponse>(); _lastResponse->parseH2(headers); _lastStatusCode = _lastResponse->getStatusCode(); _lastContentType = _lastResponse->getContentType(); _lastLocation.clear(); try { auto *loc = _lastResponse->getHeaderData("location"); if (loc && loc->getfirstValue()) _lastLocation = loc->getfirstValue()->getvalue(); } catch (...) {} }; // Read enough data into raw buffer auto ensure_bytes = [&](size_t need) { while (raw.size() < need) { Loading Loading @@ -2681,20 +2709,25 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( case H2C_FRAME_HEADERS: { if (frame_stream == stream_id) { auto headers = decoder.decode(payload, frame_len); got_headers = true; _lastResponse = std::make_unique<HttpResponse>(); _lastResponse->parseH2(headers); _lastStatusCode = _lastResponse->getStatusCode(); _lastContentType = _lastResponse->getContentType(); _lastLocation.clear(); try { auto *loc = _lastResponse->getHeaderData("location"); if (loc && loc->getfirstValue()) _lastLocation = loc->getfirstValue()->getvalue(); } catch (...) {} if (frame_flags & H2C_FLAG_END_STREAM) { got_end_stream = true; pendingHpack.assign(payload, payload + frame_len); pendingEndStream = (frame_flags & H2C_FLAG_END_STREAM) != 0; if (frame_flags & H2C_FLAG_END_HEADERS) { finishHeaders(); if (pendingEndStream) got_end_stream = true; } // else: block continues in CONTINUATION frame(s) below } break; } case H2C_FRAME_CONTINUATION: { // RFC 7540 §6.10: more HPACK data for a HEADERS block // whose END_HEADERS wasn't set yet. if (frame_stream == stream_id) { pendingHpack.insert(pendingHpack.end(), payload, payload + frame_len); if (frame_flags & H2C_FLAG_END_HEADERS) { finishHeaders(); if (pendingEndStream) got_end_stream = true; } } break; Loading