You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: warn when a ReadsBody plugin lands in SSE passthrough
A plugin that declares ReadsBody but is not a StreamingResponder falls
into streamPassthrough, where its OnResponse runs against an empty
pctx.ResponseBody (the stream is forwarded unbuffered to avoid the #642
timeout). Emit a slog.Warn -- mirroring the existing WritesBody fallback
-- so the misconfiguration surfaces instead of silently starving the
plugin of the body. Buffering is intentionally not the fix; such a plugin
should implement StreamingResponder.
Add TestForwardProxy_SSE_ReadsBodyPluginWarnsAndStreams: the stream is
still delivered verbatim, OnResponse sees an empty body, and the warning
fires.
Addresses review feedback on #675.
Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com>
Signed-off-by: Hai Huang <huang195@gmail.com>
Copy file name to clipboardExpand all lines: authbridge/authlib/listener/forwardproxy/server.go
+15Lines changed: 15 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -395,6 +395,21 @@ func (s *Server) serveOutbound(w http.ResponseWriter, r *http.Request, isBridge
395
395
// with per-write flushing. Re-framing (handleStreamingResponse)
396
396
// would drop the event:/id:/retry: lines that generic SSE
397
397
// clients (e.g. an MCP Streamable HTTP client) depend on. Fixes #642.
398
+
//
399
+
// A plugin that declares ReadsBody (but not WritesBody, and is
400
+
// not a StreamingResponder) also lands here, and its OnResponse
401
+
// runs against an empty pctx.ResponseBody: streamPassthrough
402
+
// forwards the stream without buffering it. We deliberately don't
403
+
// buffer to satisfy such a plugin — that would reintroduce the
404
+
// #642 timeout on a live stream. A plugin that must inspect a
405
+
// streamed body should implement StreamingResponder. Warn
406
+
// (mirroring the WritesBody fallback above) so the
407
+
// misconfiguration surfaces instead of the plugin silently seeing
408
+
// no body. WritesBody is already false in this branch, so
409
+
// NeedsBody() here implies ReadsBody.
410
+
ifs.OutboundPipeline.NeedsBody() {
411
+
slog.Warn("forward-proxy: text/event-stream response with a ReadsBody plugin that is not a StreamingResponder — streaming byte-for-byte; its OnResponse will see an empty body (implement StreamingResponder to inspect a streamed body)", "host", r.Host)
0 commit comments