Loading CMakeLists.txt +1 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ enable_testing () set(LIBV "1.0.0") set(Upstream_VERSION 1.0.0) set (BLOCKSIZE 65536 CACHE STRING "Block size from Network Packages") set (DEFAULT_UPLOADSIZE 4e+6 CACHE STRING "Block size for Uploads") set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) Loading config.h.in +2 −2 Original line number Diff line number Diff line Loading @@ -6,14 +6,14 @@ #define EVENT_HEADER ${EVENT_HEADER} #define BLOCKSIZE ${BLOCKSIZE} #define PATHSIZE 1024 #define MAXDEFAULTCONN 1024 #define MAXHEADERSIZE 16384 #define CHUNKSIZE 65536 #define NEWLINE "\r\n" //#define DEBUG Loading examples/httpsysinfo.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -251,12 +251,12 @@ public: void ResponseEvent(libhttppp::HttpRequest& curreq, const int tid,ULONG_PTR args){ if (curreq.getRequestURL()=="/images/header.png") { size_t rem = header_png_size - curreq.SendData.pos; size_t si = (rem > BLOCKSIZE) ? BLOCKSIZE : rem; size_t si = (rem > CHUNKSIZE) ? CHUNKSIZE : rem; curreq.SendData.append((const char*)header_png + curreq.SendData.pos, si); curreq.SendData.pos += si; } else if(curreq.getRequestURL()=="/favicon.ico"){ if(curreq.SendData.pos < favicon_ico_size){ size_t si = BLOCKSIZE < (favicon_ico_size-curreq.SendData.pos) ? BLOCKSIZE : (favicon_ico_size-curreq.SendData.pos); size_t si = CHUNKSIZE < (favicon_ico_size-curreq.SendData.pos) ? CHUNKSIZE : (favicon_ico_size-curreq.SendData.pos); curreq.SendData.append((const char*)favicon_ico+curreq.SendData.pos, si); curreq.SendData.pos+=si; } Loading src/http.cpp +124 −20 Original line number Diff line number Diff line Loading @@ -540,7 +540,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe if (header_end != std::string::npos) break; netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); // Short timeout for initial server response — if the server doesn't // start responding within 10s, the connection is likely dead. size_t n = _recvBlocking(buf, 10); Loading Loading @@ -607,7 +607,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe remaining -= can; while (remaining > 0) { netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = _recvBlocking(buf); if (n == 0) { netplus::NetException ne; Loading @@ -627,7 +627,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe auto ensure_bytes = [&](size_t need) { while (raw.size() - pos < need) { netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = _recvBlocking(buf); if (n == 0) { netplus::NetException ne; Loading @@ -648,7 +648,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe return line; } } netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = _recvBlocking(buf); if (n == 0) { netplus::NetException ne; Loading Loading @@ -706,7 +706,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe ret.insert(ret.end(), raw.begin() + (ptrdiff_t)pos, raw.end()); } for (;;) { netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = 0; try { n = _recvBlocking(buf); Loading Loading @@ -985,7 +985,7 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest auto h2_ensure_bytes = [&](size_t need) { while (_streamH2Raw.size() < need) { netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = _recvBlocking(buf, 15); if (n == 0) { HTTPException he; Loading Loading @@ -1115,7 +1115,7 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest if (header_end != std::string::npos) break; netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = _recvBlocking(buf, 10); if (n == 0) { netplus::NetException ne; Loading Loading @@ -1214,7 +1214,7 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { // Helper: receive more data into internal buffer auto recvMore = [&]() -> size_t { netplus::buffer nb(BLOCKSIZE); netplus::buffer nb(CHUNKSIZE); size_t n = _recvBlocking(nb); if (n > 0) { if (_streamBufPos > 0 && _streamBufPos < _streamBuf.size()) { Loading Loading @@ -1246,7 +1246,7 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { } // Read from socket netplus::buffer nb(BLOCKSIZE); netplus::buffer nb(CHUNKSIZE); size_t n = _recvBlocking(nb); if (n == 0) { _streamMode = STREAM_NONE; Loading Loading @@ -1309,7 +1309,7 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { return got; } // Read from socket directly netplus::buffer nb(BLOCKSIZE); netplus::buffer nb(CHUNKSIZE); size_t n = _recvBlocking(nb); if (n == 0) { _streamChunkDone = true; Loading Loading @@ -1373,7 +1373,7 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { if (got > 0) return got; // Read from socket; EOF signals end of body netplus::buffer nb(BLOCKSIZE); netplus::buffer nb(CHUNKSIZE); size_t n = 0; try { n = _recvBlocking(nb); Loading Loading @@ -1408,7 +1408,7 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { // Read more H2 frames until we get DATA for our stream auto h2_ensure_bytes = [&](size_t need) { while (_streamH2Raw.size() < need) { netplus::buffer fbuf(BLOCKSIZE); netplus::buffer fbuf(CHUNKSIZE); size_t n = _recvBlocking(fbuf); if (n == 0) { _streamH2EndStream = true; Loading Loading @@ -1447,8 +1447,13 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { } case H2C_FRAME_DATA: { if (frame_stream == _streamH2Sid) { _streamBuf.insert(_streamBuf.end(), payload, payload + frame_len); // Compact buffer before appending: remove already-consumed bytes if (_streamBufPos > 0) { _streamBuf.erase(_streamBuf.begin(), _streamBuf.begin() + static_cast<ptrdiff_t>(_streamBufPos)); _streamBufPos = 0; } _streamBuf.insert(_streamBuf.end(), payload, payload + frame_len); if (frame_len > 0) { _sendAll(h2cBuildWindowUpdate(0, frame_len)); _sendAll(h2cBuildWindowUpdate(_streamH2Sid, frame_len)); Loading Loading @@ -1672,7 +1677,7 @@ size_t libhttppp::HttpClient::readBodyChunkNonBlocking(char *buf, size_t bufsize } // Non-blocking read from socket netplus::buffer nb(BLOCKSIZE); netplus::buffer nb(CHUNKSIZE); size_t n = _recvNonBlocking(nb); if (n == 0) return 0; // No data yet — caller should retry later Loading Loading @@ -1733,8 +1738,8 @@ size_t libhttppp::HttpClient::readBodyChunkNonBlocking(char *buf, size_t bufsize _streamH3Raw.insert(_streamH3Raw.end(), rbuf, rbuf + n); got_any = true; } if (!got_any) { if (q->isStreamComplete(_streamH3Sid) && _streamH3Raw.empty() if (!got_any && _streamH3Raw.empty() && !_streamH3InDataFrame) { if (q->isStreamComplete(_streamH3Sid) && !q->hasStreamData(_streamH3Sid)) { _streamH3EndStream = true; _streamMode = STREAM_NONE; Loading Loading @@ -1807,7 +1812,106 @@ size_t libhttppp::HttpClient::readBodyChunkNonBlocking(char *buf, size_t bufsize return 0; } // For chunked/EOF/H2 modes, fall back to blocking readBodyChunk // ── HTTP/2 non-blocking streaming ── if (_streamMode == STREAM_H2) { // First drain any body data buffered during GetStream / previous reads size_t got = drainBuf(bufsize); if (got > 0) return got; if (_streamH2EndStream) { _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } // Non-blocking read from socket — always try, append to _streamH2Raw { netplus::buffer nbuf(CHUNKSIZE); size_t n = _recvNonBlocking(nbuf); if (n > 0) { _streamH2Raw.insert(_streamH2Raw.end(), reinterpret_cast<uint8_t*>(nbuf.data.buf), reinterpret_cast<uint8_t*>(nbuf.data.buf) + n); } } // Process all complete H2 frames in _streamH2Raw while (_streamH2Raw.size() >= H2C_FRAME_HEADER_LEN) { uint32_t frame_len = (static_cast<uint32_t>(_streamH2Raw[0]) << 16) | (static_cast<uint32_t>(_streamH2Raw[1]) << 8) | static_cast<uint32_t>(_streamH2Raw[2]); uint8_t frame_type = _streamH2Raw[3]; uint8_t frame_flags = _streamH2Raw[4]; uint32_t frame_stream = ((static_cast<uint32_t>(_streamH2Raw[5]) & 0x7f) << 24) | (static_cast<uint32_t>(_streamH2Raw[6]) << 16) | (static_cast<uint32_t>(_streamH2Raw[7]) << 8) | static_cast<uint32_t>(_streamH2Raw[8]); if (_streamH2Raw.size() < H2C_FRAME_HEADER_LEN + frame_len) break; // incomplete frame, wait for more data const uint8_t *payload = _streamH2Raw.data() + H2C_FRAME_HEADER_LEN; switch (frame_type) { case H2C_FRAME_SETTINGS: { if (!(frame_flags & H2C_FLAG_ACK)) _sendAll(h2cBuildSettingsAck()); break; } case H2C_FRAME_DATA: { if (frame_stream == _streamH2Sid) { if (_streamBufPos > 0) { _streamBuf.erase(_streamBuf.begin(), _streamBuf.begin() + static_cast<ptrdiff_t>(_streamBufPos)); _streamBufPos = 0; } _streamBuf.insert(_streamBuf.end(), payload, payload + frame_len); if (frame_len > 0) { _sendAll(h2cBuildWindowUpdate(0, frame_len)); _sendAll(h2cBuildWindowUpdate(_streamH2Sid, frame_len)); } if (frame_flags & H2C_FLAG_END_STREAM) _streamH2EndStream = true; } break; } case H2C_FRAME_HEADERS: { if (frame_stream == _streamH2Sid && (frame_flags & H2C_FLAG_END_STREAM)) _streamH2EndStream = true; break; } case H2C_FRAME_WINDOW_UPDATE: // Server-side window update: nothing to do for client reads break; case H2C_FRAME_PING: { if (!(frame_flags & H2C_FLAG_ACK)) { std::string ping_payload(reinterpret_cast<const char*>(payload), frame_len); _sendAll(h2cBuildFrame(H2C_FRAME_PING, H2C_FLAG_ACK, 0, ping_payload)); } break; } case H2C_FRAME_GOAWAY: _streamH2EndStream = true; break; default: break; } _streamH2Raw.erase(_streamH2Raw.begin(), _streamH2Raw.begin() + H2C_FRAME_HEADER_LEN + frame_len); } // Drain newly received body data got = drainBuf(bufsize); if (got > 0) return got; if (_streamH2EndStream) { _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } return 0; } // For chunked/EOF modes, fall back to blocking readBodyChunk return readBodyChunk(buf, bufsize); } Loading Loading @@ -2142,7 +2246,7 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( // Try a non-blocking read to pick up the server's SETTINGS // (which usually arrives right after TLS handshake). { netplus::buffer nbuf(BLOCKSIZE); netplus::buffer nbuf(CHUNKSIZE); size_t n = 0; try { n = _cltsock->recvData(nbuf, 0); } catch (...) {} if (n > 0) { Loading @@ -2159,7 +2263,7 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( // If window exhausted, block-read for WINDOW_UPDATE while (allowed <= 0) { netplus::buffer nbuf(BLOCKSIZE); netplus::buffer nbuf(CHUNKSIZE); size_t n = recv_blocking(nbuf); if (n == 0) { HTTPException he; Loading Loading @@ -2197,7 +2301,7 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( // Read enough data into raw buffer auto ensure_bytes = [&](size_t need) { while (raw.size() < need) { netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = recv_blocking(buf); if (n == 0) { HTTPException he; Loading src/http.h +1 −0 Original line number Diff line number Diff line Loading @@ -406,6 +406,7 @@ namespace libhttppp { // Peer flow-control windows (RFC 7540 §6.9) int32_t peerConnWindow = 65535; // connection-level int32_t peerInitialStreamWindow = 65535; // from peer SETTINGS size_t peerMaxFrameSize = 16384; // from peer SETTINGS_MAX_FRAME_SIZE (0x05) std::map<uint32_t, int32_t> peerStreamWindows; // per-stream // Active streaming responses (one per stream) std::map<uint32_t, std::shared_ptr<H2StreamingResponse>> activeStreams; Loading Loading
CMakeLists.txt +1 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ enable_testing () set(LIBV "1.0.0") set(Upstream_VERSION 1.0.0) set (BLOCKSIZE 65536 CACHE STRING "Block size from Network Packages") set (DEFAULT_UPLOADSIZE 4e+6 CACHE STRING "Block size for Uploads") set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) Loading
config.h.in +2 −2 Original line number Diff line number Diff line Loading @@ -6,14 +6,14 @@ #define EVENT_HEADER ${EVENT_HEADER} #define BLOCKSIZE ${BLOCKSIZE} #define PATHSIZE 1024 #define MAXDEFAULTCONN 1024 #define MAXHEADERSIZE 16384 #define CHUNKSIZE 65536 #define NEWLINE "\r\n" //#define DEBUG Loading
examples/httpsysinfo.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -251,12 +251,12 @@ public: void ResponseEvent(libhttppp::HttpRequest& curreq, const int tid,ULONG_PTR args){ if (curreq.getRequestURL()=="/images/header.png") { size_t rem = header_png_size - curreq.SendData.pos; size_t si = (rem > BLOCKSIZE) ? BLOCKSIZE : rem; size_t si = (rem > CHUNKSIZE) ? CHUNKSIZE : rem; curreq.SendData.append((const char*)header_png + curreq.SendData.pos, si); curreq.SendData.pos += si; } else if(curreq.getRequestURL()=="/favicon.ico"){ if(curreq.SendData.pos < favicon_ico_size){ size_t si = BLOCKSIZE < (favicon_ico_size-curreq.SendData.pos) ? BLOCKSIZE : (favicon_ico_size-curreq.SendData.pos); size_t si = CHUNKSIZE < (favicon_ico_size-curreq.SendData.pos) ? CHUNKSIZE : (favicon_ico_size-curreq.SendData.pos); curreq.SendData.append((const char*)favicon_ico+curreq.SendData.pos, si); curreq.SendData.pos+=si; } Loading
src/http.cpp +124 −20 Original line number Diff line number Diff line Loading @@ -540,7 +540,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe if (header_end != std::string::npos) break; netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); // Short timeout for initial server response — if the server doesn't // start responding within 10s, the connection is likely dead. size_t n = _recvBlocking(buf, 10); Loading Loading @@ -607,7 +607,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe remaining -= can; while (remaining > 0) { netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = _recvBlocking(buf); if (n == 0) { netplus::NetException ne; Loading @@ -627,7 +627,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe auto ensure_bytes = [&](size_t need) { while (raw.size() - pos < need) { netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = _recvBlocking(buf); if (n == 0) { netplus::NetException ne; Loading @@ -648,7 +648,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe return line; } } netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = _recvBlocking(buf); if (n == 0) { netplus::NetException ne; Loading Loading @@ -706,7 +706,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe ret.insert(ret.end(), raw.begin() + (ptrdiff_t)pos, raw.end()); } for (;;) { netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = 0; try { n = _recvBlocking(buf); Loading Loading @@ -985,7 +985,7 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest auto h2_ensure_bytes = [&](size_t need) { while (_streamH2Raw.size() < need) { netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = _recvBlocking(buf, 15); if (n == 0) { HTTPException he; Loading Loading @@ -1115,7 +1115,7 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest if (header_end != std::string::npos) break; netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = _recvBlocking(buf, 10); if (n == 0) { netplus::NetException ne; Loading Loading @@ -1214,7 +1214,7 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { // Helper: receive more data into internal buffer auto recvMore = [&]() -> size_t { netplus::buffer nb(BLOCKSIZE); netplus::buffer nb(CHUNKSIZE); size_t n = _recvBlocking(nb); if (n > 0) { if (_streamBufPos > 0 && _streamBufPos < _streamBuf.size()) { Loading Loading @@ -1246,7 +1246,7 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { } // Read from socket netplus::buffer nb(BLOCKSIZE); netplus::buffer nb(CHUNKSIZE); size_t n = _recvBlocking(nb); if (n == 0) { _streamMode = STREAM_NONE; Loading Loading @@ -1309,7 +1309,7 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { return got; } // Read from socket directly netplus::buffer nb(BLOCKSIZE); netplus::buffer nb(CHUNKSIZE); size_t n = _recvBlocking(nb); if (n == 0) { _streamChunkDone = true; Loading Loading @@ -1373,7 +1373,7 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { if (got > 0) return got; // Read from socket; EOF signals end of body netplus::buffer nb(BLOCKSIZE); netplus::buffer nb(CHUNKSIZE); size_t n = 0; try { n = _recvBlocking(nb); Loading Loading @@ -1408,7 +1408,7 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { // Read more H2 frames until we get DATA for our stream auto h2_ensure_bytes = [&](size_t need) { while (_streamH2Raw.size() < need) { netplus::buffer fbuf(BLOCKSIZE); netplus::buffer fbuf(CHUNKSIZE); size_t n = _recvBlocking(fbuf); if (n == 0) { _streamH2EndStream = true; Loading Loading @@ -1447,8 +1447,13 @@ size_t libhttppp::HttpClient::readBodyChunk(char *buf, size_t bufsize) { } case H2C_FRAME_DATA: { if (frame_stream == _streamH2Sid) { _streamBuf.insert(_streamBuf.end(), payload, payload + frame_len); // Compact buffer before appending: remove already-consumed bytes if (_streamBufPos > 0) { _streamBuf.erase(_streamBuf.begin(), _streamBuf.begin() + static_cast<ptrdiff_t>(_streamBufPos)); _streamBufPos = 0; } _streamBuf.insert(_streamBuf.end(), payload, payload + frame_len); if (frame_len > 0) { _sendAll(h2cBuildWindowUpdate(0, frame_len)); _sendAll(h2cBuildWindowUpdate(_streamH2Sid, frame_len)); Loading Loading @@ -1672,7 +1677,7 @@ size_t libhttppp::HttpClient::readBodyChunkNonBlocking(char *buf, size_t bufsize } // Non-blocking read from socket netplus::buffer nb(BLOCKSIZE); netplus::buffer nb(CHUNKSIZE); size_t n = _recvNonBlocking(nb); if (n == 0) return 0; // No data yet — caller should retry later Loading Loading @@ -1733,8 +1738,8 @@ size_t libhttppp::HttpClient::readBodyChunkNonBlocking(char *buf, size_t bufsize _streamH3Raw.insert(_streamH3Raw.end(), rbuf, rbuf + n); got_any = true; } if (!got_any) { if (q->isStreamComplete(_streamH3Sid) && _streamH3Raw.empty() if (!got_any && _streamH3Raw.empty() && !_streamH3InDataFrame) { if (q->isStreamComplete(_streamH3Sid) && !q->hasStreamData(_streamH3Sid)) { _streamH3EndStream = true; _streamMode = STREAM_NONE; Loading Loading @@ -1807,7 +1812,106 @@ size_t libhttppp::HttpClient::readBodyChunkNonBlocking(char *buf, size_t bufsize return 0; } // For chunked/EOF/H2 modes, fall back to blocking readBodyChunk // ── HTTP/2 non-blocking streaming ── if (_streamMode == STREAM_H2) { // First drain any body data buffered during GetStream / previous reads size_t got = drainBuf(bufsize); if (got > 0) return got; if (_streamH2EndStream) { _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } // Non-blocking read from socket — always try, append to _streamH2Raw { netplus::buffer nbuf(CHUNKSIZE); size_t n = _recvNonBlocking(nbuf); if (n > 0) { _streamH2Raw.insert(_streamH2Raw.end(), reinterpret_cast<uint8_t*>(nbuf.data.buf), reinterpret_cast<uint8_t*>(nbuf.data.buf) + n); } } // Process all complete H2 frames in _streamH2Raw while (_streamH2Raw.size() >= H2C_FRAME_HEADER_LEN) { uint32_t frame_len = (static_cast<uint32_t>(_streamH2Raw[0]) << 16) | (static_cast<uint32_t>(_streamH2Raw[1]) << 8) | static_cast<uint32_t>(_streamH2Raw[2]); uint8_t frame_type = _streamH2Raw[3]; uint8_t frame_flags = _streamH2Raw[4]; uint32_t frame_stream = ((static_cast<uint32_t>(_streamH2Raw[5]) & 0x7f) << 24) | (static_cast<uint32_t>(_streamH2Raw[6]) << 16) | (static_cast<uint32_t>(_streamH2Raw[7]) << 8) | static_cast<uint32_t>(_streamH2Raw[8]); if (_streamH2Raw.size() < H2C_FRAME_HEADER_LEN + frame_len) break; // incomplete frame, wait for more data const uint8_t *payload = _streamH2Raw.data() + H2C_FRAME_HEADER_LEN; switch (frame_type) { case H2C_FRAME_SETTINGS: { if (!(frame_flags & H2C_FLAG_ACK)) _sendAll(h2cBuildSettingsAck()); break; } case H2C_FRAME_DATA: { if (frame_stream == _streamH2Sid) { if (_streamBufPos > 0) { _streamBuf.erase(_streamBuf.begin(), _streamBuf.begin() + static_cast<ptrdiff_t>(_streamBufPos)); _streamBufPos = 0; } _streamBuf.insert(_streamBuf.end(), payload, payload + frame_len); if (frame_len > 0) { _sendAll(h2cBuildWindowUpdate(0, frame_len)); _sendAll(h2cBuildWindowUpdate(_streamH2Sid, frame_len)); } if (frame_flags & H2C_FLAG_END_STREAM) _streamH2EndStream = true; } break; } case H2C_FRAME_HEADERS: { if (frame_stream == _streamH2Sid && (frame_flags & H2C_FLAG_END_STREAM)) _streamH2EndStream = true; break; } case H2C_FRAME_WINDOW_UPDATE: // Server-side window update: nothing to do for client reads break; case H2C_FRAME_PING: { if (!(frame_flags & H2C_FLAG_ACK)) { std::string ping_payload(reinterpret_cast<const char*>(payload), frame_len); _sendAll(h2cBuildFrame(H2C_FRAME_PING, H2C_FLAG_ACK, 0, ping_payload)); } break; } case H2C_FRAME_GOAWAY: _streamH2EndStream = true; break; default: break; } _streamH2Raw.erase(_streamH2Raw.begin(), _streamH2Raw.begin() + H2C_FRAME_HEADER_LEN + frame_len); } // Drain newly received body data got = drainBuf(bufsize); if (got > 0) return got; if (_streamH2EndStream) { _streamMode = STREAM_NONE; return static_cast<size_t>(-1); } return 0; } // For chunked/EOF modes, fall back to blocking readBodyChunk return readBodyChunk(buf, bufsize); } Loading Loading @@ -2142,7 +2246,7 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( // Try a non-blocking read to pick up the server's SETTINGS // (which usually arrives right after TLS handshake). { netplus::buffer nbuf(BLOCKSIZE); netplus::buffer nbuf(CHUNKSIZE); size_t n = 0; try { n = _cltsock->recvData(nbuf, 0); } catch (...) {} if (n > 0) { Loading @@ -2159,7 +2263,7 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( // If window exhausted, block-read for WINDOW_UPDATE while (allowed <= 0) { netplus::buffer nbuf(BLOCKSIZE); netplus::buffer nbuf(CHUNKSIZE); size_t n = recv_blocking(nbuf); if (n == 0) { HTTPException he; Loading Loading @@ -2197,7 +2301,7 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( // Read enough data into raw buffer auto ensure_bytes = [&](size_t need) { while (raw.size() < need) { netplus::buffer buf(BLOCKSIZE); netplus::buffer buf(CHUNKSIZE); size_t n = recv_blocking(buf); if (n == 0) { HTTPException he; Loading
src/http.h +1 −0 Original line number Diff line number Diff line Loading @@ -406,6 +406,7 @@ namespace libhttppp { // Peer flow-control windows (RFC 7540 §6.9) int32_t peerConnWindow = 65535; // connection-level int32_t peerInitialStreamWindow = 65535; // from peer SETTINGS size_t peerMaxFrameSize = 16384; // from peer SETTINGS_MAX_FRAME_SIZE (0x05) std::map<uint32_t, int32_t> peerStreamWindows; // per-stream // Active streaming responses (one per stream) std::map<uint32_t, std::shared_ptr<H2StreamingResponse>> activeStreams; Loading