Loading src/http.cpp +302 −1 Original line number Diff line number Diff line Loading @@ -1228,6 +1228,305 @@ const std::vector<char> libhttppp::HttpClient::Post(libhttppp::HttpRequest &nreq } } const std::vector<char> libhttppp::HttpClient::Delete(libhttppp::HttpRequest &nreq) { std::vector<char> ret; try { // Ensure a fresh connection for each request; keep-alive reuse // is unreliable without full connection-state tracking. resetConnection(); const int kMaxRedirects = 1; int redirects = 0; for (;;) { std::stringstream host; host << _url.getHost() << ":" << _url.getPort(); nreq.setHeaderData("host")->push_back(host.str()); nreq.setRequestType(DELETEREQUEST); if (nreq.getRequestURL().empty()) nreq.setRequestURL(_url.getPath()); // HTTP/2: delegate to binary framing path if (_isH2) { return _h2Request("DELETE", nreq); } // --------------------------------------------------------- // 0) Build request headers // --------------------------------------------------------- if (nreq.getRequestVersion().empty()) nreq.setRequestVersion(HTTPVERSION(1.1)); // --------------------------------------------------------- // 1) Send request // --------------------------------------------------------- nreq.send(_url, _cltsock); // --------------------------------------------------------- // helper: recv one chunk with Note-retry // --------------------------------------------------------- auto recv_blocking = [&](netplus::buffer& b) -> size_t { for (;;) { try { size_t n = _cltsock->recvData(b, 0); return n; } catch (netplus::NetException& e) { if (e.getErrorType() == netplus::NetException::Note) { sleep_note(); continue; } throw; } } }; // --------------------------------------------------------- // 2) Read until we have full header (\r\n\r\n) // --------------------------------------------------------- std::vector<char> raw; raw.reserve(8192); size_t header_end = std::string::npos; for (;;) { if (raw.size() >= 4) { for (size_t i = 0; i + 3 < raw.size(); ++i) { if (raw[i] == '\r' && raw[i+1] == '\n' && raw[i+2] == '\r' && raw[i+3] == '\n') { header_end = i + 4; break; } } } if (header_end != std::string::npos) break; netplus::buffer buf(BLOCKSIZE); size_t n = recv_blocking(buf); if (n == 0) { netplus::NetException ne; ne[netplus::NetException::Error] << "HTTP DELETE: EOF while reading header"; throw ne; } raw.insert(raw.end(), buf.data.buf, buf.data.buf + n); } // --------------------------------------------------------- // 3) Parse header // --------------------------------------------------------- libhttppp::HttpResponse res; size_t parsed_hsize = res.parse(raw.data(), raw.size()); if (parsed_hsize == 0 || parsed_hsize > raw.size()) { libhttppp::HTTPException he; he[libhttppp::HTTPException::Error] << "HTTP DELETE: response header parse failed"; throw he; } if (is_redirect_status(res.getStatusCode()) && redirects < kMaxRedirects) { std::string location = extract_location_from_response(res); if (!location.empty()) { ++redirects; if (location.rfind("http://", 0) == 0 || location.rfind("https://", 0) == 0) { _url = HttpUrl(location, false); nreq.setRequestURL(_url.getPath()); } else { std::string base = nreq.getRequestURL().empty() ? _url.getPath() : nreq.getRequestURL(); nreq.setRequestURL(normalize_path(location, base)); } resetConnection(); continue; } } size_t body_off = parsed_hsize; // --------------------------------------------------------- // 4) Determine transfer mode // --------------------------------------------------------- bool chunked = false; ptrdiff_t content_len = -1; try { for (libhttppp::HttpHeader::HeaderData::Values *v = res.getTransferEncoding(); v; v = v->nextvalue()) { std::string val = tolower_copy(v->getvalue()); if (val == "chunked") { chunked = true; break; } } } catch (...) { // ignore } if (!chunked) { try { content_len = res.getContentLength(); if (content_len < 0) content_len = -1; } catch (...) { content_len = -1; } } // --------------------------------------------------------- // 5) Helper: append from raw buffer // --------------------------------------------------------- auto append_from_raw = [&](size_t& take_pos, size_t take_len) { if (take_len == 0) return; ret.insert(ret.end(), raw.begin() + (ptrdiff_t)take_pos, raw.begin() + (ptrdiff_t)(take_pos + take_len)); take_pos += take_len; }; // ========================================================= // 6A) BODY: Content-Length // ========================================================= if (!chunked && content_len >= 0) { size_t remaining = (size_t)content_len; size_t pos = body_off; size_t can = (std::min)(remaining, raw.size() - pos); append_from_raw(pos, can); remaining -= can; while (remaining > 0) { netplus::buffer buf(BLOCKSIZE); size_t n = recv_blocking(buf); if (n == 0) { netplus::NetException ne; ne[netplus::NetException::Error] << "HTTP DELETE: EOF before Content-Length complete"; throw ne; } size_t take = (std::min)(remaining, n); ret.insert(ret.end(), buf.data.buf, buf.data.buf + take); remaining -= take; } return ret; } // ========================================================= // 6B) BODY: chunked // ========================================================= if (chunked) { size_t pos = body_off; auto ensure_bytes = [&](size_t need) { while (raw.size() - pos < need) { netplus::buffer buf(BLOCKSIZE); size_t n = recv_blocking(buf); if (n == 0) { netplus::NetException ne; ne[netplus::NetException::Error] << "HTTP DELETE: EOF while reading chunked body"; throw ne; } raw.insert(raw.end(), buf.data.buf, buf.data.buf + n); } }; auto read_line = [&]() -> std::string { for (;;) { for (size_t i = pos; i + 1 < raw.size(); ++i) { if (raw[i] == '\r' && raw[i+1] == '\n') { std::string line(raw.begin() + (ptrdiff_t)pos, raw.begin() + (ptrdiff_t)i); pos = i + 2; return line; } } netplus::buffer buf(BLOCKSIZE); size_t n = recv_blocking(buf); if (n == 0) { netplus::NetException ne; ne[netplus::NetException::Error] << "HTTP DELETE: EOF while reading chunk size line"; throw ne; } raw.insert(raw.end(), buf.data.buf, buf.data.buf + n); } }; for (;;) { std::string szline = read_line(); auto sem = szline.find(';'); if (sem != std::string::npos) szline.resize(sem); size_t chunk_size = 0; try { chunk_size = (size_t)std::stoul(szline, nullptr, 16); } catch (...) { libhttppp::HTTPException he; he[libhttppp::HTTPException::Error] << "HTTP DELETE: invalid chunk size line: " << szline; throw he; } if (chunk_size == 0) { for (;;) { std::string tline = read_line(); if (tline.empty()) break; } break; } ensure_bytes(chunk_size + 2); ret.insert(ret.end(), raw.begin() + (ptrdiff_t)pos, raw.begin() + (ptrdiff_t)(pos + chunk_size)); pos += chunk_size; if (raw[pos] != '\r' || raw[pos+1] != '\n') { libhttppp::HTTPException he; he[libhttppp::HTTPException::Error] << "HTTP DELETE: bad chunk terminator"; throw he; } pos += 2; } return ret; } // ========================================================= // 6C) BODY: no length, not chunked -> read until EOF // ========================================================= { size_t pos = body_off; if (raw.size() > pos) { ret.insert(ret.end(), raw.begin() + (ptrdiff_t)pos, raw.end()); } for (;;) { netplus::buffer buf(BLOCKSIZE); size_t n = 0; try { n = recv_blocking(buf); } catch (...) { throw; } if (n == 0) break; ret.insert(ret.end(), buf.data.buf, buf.data.buf + n); } } return ret; } } catch (netplus::NetException &e) { libhttppp::HTTPException ee; ee[libhttppp::HTTPException::Error] << e.what(); throw ee; } } int libhttppp::HttpClient::readchunk(const char *data, int datasize, int &pos) { // 1) Skip CRLF left after previous chunk Loading Loading @@ -2437,6 +2736,8 @@ void libhttppp::HttpRequest::printHeader(std::string &buffer){ buffer="GET "; else if(_RequestType==POSTREQUEST) buffer="POST "; else if(_RequestType==DELETEREQUEST) buffer="DELETE "; buffer.append(_cachedRequest); buffer.append(" "); Loading Loading @@ -2569,7 +2870,7 @@ void libhttppp::HttpRequest::send(const HttpUrl &dest, } void libhttppp::HttpRequest::setRequestType(int req){ if(req == POSTREQUEST || req == GETREQUEST){ if(req == POSTREQUEST || req == GETREQUEST || req == DELETEREQUEST){ _RequestType=req; return; } Loading Loading
src/http.cpp +302 −1 Original line number Diff line number Diff line Loading @@ -1228,6 +1228,305 @@ const std::vector<char> libhttppp::HttpClient::Post(libhttppp::HttpRequest &nreq } } const std::vector<char> libhttppp::HttpClient::Delete(libhttppp::HttpRequest &nreq) { std::vector<char> ret; try { // Ensure a fresh connection for each request; keep-alive reuse // is unreliable without full connection-state tracking. resetConnection(); const int kMaxRedirects = 1; int redirects = 0; for (;;) { std::stringstream host; host << _url.getHost() << ":" << _url.getPort(); nreq.setHeaderData("host")->push_back(host.str()); nreq.setRequestType(DELETEREQUEST); if (nreq.getRequestURL().empty()) nreq.setRequestURL(_url.getPath()); // HTTP/2: delegate to binary framing path if (_isH2) { return _h2Request("DELETE", nreq); } // --------------------------------------------------------- // 0) Build request headers // --------------------------------------------------------- if (nreq.getRequestVersion().empty()) nreq.setRequestVersion(HTTPVERSION(1.1)); // --------------------------------------------------------- // 1) Send request // --------------------------------------------------------- nreq.send(_url, _cltsock); // --------------------------------------------------------- // helper: recv one chunk with Note-retry // --------------------------------------------------------- auto recv_blocking = [&](netplus::buffer& b) -> size_t { for (;;) { try { size_t n = _cltsock->recvData(b, 0); return n; } catch (netplus::NetException& e) { if (e.getErrorType() == netplus::NetException::Note) { sleep_note(); continue; } throw; } } }; // --------------------------------------------------------- // 2) Read until we have full header (\r\n\r\n) // --------------------------------------------------------- std::vector<char> raw; raw.reserve(8192); size_t header_end = std::string::npos; for (;;) { if (raw.size() >= 4) { for (size_t i = 0; i + 3 < raw.size(); ++i) { if (raw[i] == '\r' && raw[i+1] == '\n' && raw[i+2] == '\r' && raw[i+3] == '\n') { header_end = i + 4; break; } } } if (header_end != std::string::npos) break; netplus::buffer buf(BLOCKSIZE); size_t n = recv_blocking(buf); if (n == 0) { netplus::NetException ne; ne[netplus::NetException::Error] << "HTTP DELETE: EOF while reading header"; throw ne; } raw.insert(raw.end(), buf.data.buf, buf.data.buf + n); } // --------------------------------------------------------- // 3) Parse header // --------------------------------------------------------- libhttppp::HttpResponse res; size_t parsed_hsize = res.parse(raw.data(), raw.size()); if (parsed_hsize == 0 || parsed_hsize > raw.size()) { libhttppp::HTTPException he; he[libhttppp::HTTPException::Error] << "HTTP DELETE: response header parse failed"; throw he; } if (is_redirect_status(res.getStatusCode()) && redirects < kMaxRedirects) { std::string location = extract_location_from_response(res); if (!location.empty()) { ++redirects; if (location.rfind("http://", 0) == 0 || location.rfind("https://", 0) == 0) { _url = HttpUrl(location, false); nreq.setRequestURL(_url.getPath()); } else { std::string base = nreq.getRequestURL().empty() ? _url.getPath() : nreq.getRequestURL(); nreq.setRequestURL(normalize_path(location, base)); } resetConnection(); continue; } } size_t body_off = parsed_hsize; // --------------------------------------------------------- // 4) Determine transfer mode // --------------------------------------------------------- bool chunked = false; ptrdiff_t content_len = -1; try { for (libhttppp::HttpHeader::HeaderData::Values *v = res.getTransferEncoding(); v; v = v->nextvalue()) { std::string val = tolower_copy(v->getvalue()); if (val == "chunked") { chunked = true; break; } } } catch (...) { // ignore } if (!chunked) { try { content_len = res.getContentLength(); if (content_len < 0) content_len = -1; } catch (...) { content_len = -1; } } // --------------------------------------------------------- // 5) Helper: append from raw buffer // --------------------------------------------------------- auto append_from_raw = [&](size_t& take_pos, size_t take_len) { if (take_len == 0) return; ret.insert(ret.end(), raw.begin() + (ptrdiff_t)take_pos, raw.begin() + (ptrdiff_t)(take_pos + take_len)); take_pos += take_len; }; // ========================================================= // 6A) BODY: Content-Length // ========================================================= if (!chunked && content_len >= 0) { size_t remaining = (size_t)content_len; size_t pos = body_off; size_t can = (std::min)(remaining, raw.size() - pos); append_from_raw(pos, can); remaining -= can; while (remaining > 0) { netplus::buffer buf(BLOCKSIZE); size_t n = recv_blocking(buf); if (n == 0) { netplus::NetException ne; ne[netplus::NetException::Error] << "HTTP DELETE: EOF before Content-Length complete"; throw ne; } size_t take = (std::min)(remaining, n); ret.insert(ret.end(), buf.data.buf, buf.data.buf + take); remaining -= take; } return ret; } // ========================================================= // 6B) BODY: chunked // ========================================================= if (chunked) { size_t pos = body_off; auto ensure_bytes = [&](size_t need) { while (raw.size() - pos < need) { netplus::buffer buf(BLOCKSIZE); size_t n = recv_blocking(buf); if (n == 0) { netplus::NetException ne; ne[netplus::NetException::Error] << "HTTP DELETE: EOF while reading chunked body"; throw ne; } raw.insert(raw.end(), buf.data.buf, buf.data.buf + n); } }; auto read_line = [&]() -> std::string { for (;;) { for (size_t i = pos; i + 1 < raw.size(); ++i) { if (raw[i] == '\r' && raw[i+1] == '\n') { std::string line(raw.begin() + (ptrdiff_t)pos, raw.begin() + (ptrdiff_t)i); pos = i + 2; return line; } } netplus::buffer buf(BLOCKSIZE); size_t n = recv_blocking(buf); if (n == 0) { netplus::NetException ne; ne[netplus::NetException::Error] << "HTTP DELETE: EOF while reading chunk size line"; throw ne; } raw.insert(raw.end(), buf.data.buf, buf.data.buf + n); } }; for (;;) { std::string szline = read_line(); auto sem = szline.find(';'); if (sem != std::string::npos) szline.resize(sem); size_t chunk_size = 0; try { chunk_size = (size_t)std::stoul(szline, nullptr, 16); } catch (...) { libhttppp::HTTPException he; he[libhttppp::HTTPException::Error] << "HTTP DELETE: invalid chunk size line: " << szline; throw he; } if (chunk_size == 0) { for (;;) { std::string tline = read_line(); if (tline.empty()) break; } break; } ensure_bytes(chunk_size + 2); ret.insert(ret.end(), raw.begin() + (ptrdiff_t)pos, raw.begin() + (ptrdiff_t)(pos + chunk_size)); pos += chunk_size; if (raw[pos] != '\r' || raw[pos+1] != '\n') { libhttppp::HTTPException he; he[libhttppp::HTTPException::Error] << "HTTP DELETE: bad chunk terminator"; throw he; } pos += 2; } return ret; } // ========================================================= // 6C) BODY: no length, not chunked -> read until EOF // ========================================================= { size_t pos = body_off; if (raw.size() > pos) { ret.insert(ret.end(), raw.begin() + (ptrdiff_t)pos, raw.end()); } for (;;) { netplus::buffer buf(BLOCKSIZE); size_t n = 0; try { n = recv_blocking(buf); } catch (...) { throw; } if (n == 0) break; ret.insert(ret.end(), buf.data.buf, buf.data.buf + n); } } return ret; } } catch (netplus::NetException &e) { libhttppp::HTTPException ee; ee[libhttppp::HTTPException::Error] << e.what(); throw ee; } } int libhttppp::HttpClient::readchunk(const char *data, int datasize, int &pos) { // 1) Skip CRLF left after previous chunk Loading Loading @@ -2437,6 +2736,8 @@ void libhttppp::HttpRequest::printHeader(std::string &buffer){ buffer="GET "; else if(_RequestType==POSTREQUEST) buffer="POST "; else if(_RequestType==DELETEREQUEST) buffer="DELETE "; buffer.append(_cachedRequest); buffer.append(" "); Loading Loading @@ -2569,7 +2870,7 @@ void libhttppp::HttpRequest::send(const HttpUrl &dest, } void libhttppp::HttpRequest::setRequestType(int req){ if(req == POSTREQUEST || req == GETREQUEST){ if(req == POSTREQUEST || req == GETREQUEST || req == DELETEREQUEST){ _RequestType=req; return; } Loading