Loading src/http.cpp +33 −0 Changes for src/http.cpp: 33 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -591,6 +591,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe size_t header_end = std::string::npos; size_t search_from = 0; // avoid re-scanning from 0 on every recv (O(n²) → O(n)) read_header: for (;;) { if (raw.size() >= 4) { size_t start = (search_from >= 3) ? search_from - 3 : 0; Loading Loading @@ -629,6 +630,18 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe throw he; } // RFC 9110 §15.2: 1xx interim responses (e.g. "100 Continue" answering a // forwarded "Expect: 100-continue") precede the real one on the same // connection. Taking one as final made the EOF branch below swallow the // real response and then block until the peer closed its keep-alive. // 101 is final (protocol switch) and handled by the caller. if (res.getStatusCode() >= 100 && res.getStatusCode() < 200 && res.getStatusCode() != 101) { raw.erase(raw.begin(), raw.begin() + (ptrdiff_t)parsed_hsize); header_end = std::string::npos; search_from = 0; goto read_header; } // Store parsed response and extract fields for redirect handling _lastResponse = std::make_unique<HttpResponse>(res); _lastStatusCode = res.getStatusCode(); Loading @@ -653,6 +666,16 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe size_t body_off = parsed_hsize; // RFC 9112 §6.3: responses to HEAD, and 1xx/204/304 responses, never carry // a body regardless of Content-Length/Transfer-Encoding. Reading one anyway // blocked until recv timeout (Content-Length present, mirroring the GET's // size) or until the peer closed the keep-alive (EOF branch). { int sc = res.getStatusCode(); if (label == "HEAD" || sc == 204 || sc == 304 || (sc >= 100 && sc < 200)) return ret; } // 3) Determine transfer mode bool chunked = false; ptrdiff_t content_len = -1; Loading Loading @@ -808,6 +831,9 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe if (n == 0) break; ret.insert(ret.end(), _recvScratch.data.buf, _recvScratch.data.buf + n); } // The peer closed to end the body -- this socket is done; without this // a connection pool would hand the dead socket out again. _peerWantsClose = true; } return ret; Loading Loading @@ -1325,6 +1351,13 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest } } // 204/304 never carry a body (RFC 9112 §6.3), whatever the headers say. if (res.getStatusCode() == 204 || res.getStatusCode() == 304) { chunked = false; content_len = 0; _streamBuf.clear(); } if (chunked) { _streamMode = STREAM_CHUNKED; _streamChunkDone = false; Loading Loading
src/http.cpp +33 −0 Changes for src/http.cpp: 33 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -591,6 +591,7 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe size_t header_end = std::string::npos; size_t search_from = 0; // avoid re-scanning from 0 on every recv (O(n²) → O(n)) read_header: for (;;) { if (raw.size() >= 4) { size_t start = (search_from >= 3) ? search_from - 3 : 0; Loading Loading @@ -629,6 +630,18 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe throw he; } // RFC 9110 §15.2: 1xx interim responses (e.g. "100 Continue" answering a // forwarded "Expect: 100-continue") precede the real one on the same // connection. Taking one as final made the EOF branch below swallow the // real response and then block until the peer closed its keep-alive. // 101 is final (protocol switch) and handled by the caller. if (res.getStatusCode() >= 100 && res.getStatusCode() < 200 && res.getStatusCode() != 101) { raw.erase(raw.begin(), raw.begin() + (ptrdiff_t)parsed_hsize); header_end = std::string::npos; search_from = 0; goto read_header; } // Store parsed response and extract fields for redirect handling _lastResponse = std::make_unique<HttpResponse>(res); _lastStatusCode = res.getStatusCode(); Loading @@ -653,6 +666,16 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe size_t body_off = parsed_hsize; // RFC 9112 §6.3: responses to HEAD, and 1xx/204/304 responses, never carry // a body regardless of Content-Length/Transfer-Encoding. Reading one anyway // blocked until recv timeout (Content-Length present, mirroring the GET's // size) or until the peer closed the keep-alive (EOF branch). { int sc = res.getStatusCode(); if (label == "HEAD" || sc == 204 || sc == 304 || (sc >= 100 && sc < 200)) return ret; } // 3) Determine transfer mode bool chunked = false; ptrdiff_t content_len = -1; Loading Loading @@ -808,6 +831,9 @@ std::vector<char> libhttppp::HttpClient::_h1ReadResponse(const std::string &labe if (n == 0) break; ret.insert(ret.end(), _recvScratch.data.buf, _recvScratch.data.buf + n); } // The peer closed to end the body -- this socket is done; without this // a connection pool would hand the dead socket out again. _peerWantsClose = true; } return ret; Loading Loading @@ -1325,6 +1351,13 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest } } // 204/304 never carry a body (RFC 9112 §6.3), whatever the headers say. if (res.getStatusCode() == 204 || res.getStatusCode() == 304) { chunked = false; content_len = 0; _streamBuf.clear(); } if (chunked) { _streamMode = STREAM_CHUNKED; _streamChunkDone = false; Loading