Loading debian/changelog +26 −0 Original line number Diff line number Diff line libhttppp (20260704+9) unstable; urgency=high * HttpClient::GetStream: fix unbounded blocking while reading response headers — each call to the header-read loop restarted a fresh 10s timeout on every partial chunk, so a peer trickling a byte every few seconds could hold the loop (and the calling thread) open indefinitely. Now uses a single 10s deadline for the whole header, throwing HTTPException on expiry instead of resetting the clock per chunk. * HttpEvent::_resumeH2Streams: fix HTTP/2 streaming responses (video, large previews) spinning forever instead of failing when the upstream stalls. The stall counter (emptyCount, capped at 500) was reset to 0 every time by checking ss->tempreq's own ResponsePending flag — but tempreq is a synthetic per-stream request with no external writer of that flag; it was actually being set, on every empty read, by the app-level ResponseEvent handler we had just called (a "rearm me for a real connection" signal, not a "new data arrived" signal), so the check always read true and the counter could never advance. Combined with the epoll layer re-arming EPOLLOUT every such cycle (always ready, since nothing is being written), a stalled upstream produced an unconditional, zero-backoff CPU spin with no progress on the stream. emptyCount now increments unconditionally on empty reads, so the existing 500-attempt cap actually terminates a genuinely stalled stream with END_STREAM instead of hanging. -- Jan Koester <jan.koester@tuxist.de> Sat, 04 Jul 2026 06:02:49 +0200 libhttppp (20260629+8) unstable; urgency=medium * HTTPException: derive from std::exception and change what() to the Loading Loading
debian/changelog +26 −0 Original line number Diff line number Diff line libhttppp (20260704+9) unstable; urgency=high * HttpClient::GetStream: fix unbounded blocking while reading response headers — each call to the header-read loop restarted a fresh 10s timeout on every partial chunk, so a peer trickling a byte every few seconds could hold the loop (and the calling thread) open indefinitely. Now uses a single 10s deadline for the whole header, throwing HTTPException on expiry instead of resetting the clock per chunk. * HttpEvent::_resumeH2Streams: fix HTTP/2 streaming responses (video, large previews) spinning forever instead of failing when the upstream stalls. The stall counter (emptyCount, capped at 500) was reset to 0 every time by checking ss->tempreq's own ResponsePending flag — but tempreq is a synthetic per-stream request with no external writer of that flag; it was actually being set, on every empty read, by the app-level ResponseEvent handler we had just called (a "rearm me for a real connection" signal, not a "new data arrived" signal), so the check always read true and the counter could never advance. Combined with the epoll layer re-arming EPOLLOUT every such cycle (always ready, since nothing is being written), a stalled upstream produced an unconditional, zero-backoff CPU spin with no progress on the stream. emptyCount now increments unconditionally on empty reads, so the existing 500-attempt cap actually terminates a genuinely stalled stream with END_STREAM instead of hanging. -- Jan Koester <jan.koester@tuxist.de> Sat, 04 Jul 2026 06:02:49 +0200 libhttppp (20260629+8) unstable; urgency=medium * HTTPException: derive from std::exception and change what() to the Loading