Loading examples/httpsysinfo.cpp +7 −7 Original line number Diff line number Diff line Loading @@ -250,15 +250,15 @@ 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 rem = header_png_size - curreq.slots[0].SendData.pos; size_t si = (rem > BLOCKSIZE) ? BLOCKSIZE : rem; curreq.SendData.append((const char*)header_png + curreq.SendData.pos, si); curreq.SendData.pos += si; curreq.slots[0].SendData.append((const char*)header_png + curreq.slots[0].SendData.pos, si); curreq.slots[0].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); curreq.SendData.append((const char*)favicon_ico+curreq.SendData.pos, si); curreq.SendData.pos+=si; if(curreq.slots[0].SendData.pos < favicon_ico_size){ size_t si = BLOCKSIZE < (favicon_ico_size-curreq.slots[0].SendData.pos) ? BLOCKSIZE : (favicon_ico_size-curreq.slots[0].SendData.pos); curreq.slots[0].SendData.append((const char*)favicon_ico+curreq.slots[0].SendData.pos, si); curreq.slots[0].SendData.pos+=si; } } } Loading src/http.cpp +35 −27 Original line number Diff line number Diff line Loading @@ -782,6 +782,7 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest } }; auto h3_header_deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10); while (!got_headers) { uint8_t rbuf[4096]; size_t n = q->recvStreamData(stream_id, rbuf, sizeof(rbuf)); Loading @@ -789,6 +790,13 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest h3_pump(); n = q->recvStreamData(stream_id, rbuf, sizeof(rbuf)); if (n == 0) { if (q->isStreamComplete(stream_id)) break; if (std::chrono::steady_clock::now() >= h3_header_deadline) { HTTPException ee; ee[HTTPException::Error] << "HTTP/3 header timeout"; throw ee; } _sw.waitRead(*_cltsock, 100); continue; } Loading Loading @@ -2108,10 +2116,10 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( throw ee; } // Always wait for socket readability before next iteration to // avoid busy-spinning when pumpNetwork processes only ACKs/control // frames but no application stream data is available yet. if (n == 0) { // Wait for socket readability before next iteration to // avoid busy-spinning — but skip if QUIC already has buffered // data or the stream is complete (no more UDP packets expected). if (n == 0 && !q->hasStreamData(stream_id) && !q->isStreamComplete(stream_id)) { _sw.waitRead(*_cltsock, 100); } } Loading Loading @@ -2925,10 +2933,10 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const std::string } // For HTTP/2 and HTTP/3: store structured response info directly, // write only body data to SendData (no H1 text round-trip) // write only body data to slots[0].SendData (no H1 text round-trip) if (_storeResponseInfo(curconnection, datalen)) { if (datalen > 0) curconnection.SendData.append(data.data(), datalen); curconnection.slots[0].SendData.append(data.data(), datalen); return; } Loading @@ -2936,10 +2944,10 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const std::string printHeader(header); curconnection.SendData.append(header.data(),header.size()); curconnection.slots[0].SendData.append(header.data(),header.size()); if (datalen > 0) curconnection.SendData.append(data.data(),datalen); curconnection.slots[0].SendData.append(data.data(),datalen); } void libhttppp::HttpResponse::send(netplus::con &curconnection,const unsigned char *data,int datalen){ Loading @@ -2957,7 +2965,7 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const unsigned c // For HTTP/2 and HTTP/3: store structured response info directly if (_storeResponseInfo(curconnection, datalen)) { if (datalen > 0 && data) curconnection.SendData.append(reinterpret_cast<const char*>(data), datalen); curconnection.slots[0].SendData.append(reinterpret_cast<const char*>(data), datalen); return; } Loading @@ -2965,10 +2973,10 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const unsigned c printHeader(header); curconnection.SendData.append(header.data(),header.size()); curconnection.slots[0].SendData.append(header.data(),header.size()); if (datalen > 0 && data) { curconnection.SendData.append(reinterpret_cast<const char*>(data), datalen); curconnection.slots[0].SendData.append(reinterpret_cast<const char*>(data), datalen); } } Loading @@ -2991,7 +2999,7 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const std::vector // For HTTP/2 and HTTP/3: store structured response info directly if (_storeResponseInfo(curconnection, datalen)) { if (datalen > 0) curconnection.SendData.append(data.data(), datalen); curconnection.slots[0].SendData.append(data.data(), datalen); return; } Loading @@ -2999,10 +3007,10 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const std::vector printHeader(header); curconnection.SendData.append(header.data(),header.size()); curconnection.slots[0].SendData.append(header.data(),header.size()); if (datalen > 0) curconnection.SendData.append(data.data(),datalen); curconnection.slots[0].SendData.append(data.data(),datalen); } size_t libhttppp::HttpResponse::parse(const char *data, size_t inlen) { Loading Loading @@ -3245,7 +3253,7 @@ size_t libhttppp::HttpRequest::parseH2(const std::vector<hpack::HeaderField> &he h2.streamId = stream_id; h2.headersSent = false; h2.bodyBytesSent = 0; SendData.pos = 0; slots[0].SendData.pos = 0; // Store ALL headers (including pseudo-headers) in _firstHeaderData. // Split values by ';' (matching parseH1 behaviour) so that cookie Loading Loading @@ -3313,7 +3321,7 @@ size_t libhttppp::HttpRequest::parseH2(const std::vector<hpack::HeaderField> &he size_t libhttppp::HttpRequest::parseH3(const std::vector<qpack::HeaderField> &headers) { clear(); _httpProtocol = 2; SendData.pos = 0; slots[0].SendData.pos = 0; // Store ALL headers (including pseudo-headers) in _firstHeaderData. // Split values by ';' (matching parseH1 behaviour) so that cookie Loading Loading @@ -3397,7 +3405,7 @@ size_t libhttppp::HttpRequest::parseH1() { try { // 1) Find end of headers: "\r\n\r\n" size_t endpos = RecvData.search("\r\n\r\n"); size_t endpos = slots[0].RecvData.search("\r\n\r\n"); if (endpos == std::string::npos) { // Not enough data yet _RequestType = PARSEREQUEST; Loading @@ -3406,11 +3414,11 @@ size_t libhttppp::HttpRequest::parseH1() { // 2) Copy header bytes (include the first \r\n of the separator so // every header line, including the last one, ends with \r\n) header.assign(RecvData.begin(), RecvData.begin() + endpos + 2); header.assign(slots[0].RecvData.begin(), slots[0].RecvData.begin() + endpos + 2); // 3) Consume header (and the delimiter) from RecvData // 3) Consume header (and the delimiter) from slots[0].RecvData endpos += 4; // include "\r\n\r\n" RecvData.erase(RecvData.begin(),RecvData.begin()+endpos); slots[0].RecvData.erase(slots[0].RecvData.begin(),slots[0].RecvData.begin()+endpos); // 4) Parse the request line (first line until CRLF) size_t line_end = 0; Loading Loading @@ -3564,13 +3572,13 @@ size_t libhttppp::HttpRequest::parseH1() { } catch (netplus::NetException& e) { if (e.getErrorType() != netplus::NetException::Note) { RecvData.clear(); slots[0].RecvData.clear(); } excep[HTTPException::Error] << "netplus error: " << e.what(); throw excep; } catch (...) { // keep behavior similar to your original: on parse error, clean up input RecvData.clear(); slots[0].RecvData.clear(); throw; } Loading Loading @@ -3751,14 +3759,14 @@ void libhttppp::HttpForm::parse(libhttppp::HttpRequest &request){ throw excep; } // Use content-length if available, otherwise fall back to RecvData size // Use content-length if available, otherwise fall back to slots[0].RecvData size // (HTTP/2 and HTTP/3 may omit Content-Length) size_t bodyLen = request.getContentLength(); if(bodyLen == 0) bodyLen = request.RecvData.size(); bodyLen = request.slots[0].RecvData.size(); for(auto *cval=ctype->getfirstValue(); cval; cval=cval->nextvalue()){ if(bodyLen <= request.RecvData.size()){ if(bodyLen <= request.slots[0].RecvData.size()){ if(cval->getvalue().find("multipart/form-data") != std::string::npos){ _contentType = "multipart/form-data"; for(auto *cbod=ctype->getfirstValue(); cbod; cbod=cbod->nextvalue()){ Loading @@ -3775,7 +3783,7 @@ void libhttppp::HttpForm::parse(libhttppp::HttpRequest &request){ if(bval.size() >= 2 && bval.front() == '"' && bval.back() == '"') bval = bval.substr(1, bval.size() - 2); _boundary = std::move(bval); _parseMultipart(request.RecvData.data(), request.RecvData.size()); _parseMultipart(request.slots[0].RecvData.data(), request.slots[0].RecvData.size()); break; } } Loading @@ -3783,7 +3791,7 @@ void libhttppp::HttpForm::parse(libhttppp::HttpRequest &request){ } if(cval->getvalue().find("application/x-www-form-urlencoded") != std::string::npos){ _contentType = "application/x-www-form-urlencoded"; _parseUrlDecode(request.RecvData.data(), bodyLen); _parseUrlDecode(request.slots[0].RecvData.data(), bodyLen); } } } Loading src/httpd.cpp +99 −65 File changed.Preview size limit exceeded, changes collapsed. Show changes src/httpd.h +3 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <map> #include <memory> #include <mutex> #include <set> #include <string> #include <vector> Loading Loading @@ -77,6 +78,8 @@ namespace libhttppp { }; std::mutex _h3BufferMutex; std::map<uint64_t, H3StreamBuffer> _h3StreamBuffers; std::set<netplus::socket*> _h3ControlStreamsSent; void _initH3ControlStreams(netplus::quic *q); void _dispatchH2Stream(HttpRequest &cureq, std::string &out, uint32_t sid, const std::vector<hpack::HeaderField> &decoded, Loading Loading
examples/httpsysinfo.cpp +7 −7 Original line number Diff line number Diff line Loading @@ -250,15 +250,15 @@ 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 rem = header_png_size - curreq.slots[0].SendData.pos; size_t si = (rem > BLOCKSIZE) ? BLOCKSIZE : rem; curreq.SendData.append((const char*)header_png + curreq.SendData.pos, si); curreq.SendData.pos += si; curreq.slots[0].SendData.append((const char*)header_png + curreq.slots[0].SendData.pos, si); curreq.slots[0].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); curreq.SendData.append((const char*)favicon_ico+curreq.SendData.pos, si); curreq.SendData.pos+=si; if(curreq.slots[0].SendData.pos < favicon_ico_size){ size_t si = BLOCKSIZE < (favicon_ico_size-curreq.slots[0].SendData.pos) ? BLOCKSIZE : (favicon_ico_size-curreq.slots[0].SendData.pos); curreq.slots[0].SendData.append((const char*)favicon_ico+curreq.slots[0].SendData.pos, si); curreq.slots[0].SendData.pos+=si; } } } Loading
src/http.cpp +35 −27 Original line number Diff line number Diff line Loading @@ -782,6 +782,7 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest } }; auto h3_header_deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10); while (!got_headers) { uint8_t rbuf[4096]; size_t n = q->recvStreamData(stream_id, rbuf, sizeof(rbuf)); Loading @@ -789,6 +790,13 @@ libhttppp::HttpResponse libhttppp::HttpClient::GetStream(libhttppp::HttpRequest h3_pump(); n = q->recvStreamData(stream_id, rbuf, sizeof(rbuf)); if (n == 0) { if (q->isStreamComplete(stream_id)) break; if (std::chrono::steady_clock::now() >= h3_header_deadline) { HTTPException ee; ee[HTTPException::Error] << "HTTP/3 header timeout"; throw ee; } _sw.waitRead(*_cltsock, 100); continue; } Loading Loading @@ -2108,10 +2116,10 @@ const std::vector<char> libhttppp::HttpClient::_h2Request( throw ee; } // Always wait for socket readability before next iteration to // avoid busy-spinning when pumpNetwork processes only ACKs/control // frames but no application stream data is available yet. if (n == 0) { // Wait for socket readability before next iteration to // avoid busy-spinning — but skip if QUIC already has buffered // data or the stream is complete (no more UDP packets expected). if (n == 0 && !q->hasStreamData(stream_id) && !q->isStreamComplete(stream_id)) { _sw.waitRead(*_cltsock, 100); } } Loading Loading @@ -2925,10 +2933,10 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const std::string } // For HTTP/2 and HTTP/3: store structured response info directly, // write only body data to SendData (no H1 text round-trip) // write only body data to slots[0].SendData (no H1 text round-trip) if (_storeResponseInfo(curconnection, datalen)) { if (datalen > 0) curconnection.SendData.append(data.data(), datalen); curconnection.slots[0].SendData.append(data.data(), datalen); return; } Loading @@ -2936,10 +2944,10 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const std::string printHeader(header); curconnection.SendData.append(header.data(),header.size()); curconnection.slots[0].SendData.append(header.data(),header.size()); if (datalen > 0) curconnection.SendData.append(data.data(),datalen); curconnection.slots[0].SendData.append(data.data(),datalen); } void libhttppp::HttpResponse::send(netplus::con &curconnection,const unsigned char *data,int datalen){ Loading @@ -2957,7 +2965,7 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const unsigned c // For HTTP/2 and HTTP/3: store structured response info directly if (_storeResponseInfo(curconnection, datalen)) { if (datalen > 0 && data) curconnection.SendData.append(reinterpret_cast<const char*>(data), datalen); curconnection.slots[0].SendData.append(reinterpret_cast<const char*>(data), datalen); return; } Loading @@ -2965,10 +2973,10 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const unsigned c printHeader(header); curconnection.SendData.append(header.data(),header.size()); curconnection.slots[0].SendData.append(header.data(),header.size()); if (datalen > 0 && data) { curconnection.SendData.append(reinterpret_cast<const char*>(data), datalen); curconnection.slots[0].SendData.append(reinterpret_cast<const char*>(data), datalen); } } Loading @@ -2991,7 +2999,7 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const std::vector // For HTTP/2 and HTTP/3: store structured response info directly if (_storeResponseInfo(curconnection, datalen)) { if (datalen > 0) curconnection.SendData.append(data.data(), datalen); curconnection.slots[0].SendData.append(data.data(), datalen); return; } Loading @@ -2999,10 +3007,10 @@ void libhttppp::HttpResponse::send(netplus::con &curconnection,const std::vector printHeader(header); curconnection.SendData.append(header.data(),header.size()); curconnection.slots[0].SendData.append(header.data(),header.size()); if (datalen > 0) curconnection.SendData.append(data.data(),datalen); curconnection.slots[0].SendData.append(data.data(),datalen); } size_t libhttppp::HttpResponse::parse(const char *data, size_t inlen) { Loading Loading @@ -3245,7 +3253,7 @@ size_t libhttppp::HttpRequest::parseH2(const std::vector<hpack::HeaderField> &he h2.streamId = stream_id; h2.headersSent = false; h2.bodyBytesSent = 0; SendData.pos = 0; slots[0].SendData.pos = 0; // Store ALL headers (including pseudo-headers) in _firstHeaderData. // Split values by ';' (matching parseH1 behaviour) so that cookie Loading Loading @@ -3313,7 +3321,7 @@ size_t libhttppp::HttpRequest::parseH2(const std::vector<hpack::HeaderField> &he size_t libhttppp::HttpRequest::parseH3(const std::vector<qpack::HeaderField> &headers) { clear(); _httpProtocol = 2; SendData.pos = 0; slots[0].SendData.pos = 0; // Store ALL headers (including pseudo-headers) in _firstHeaderData. // Split values by ';' (matching parseH1 behaviour) so that cookie Loading Loading @@ -3397,7 +3405,7 @@ size_t libhttppp::HttpRequest::parseH1() { try { // 1) Find end of headers: "\r\n\r\n" size_t endpos = RecvData.search("\r\n\r\n"); size_t endpos = slots[0].RecvData.search("\r\n\r\n"); if (endpos == std::string::npos) { // Not enough data yet _RequestType = PARSEREQUEST; Loading @@ -3406,11 +3414,11 @@ size_t libhttppp::HttpRequest::parseH1() { // 2) Copy header bytes (include the first \r\n of the separator so // every header line, including the last one, ends with \r\n) header.assign(RecvData.begin(), RecvData.begin() + endpos + 2); header.assign(slots[0].RecvData.begin(), slots[0].RecvData.begin() + endpos + 2); // 3) Consume header (and the delimiter) from RecvData // 3) Consume header (and the delimiter) from slots[0].RecvData endpos += 4; // include "\r\n\r\n" RecvData.erase(RecvData.begin(),RecvData.begin()+endpos); slots[0].RecvData.erase(slots[0].RecvData.begin(),slots[0].RecvData.begin()+endpos); // 4) Parse the request line (first line until CRLF) size_t line_end = 0; Loading Loading @@ -3564,13 +3572,13 @@ size_t libhttppp::HttpRequest::parseH1() { } catch (netplus::NetException& e) { if (e.getErrorType() != netplus::NetException::Note) { RecvData.clear(); slots[0].RecvData.clear(); } excep[HTTPException::Error] << "netplus error: " << e.what(); throw excep; } catch (...) { // keep behavior similar to your original: on parse error, clean up input RecvData.clear(); slots[0].RecvData.clear(); throw; } Loading Loading @@ -3751,14 +3759,14 @@ void libhttppp::HttpForm::parse(libhttppp::HttpRequest &request){ throw excep; } // Use content-length if available, otherwise fall back to RecvData size // Use content-length if available, otherwise fall back to slots[0].RecvData size // (HTTP/2 and HTTP/3 may omit Content-Length) size_t bodyLen = request.getContentLength(); if(bodyLen == 0) bodyLen = request.RecvData.size(); bodyLen = request.slots[0].RecvData.size(); for(auto *cval=ctype->getfirstValue(); cval; cval=cval->nextvalue()){ if(bodyLen <= request.RecvData.size()){ if(bodyLen <= request.slots[0].RecvData.size()){ if(cval->getvalue().find("multipart/form-data") != std::string::npos){ _contentType = "multipart/form-data"; for(auto *cbod=ctype->getfirstValue(); cbod; cbod=cbod->nextvalue()){ Loading @@ -3775,7 +3783,7 @@ void libhttppp::HttpForm::parse(libhttppp::HttpRequest &request){ if(bval.size() >= 2 && bval.front() == '"' && bval.back() == '"') bval = bval.substr(1, bval.size() - 2); _boundary = std::move(bval); _parseMultipart(request.RecvData.data(), request.RecvData.size()); _parseMultipart(request.slots[0].RecvData.data(), request.slots[0].RecvData.size()); break; } } Loading @@ -3783,7 +3791,7 @@ void libhttppp::HttpForm::parse(libhttppp::HttpRequest &request){ } if(cval->getvalue().find("application/x-www-form-urlencoded") != std::string::npos){ _contentType = "application/x-www-form-urlencoded"; _parseUrlDecode(request.RecvData.data(), bodyLen); _parseUrlDecode(request.slots[0].RecvData.data(), bodyLen); } } } Loading
src/httpd.h +3 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <map> #include <memory> #include <mutex> #include <set> #include <string> #include <vector> Loading Loading @@ -77,6 +78,8 @@ namespace libhttppp { }; std::mutex _h3BufferMutex; std::map<uint64_t, H3StreamBuffer> _h3StreamBuffers; std::set<netplus::socket*> _h3ControlStreamsSent; void _initH3ControlStreams(netplus::quic *q); void _dispatchH2Stream(HttpRequest &cureq, std::string &out, uint32_t sid, const std::vector<hpack::HeaderField> &decoded, Loading