Loading src/http/HttpProxyServer.cpp +18 −12 Changes for src/http/HttpProxyServer.cpp: 18 added lines, 12 removed lines. Original line number Diff line number Diff line Loading @@ -118,7 +118,8 @@ HttpProxyController::HttpProxyController(std::vector<netplus::socket *> serverSo tls::AcmeChallengeStore *acmeChallenges, int idleTimeoutSeconds, int upstreamTimeoutSeconds, int h2DispatchQueueMax) int h2DispatchQueueMax, int h1DispatchQueueMax) // H2 dispatch now runs through the same offload pool as H1 (see shouldOffloadH2Dispatch // below): both RequestEvent calls do real backend I/O, so both need off the shared // epoll/kqueue listener workers to avoid one bursty connection starving new TLS Loading @@ -126,15 +127,15 @@ HttpProxyController::HttpProxyController(std::vector<netplus::socket *> serverSo // try/catch around RequestEvent (see httpd.cpp's _dispatchH2Stream) -- without it, a // backend exception left the stream queued forever with no HEADERS/DATA/RST_STREAM ever // sent. ALPN is left at HttpEvent's own default (prefer h2, fall back to http/1.1) below; // H3 stays independent via QUIC/Alt-Svc regardless. h2DispatchQueueMax bounds that same // pool's queue (see httpd.h) so a saturated/stuck pool degrades to 503 instead of every // subsequent stream -- on every connection -- queuing forever with no way to notice; see // BootstrapConfig.h's h2DispatchQueueMax doc comment for the incident this fixes. // H3 stays independent via QUIC/Alt-Svc regardless. h2DispatchQueueMax/h1DispatchQueueMax // bound those same pools' queues (see httpd.h) so a saturated/stuck pool degrades to 503 // instead of every subsequent stream/request -- on every connection -- queuing forever // with no way to notice; see BootstrapConfig.h's doc comments for the incidents this fixes. : libhttppp::HttpEvent(serverSockets, /*timeout=*/1000, /*h2OffloadThreads=*/(std::max<size_t>)(4, std::thread::hardware_concurrency() * 2), idleTimeoutSeconds, /*h1OffloadThreads=*/(std::max<size_t>)(4, std::thread::hardware_concurrency() * 2), h2DispatchQueueMax) h2DispatchQueueMax, h1DispatchQueueMax) , _listenerLabel(std::move(listenerLabel)) , _tlsActive(tlsActive) , _configStore(configStore) Loading @@ -144,7 +145,8 @@ HttpProxyController::HttpProxyController(std::vector<netplus::socket *> serverSo , _connectionPool(connectionPool) , _acmeChallenges(acmeChallenges) , _upstreamTimeoutSeconds(upstreamTimeoutSeconds) , _h2DispatchQueueMax(h2DispatchQueueMax) { , _h2DispatchQueueMax(h2DispatchQueueMax) , _h1DispatchQueueMax(h1DispatchQueueMax) { } bool HttpProxyController::shouldOffloadH2Dispatch(libhttppp::HttpRequest &, uint32_t) const { Loading Loading @@ -670,7 +672,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener, std::string ce tls::AcmeChallengeStore *acmeChallenges, int idleTimeoutSeconds, int upstreamTimeoutSeconds, int h2DispatchQueueMax) int h2DispatchQueueMax, int h1DispatchQueueMax) : _listener(listener) , _tlsActive(!listener.tlsProfile.empty()) , _httpd(std::make_unique<libhttppp::HttpD>(listener.address, listener.port, 512, certPath, Loading @@ -683,7 +686,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener, std::string ce , _acmeChallenges(acmeChallenges) , _idleTimeoutSeconds(idleTimeoutSeconds) , _upstreamTimeoutSeconds(upstreamTimeoutSeconds) , _h2DispatchQueueMax(h2DispatchQueueMax) { , _h2DispatchQueueMax(h2DispatchQueueMax) , _h1DispatchQueueMax(h1DispatchQueueMax) { bindAndListen(); } Loading @@ -695,7 +699,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener, tls::AcmeChallengeStore *acmeChallenges, int idleTimeoutSeconds, int upstreamTimeoutSeconds, int h2DispatchQueueMax) int h2DispatchQueueMax, int h1DispatchQueueMax) : _listener(listener) , _tlsActive(true) , _httpd(std::make_unique<libhttppp::HttpD>(listener.address, listener.port, 512, certsByHostname)) Loading @@ -707,7 +712,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener, , _acmeChallenges(acmeChallenges) , _idleTimeoutSeconds(idleTimeoutSeconds) , _upstreamTimeoutSeconds(upstreamTimeoutSeconds) , _h2DispatchQueueMax(h2DispatchQueueMax) { , _h2DispatchQueueMax(h2DispatchQueueMax) , _h1DispatchQueueMax(h1DispatchQueueMax) { bindAndListen(); } Loading @@ -728,7 +734,7 @@ void HttpProxyServer::run() { _tlsActive, _configStore, _authService, _pluginManager, _loadBalancer, _connectionPool, _acmeChallenges, _idleTimeoutSeconds, _upstreamTimeoutSeconds, _h2DispatchQueueMax); _h2DispatchQueueMax, _h1DispatchQueueMax); controller.runEventloop(); } Loading src/http/HttpProxyServer.h +8 −5 Changes for src/http/HttpProxyServer.h: 8 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -124,9 +124,9 @@ private: // from a worker thread after privileges have been dropped. class HttpProxyServer { public: // idleTimeoutSeconds/upstreamTimeoutSeconds/h2DispatchQueueMax: see HttpProxyController's // own doc comment above -- threaded down into the controller it constructs internally in // run(). // idleTimeoutSeconds/upstreamTimeoutSeconds/h2DispatchQueueMax/h1DispatchQueueMax: see // HttpProxyController's own doc comment above -- threaded down into the controller it // constructs internally in run(). HttpProxyServer(config::ListenerConfig listener, std::string certPath, std::string keyPath, Loading @@ -138,7 +138,8 @@ public: tls::AcmeChallengeStore *acmeChallenges = nullptr, int idleTimeoutSeconds = 0, int upstreamTimeoutSeconds = 60, int h2DispatchQueueMax = 256); int h2DispatchQueueMax = 256, int h1DispatchQueueMax = 256); // SNI virtual hosting variant: certsByHostname carries one CertificateBundle per domain // sharing this listener (see ListenerConfig::tlsProfiles) instead of the single cert/key Loading @@ -153,7 +154,8 @@ public: tls::AcmeChallengeStore *acmeChallenges = nullptr, int idleTimeoutSeconds = 0, int upstreamTimeoutSeconds = 60, int h2DispatchQueueMax = 256); int h2DispatchQueueMax = 256, int h1DispatchQueueMax = 256); void run(); Loading Loading @@ -184,6 +186,7 @@ private: int _idleTimeoutSeconds; int _upstreamTimeoutSeconds; int _h2DispatchQueueMax; int _h1DispatchQueueMax; }; } // namespace proxyplus::httpproxy src/main.cpp +3 −2 Changes for src/main.cpp: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -356,7 +356,8 @@ int main(int argc, char **argv) { httpServers.push_back(std::make_unique<proxyplus::httpproxy::HttpProxyServer>( listener, sniCerts, configStore, authService, pluginManager, loadBalancer, connectionPool, &acmeChallenges, cfg.idleConnectionTimeoutSeconds, cfg.upstreamRequestTimeoutSeconds, cfg.h2DispatchQueueMax)); cfg.upstreamRequestTimeoutSeconds, cfg.h2DispatchQueueMax, cfg.h1DispatchQueueMax)); auto *server = httpServers.back().get(); auto allProfiles = configStore.listTlsProfiles(); for (const auto &profileName : tlsProfiles) { Loading @@ -378,7 +379,7 @@ int main(int argc, char **argv) { listener, certPathFor(cfg, profile), keyPathFor(cfg, profile), configStore, authService, pluginManager, loadBalancer, connectionPool, &acmeChallenges, cfg.idleConnectionTimeoutSeconds, cfg.upstreamRequestTimeoutSeconds, cfg.h2DispatchQueueMax)); cfg.h2DispatchQueueMax, cfg.h1DispatchQueueMax)); if (!profile.empty()) { auto *server = httpServers.back().get(); certManager.registerReloadCallback(profile, [server, &cfg, profile] { Loading Loading
src/http/HttpProxyServer.cpp +18 −12 Changes for src/http/HttpProxyServer.cpp: 18 added lines, 12 removed lines. Original line number Diff line number Diff line Loading @@ -118,7 +118,8 @@ HttpProxyController::HttpProxyController(std::vector<netplus::socket *> serverSo tls::AcmeChallengeStore *acmeChallenges, int idleTimeoutSeconds, int upstreamTimeoutSeconds, int h2DispatchQueueMax) int h2DispatchQueueMax, int h1DispatchQueueMax) // H2 dispatch now runs through the same offload pool as H1 (see shouldOffloadH2Dispatch // below): both RequestEvent calls do real backend I/O, so both need off the shared // epoll/kqueue listener workers to avoid one bursty connection starving new TLS Loading @@ -126,15 +127,15 @@ HttpProxyController::HttpProxyController(std::vector<netplus::socket *> serverSo // try/catch around RequestEvent (see httpd.cpp's _dispatchH2Stream) -- without it, a // backend exception left the stream queued forever with no HEADERS/DATA/RST_STREAM ever // sent. ALPN is left at HttpEvent's own default (prefer h2, fall back to http/1.1) below; // H3 stays independent via QUIC/Alt-Svc regardless. h2DispatchQueueMax bounds that same // pool's queue (see httpd.h) so a saturated/stuck pool degrades to 503 instead of every // subsequent stream -- on every connection -- queuing forever with no way to notice; see // BootstrapConfig.h's h2DispatchQueueMax doc comment for the incident this fixes. // H3 stays independent via QUIC/Alt-Svc regardless. h2DispatchQueueMax/h1DispatchQueueMax // bound those same pools' queues (see httpd.h) so a saturated/stuck pool degrades to 503 // instead of every subsequent stream/request -- on every connection -- queuing forever // with no way to notice; see BootstrapConfig.h's doc comments for the incidents this fixes. : libhttppp::HttpEvent(serverSockets, /*timeout=*/1000, /*h2OffloadThreads=*/(std::max<size_t>)(4, std::thread::hardware_concurrency() * 2), idleTimeoutSeconds, /*h1OffloadThreads=*/(std::max<size_t>)(4, std::thread::hardware_concurrency() * 2), h2DispatchQueueMax) h2DispatchQueueMax, h1DispatchQueueMax) , _listenerLabel(std::move(listenerLabel)) , _tlsActive(tlsActive) , _configStore(configStore) Loading @@ -144,7 +145,8 @@ HttpProxyController::HttpProxyController(std::vector<netplus::socket *> serverSo , _connectionPool(connectionPool) , _acmeChallenges(acmeChallenges) , _upstreamTimeoutSeconds(upstreamTimeoutSeconds) , _h2DispatchQueueMax(h2DispatchQueueMax) { , _h2DispatchQueueMax(h2DispatchQueueMax) , _h1DispatchQueueMax(h1DispatchQueueMax) { } bool HttpProxyController::shouldOffloadH2Dispatch(libhttppp::HttpRequest &, uint32_t) const { Loading Loading @@ -670,7 +672,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener, std::string ce tls::AcmeChallengeStore *acmeChallenges, int idleTimeoutSeconds, int upstreamTimeoutSeconds, int h2DispatchQueueMax) int h2DispatchQueueMax, int h1DispatchQueueMax) : _listener(listener) , _tlsActive(!listener.tlsProfile.empty()) , _httpd(std::make_unique<libhttppp::HttpD>(listener.address, listener.port, 512, certPath, Loading @@ -683,7 +686,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener, std::string ce , _acmeChallenges(acmeChallenges) , _idleTimeoutSeconds(idleTimeoutSeconds) , _upstreamTimeoutSeconds(upstreamTimeoutSeconds) , _h2DispatchQueueMax(h2DispatchQueueMax) { , _h2DispatchQueueMax(h2DispatchQueueMax) , _h1DispatchQueueMax(h1DispatchQueueMax) { bindAndListen(); } Loading @@ -695,7 +699,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener, tls::AcmeChallengeStore *acmeChallenges, int idleTimeoutSeconds, int upstreamTimeoutSeconds, int h2DispatchQueueMax) int h2DispatchQueueMax, int h1DispatchQueueMax) : _listener(listener) , _tlsActive(true) , _httpd(std::make_unique<libhttppp::HttpD>(listener.address, listener.port, 512, certsByHostname)) Loading @@ -707,7 +712,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener, , _acmeChallenges(acmeChallenges) , _idleTimeoutSeconds(idleTimeoutSeconds) , _upstreamTimeoutSeconds(upstreamTimeoutSeconds) , _h2DispatchQueueMax(h2DispatchQueueMax) { , _h2DispatchQueueMax(h2DispatchQueueMax) , _h1DispatchQueueMax(h1DispatchQueueMax) { bindAndListen(); } Loading @@ -728,7 +734,7 @@ void HttpProxyServer::run() { _tlsActive, _configStore, _authService, _pluginManager, _loadBalancer, _connectionPool, _acmeChallenges, _idleTimeoutSeconds, _upstreamTimeoutSeconds, _h2DispatchQueueMax); _h2DispatchQueueMax, _h1DispatchQueueMax); controller.runEventloop(); } Loading
src/http/HttpProxyServer.h +8 −5 Changes for src/http/HttpProxyServer.h: 8 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -124,9 +124,9 @@ private: // from a worker thread after privileges have been dropped. class HttpProxyServer { public: // idleTimeoutSeconds/upstreamTimeoutSeconds/h2DispatchQueueMax: see HttpProxyController's // own doc comment above -- threaded down into the controller it constructs internally in // run(). // idleTimeoutSeconds/upstreamTimeoutSeconds/h2DispatchQueueMax/h1DispatchQueueMax: see // HttpProxyController's own doc comment above -- threaded down into the controller it // constructs internally in run(). HttpProxyServer(config::ListenerConfig listener, std::string certPath, std::string keyPath, Loading @@ -138,7 +138,8 @@ public: tls::AcmeChallengeStore *acmeChallenges = nullptr, int idleTimeoutSeconds = 0, int upstreamTimeoutSeconds = 60, int h2DispatchQueueMax = 256); int h2DispatchQueueMax = 256, int h1DispatchQueueMax = 256); // SNI virtual hosting variant: certsByHostname carries one CertificateBundle per domain // sharing this listener (see ListenerConfig::tlsProfiles) instead of the single cert/key Loading @@ -153,7 +154,8 @@ public: tls::AcmeChallengeStore *acmeChallenges = nullptr, int idleTimeoutSeconds = 0, int upstreamTimeoutSeconds = 60, int h2DispatchQueueMax = 256); int h2DispatchQueueMax = 256, int h1DispatchQueueMax = 256); void run(); Loading Loading @@ -184,6 +186,7 @@ private: int _idleTimeoutSeconds; int _upstreamTimeoutSeconds; int _h2DispatchQueueMax; int _h1DispatchQueueMax; }; } // namespace proxyplus::httpproxy
src/main.cpp +3 −2 Changes for src/main.cpp: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -356,7 +356,8 @@ int main(int argc, char **argv) { httpServers.push_back(std::make_unique<proxyplus::httpproxy::HttpProxyServer>( listener, sniCerts, configStore, authService, pluginManager, loadBalancer, connectionPool, &acmeChallenges, cfg.idleConnectionTimeoutSeconds, cfg.upstreamRequestTimeoutSeconds, cfg.h2DispatchQueueMax)); cfg.upstreamRequestTimeoutSeconds, cfg.h2DispatchQueueMax, cfg.h1DispatchQueueMax)); auto *server = httpServers.back().get(); auto allProfiles = configStore.listTlsProfiles(); for (const auto &profileName : tlsProfiles) { Loading @@ -378,7 +379,7 @@ int main(int argc, char **argv) { listener, certPathFor(cfg, profile), keyPathFor(cfg, profile), configStore, authService, pluginManager, loadBalancer, connectionPool, &acmeChallenges, cfg.idleConnectionTimeoutSeconds, cfg.upstreamRequestTimeoutSeconds, cfg.h2DispatchQueueMax)); cfg.h2DispatchQueueMax, cfg.h1DispatchQueueMax)); if (!profile.empty()) { auto *server = httpServers.back().get(); certManager.registerReloadCallback(profile, [server, &cfg, profile] { Loading