Loading src/http.cpp +89 −1 Original line number Diff line number Diff line Loading @@ -1561,7 +1561,95 @@ size_t libhttppp::HttpClient::readBodyChunkNonBlocking(char *buf, size_t bufsize return take; } // For chunked/EOF/H2/H3 modes, fall back to blocking readBodyChunk // ── HTTP/3 non-blocking streaming ── if (_streamMode == STREAM_H3) { // Drain already-decoded body data first if (!_streamH3Body.empty()) { size_t have = _streamH3Body.size(); size_t take = (std::min)(have, bufsize); std::memcpy(buf, _streamH3Body.data(), take); _streamH3Body.erase(_streamH3Body.begin(), _streamH3Body.begin() + (ptrdiff_t)take); return take; } if (_streamH3EndStream) { _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } auto *q = dynamic_cast<netplus::quic*>(_cltsock.get()); if (!q) { _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } // Non-blocking pump for (int pump_i = 0; pump_i < 256; ++pump_i) { try { q->pumpNetwork(MSG_DONTWAIT); } catch (netplus::NetException &e) { if (e.getErrorType() != netplus::NetException::Note) throw; break; } } uint8_t rbuf[4096]; size_t n = q->recvStreamData(_streamH3Sid, rbuf, sizeof(rbuf)); if (n == 0) { if (q->isStreamComplete(_streamH3Sid) && _streamH3Raw.empty()) { _streamH3EndStream = true; _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } return 0; // No data yet — caller should retry later } _streamH3Raw.insert(_streamH3Raw.end(), rbuf, rbuf + n); // Parse H3 frames size_t pos = 0; while (pos < _streamH3Raw.size()) { size_t frame_start = pos; size_t bytes = 0; uint64_t frame_type = h3DecodeVarInt(_streamH3Raw.data() + pos, _streamH3Raw.size() - pos, bytes); if (bytes == 0) break; pos += bytes; if (pos >= _streamH3Raw.size()) { pos = frame_start; break; } uint64_t frame_len = h3DecodeVarInt(_streamH3Raw.data() + pos, _streamH3Raw.size() - pos, bytes); if (bytes == 0) { pos = frame_start; break; } pos += bytes; if (pos + frame_len > _streamH3Raw.size()) { pos = frame_start; break; } if (frame_type == 0x00) { // DATA _streamH3Body.insert(_streamH3Body.end(), _streamH3Raw.begin() + static_cast<ptrdiff_t>(pos), _streamH3Raw.begin() + static_cast<ptrdiff_t>(pos + frame_len)); } pos += frame_len; } if (pos > 0) _streamH3Raw.erase(_streamH3Raw.begin(), _streamH3Raw.begin() + static_cast<ptrdiff_t>(pos)); if (q->isStreamComplete(_streamH3Sid) && _streamH3Raw.empty() && _streamH3Body.empty()) _streamH3EndStream = true; if (!_streamH3Body.empty()) { size_t have = _streamH3Body.size(); size_t take = (std::min)(have, bufsize); std::memcpy(buf, _streamH3Body.data(), take); _streamH3Body.erase(_streamH3Body.begin(), _streamH3Body.begin() + (ptrdiff_t)take); return take; } if (_streamH3EndStream) { _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } return 0; } // For chunked/EOF/H2 modes, fall back to blocking readBodyChunk return readBodyChunk(buf, bufsize); } Loading Loading
src/http.cpp +89 −1 Original line number Diff line number Diff line Loading @@ -1561,7 +1561,95 @@ size_t libhttppp::HttpClient::readBodyChunkNonBlocking(char *buf, size_t bufsize return take; } // For chunked/EOF/H2/H3 modes, fall back to blocking readBodyChunk // ── HTTP/3 non-blocking streaming ── if (_streamMode == STREAM_H3) { // Drain already-decoded body data first if (!_streamH3Body.empty()) { size_t have = _streamH3Body.size(); size_t take = (std::min)(have, bufsize); std::memcpy(buf, _streamH3Body.data(), take); _streamH3Body.erase(_streamH3Body.begin(), _streamH3Body.begin() + (ptrdiff_t)take); return take; } if (_streamH3EndStream) { _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } auto *q = dynamic_cast<netplus::quic*>(_cltsock.get()); if (!q) { _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } // Non-blocking pump for (int pump_i = 0; pump_i < 256; ++pump_i) { try { q->pumpNetwork(MSG_DONTWAIT); } catch (netplus::NetException &e) { if (e.getErrorType() != netplus::NetException::Note) throw; break; } } uint8_t rbuf[4096]; size_t n = q->recvStreamData(_streamH3Sid, rbuf, sizeof(rbuf)); if (n == 0) { if (q->isStreamComplete(_streamH3Sid) && _streamH3Raw.empty()) { _streamH3EndStream = true; _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } return 0; // No data yet — caller should retry later } _streamH3Raw.insert(_streamH3Raw.end(), rbuf, rbuf + n); // Parse H3 frames size_t pos = 0; while (pos < _streamH3Raw.size()) { size_t frame_start = pos; size_t bytes = 0; uint64_t frame_type = h3DecodeVarInt(_streamH3Raw.data() + pos, _streamH3Raw.size() - pos, bytes); if (bytes == 0) break; pos += bytes; if (pos >= _streamH3Raw.size()) { pos = frame_start; break; } uint64_t frame_len = h3DecodeVarInt(_streamH3Raw.data() + pos, _streamH3Raw.size() - pos, bytes); if (bytes == 0) { pos = frame_start; break; } pos += bytes; if (pos + frame_len > _streamH3Raw.size()) { pos = frame_start; break; } if (frame_type == 0x00) { // DATA _streamH3Body.insert(_streamH3Body.end(), _streamH3Raw.begin() + static_cast<ptrdiff_t>(pos), _streamH3Raw.begin() + static_cast<ptrdiff_t>(pos + frame_len)); } pos += frame_len; } if (pos > 0) _streamH3Raw.erase(_streamH3Raw.begin(), _streamH3Raw.begin() + static_cast<ptrdiff_t>(pos)); if (q->isStreamComplete(_streamH3Sid) && _streamH3Raw.empty() && _streamH3Body.empty()) _streamH3EndStream = true; if (!_streamH3Body.empty()) { size_t have = _streamH3Body.size(); size_t take = (std::min)(have, bufsize); std::memcpy(buf, _streamH3Body.data(), take); _streamH3Body.erase(_streamH3Body.begin(), _streamH3Body.begin() + (ptrdiff_t)take); return take; } if (_streamH3EndStream) { _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } return 0; } // For chunked/EOF/H2 modes, fall back to blocking readBodyChunk return readBodyChunk(buf, bufsize); } Loading