Loading src/httpd.cpp +64 −14 Changes for src/httpd.cpp: 64 added lines, 14 removed lines. Original line number Diff line number Diff line Loading @@ -683,32 +683,77 @@ void libhttppp::HttpEvent::_finishH2Dispatch(HttpRequest &cureq, } bool libhttppp::HttpEvent::_flushSendDataNow(HttpRequest &cureq) { if (!(cureq.SendData.pos < cureq.SendData.size() && cureq.slots[0].csock)) return cureq.SendData.pos >= cureq.SendData.size(); auto &slot = cureq.slots[0]; if (!slot.csock) { return false; } bool blocked = false; try { while (cureq.SendData.pos < cureq.SendData.size()) { size_t remaining = cureq.SendData.size() - cureq.SendData.pos; size_t sendlen = std::min(remaining, static_cast<size_t>(16384)); netplus::buffer buf(cureq.SendData.data() + cureq.SendData.pos, sendlen); size_t sent = cureq.slots[0].csock->sendData(buf, 0); if (sent > 0) { const size_t remaining = cureq.SendData.size() - cureq.SendData.pos; const size_t sendlen = std::min<size_t>(remaining, 16 * 1024); netplus::buffer buf(cureq.SendData.data() + cureq.SendData.pos, sendlen); const size_t sent = slot.csock->sendData(buf, 0); if (sent == 0) { blocked = true; break; } cureq.SendData.pos += sent; if (cureq.slots[0].csock->hasPendingWrite()) cureq.slots[0].csock->flush_out(); } else { // sendData() may only enqueue encrypted TLS records. Try to // push them immediately, but retain the write interest when the // transport cannot drain the complete output buffer right now. if (slot.csock->hasPendingWrite()) { slot.csock->flush_out(); if (slot.csock->hasPendingWrite()) { blocked = true; break; } } } } catch (const std::exception &e) { std::cerr << "[HTTP-WRITE] deferred: " << e.what() << " pos=" << cureq.SendData.pos << " size=" << cureq.SendData.size() << std::endl; blocked = true; } catch (...) { // Socket busy or error — remaining data will be flushed // by IoEventHandler's send loop after we return. std::cerr << "[HTTP-WRITE] deferred: unknown exception" << " pos=" << cureq.SendData.pos << " size=" << cureq.SendData.size() << std::endl; blocked = true; } if (cureq.SendData.pos >= cureq.SendData.size()) { const bool appDataDone = cureq.SendData.pos >= cureq.SendData.size(); const bool transportDone = !slot.csock->hasPendingWrite(); if (appDataDone) { // sendData() has taken ownership of all plaintext bytes. It is safe // to release that buffer even when encrypted transport bytes are // still queued inside the socket implementation. cureq.SendData.clear(); cureq.SendData.pos = 0; } return cureq.SendData.pos >= cureq.SendData.size(); if (appDataDone && transportDone && !blocked) { slot.ResponsePending.store(false, std::memory_order_release); return true; } // A short write, EAGAIN, or queued TLS output must explicitly re-arm // EPOLLOUT/EVFILT_WRITE. Merely leaving bytes in SendData is not enough // with an edge-triggered or one-shot event loop. slot.ResponsePending.store(true, std::memory_order_release); netplus::requestWritablePoll(cureq); return false; } void libhttppp::HttpEvent::_resumeH2Streams(HttpRequest &cureq, Loading Loading @@ -1875,6 +1920,11 @@ void libhttppp::HttpEvent::ResponseEvent(netplus::con &curcon,const int tid,ULON Http2RequestEvent(curcon, tid, args, "h2c", nullCb); } } // DATA generated above must be handed to the socket now. If the // socket is temporarily blocked, _flushSendDataNow() re-arms the // writable event so the response cannot remain parked forever. _flushSendDataNow(cureq); return; } Loading Loading
src/httpd.cpp +64 −14 Changes for src/httpd.cpp: 64 added lines, 14 removed lines. Original line number Diff line number Diff line Loading @@ -683,32 +683,77 @@ void libhttppp::HttpEvent::_finishH2Dispatch(HttpRequest &cureq, } bool libhttppp::HttpEvent::_flushSendDataNow(HttpRequest &cureq) { if (!(cureq.SendData.pos < cureq.SendData.size() && cureq.slots[0].csock)) return cureq.SendData.pos >= cureq.SendData.size(); auto &slot = cureq.slots[0]; if (!slot.csock) { return false; } bool blocked = false; try { while (cureq.SendData.pos < cureq.SendData.size()) { size_t remaining = cureq.SendData.size() - cureq.SendData.pos; size_t sendlen = std::min(remaining, static_cast<size_t>(16384)); netplus::buffer buf(cureq.SendData.data() + cureq.SendData.pos, sendlen); size_t sent = cureq.slots[0].csock->sendData(buf, 0); if (sent > 0) { const size_t remaining = cureq.SendData.size() - cureq.SendData.pos; const size_t sendlen = std::min<size_t>(remaining, 16 * 1024); netplus::buffer buf(cureq.SendData.data() + cureq.SendData.pos, sendlen); const size_t sent = slot.csock->sendData(buf, 0); if (sent == 0) { blocked = true; break; } cureq.SendData.pos += sent; if (cureq.slots[0].csock->hasPendingWrite()) cureq.slots[0].csock->flush_out(); } else { // sendData() may only enqueue encrypted TLS records. Try to // push them immediately, but retain the write interest when the // transport cannot drain the complete output buffer right now. if (slot.csock->hasPendingWrite()) { slot.csock->flush_out(); if (slot.csock->hasPendingWrite()) { blocked = true; break; } } } } catch (const std::exception &e) { std::cerr << "[HTTP-WRITE] deferred: " << e.what() << " pos=" << cureq.SendData.pos << " size=" << cureq.SendData.size() << std::endl; blocked = true; } catch (...) { // Socket busy or error — remaining data will be flushed // by IoEventHandler's send loop after we return. std::cerr << "[HTTP-WRITE] deferred: unknown exception" << " pos=" << cureq.SendData.pos << " size=" << cureq.SendData.size() << std::endl; blocked = true; } if (cureq.SendData.pos >= cureq.SendData.size()) { const bool appDataDone = cureq.SendData.pos >= cureq.SendData.size(); const bool transportDone = !slot.csock->hasPendingWrite(); if (appDataDone) { // sendData() has taken ownership of all plaintext bytes. It is safe // to release that buffer even when encrypted transport bytes are // still queued inside the socket implementation. cureq.SendData.clear(); cureq.SendData.pos = 0; } return cureq.SendData.pos >= cureq.SendData.size(); if (appDataDone && transportDone && !blocked) { slot.ResponsePending.store(false, std::memory_order_release); return true; } // A short write, EAGAIN, or queued TLS output must explicitly re-arm // EPOLLOUT/EVFILT_WRITE. Merely leaving bytes in SendData is not enough // with an edge-triggered or one-shot event loop. slot.ResponsePending.store(true, std::memory_order_release); netplus::requestWritablePoll(cureq); return false; } void libhttppp::HttpEvent::_resumeH2Streams(HttpRequest &cureq, Loading Loading @@ -1875,6 +1920,11 @@ void libhttppp::HttpEvent::ResponseEvent(netplus::con &curcon,const int tid,ULON Http2RequestEvent(curcon, tid, args, "h2c", nullCb); } } // DATA generated above must be handed to the socket now. If the // socket is temporarily blocked, _flushSendDataNow() re-arms the // writable event so the response cannot remain parked forever. _flushSendDataNow(cureq); return; } Loading