-
Notifications
You must be signed in to change notification settings - Fork 1.6k
SSE (Server-Sent Events) response body not flushed to downstream on macOS #841
Description
Description
When proxying SSE (Server-Sent Events) responses through Pingora on macOS, the response body chunks are received from upstream but never flushed to the downstream client. The same setup works correctly on Linux.
Environment
- macOS: Darwin 24.6.0 (Apple Silicon, aarch64)
- Linux: Ubuntu 22.04 x86_64 (works correctly)
- Pingora version: 0.8.0
- Rust: stable
Steps to Reproduce
- Set up a simple upstream server that serves SSE responses (
Content-Type: text/event-stream,Transfer-Encoding: chunked) - Configure Pingora as a reverse proxy forwarding to this upstream
- Send a GET request to the proxy endpoint from macOS
Expected Behavior
SSE events should be streamed to the client in real-time as they arrive from upstream.
Actual Behavior (macOS only)
- Pingora successfully connects to upstream and receives the response headers
- Upstream body chunks are received (confirmed via
response_body_filterlogging) - However, no data reaches the downstream client — curl shows no output
- After curl timeout, the connection is reset with:
Fail to proxy: Downstream ConnectionClosed ... Prematurely before response body is complete - Debug logs show the downstream socket's BufWriter has
written: 0despite data being in the buffer
Debug Log Evidence
[DEBUG] Detected streaming response: text/event-stream
[DEBUG] Streaming chunk: 937 bytes, eof: false ← data received from upstream
[DEBUG] Streaming chunk: 318 bytes, eof: false ← more data received
[ERROR] Fail to proxy: Downstream ConnectionClosed
context: Prematurely before response body is complete
status: 0 ← 0 bytes written downstream
The BufWriter state at connection close:
BufStream { inner: BufReader { reader: BufWriter {
writer: ..., buffer: 0/1460, written: 0 ← 1460 bytes buffered, 0 written
}}}
Analysis
The issue appears to be in the HTTP/1.1 downstream write path. Pingora's do_write_chunked_body in body.rs does call stream.flush() after each chunk write. However, on macOS, the data appears to remain in the BufWriter's buffer (1460 bytes = typical TCP MSS) without being flushed to the socket.
This suggests a platform-specific difference in how AsyncWrite::flush() behaves on macOS vs Linux TCP sockets, possibly related to:
- TCP_NODELAY not being set on the downstream socket
- macOS TCP stack buffering behavior differences
- BufWriter not propagating flush to the underlying TCP stream
Workarounds Attempted (none worked on macOS)
session.set_keepalive(None)- Custom
response_body_filterreturningOk(None)(no delay) - Custom
upstream_response_filtersetting chunked encoding headers - Removing all custom filters (bare Pingora proxy) — still fails on macOS
Impact
- Normal HTTP requests (GET, POST with complete responses) work fine on macOS
- Only streaming/long-lived responses (SSE, potentially WebSocket) are affected
- Linux works perfectly — this is macOS-only
Notes
macOS is commonly used for development. While Pingora is primarily designed for Linux production deployments, macOS development support would significantly improve the developer experience.
Reported by siyuan — discovered while building gateway-rs