Observation
Found while addressing review feedback on #326, which removed this header from the new
/v1/messages SSE response. The same header is set on the two pre-existing streaming endpoints:
src/DotLLM.Server/Endpoints/ChatCompletionEndpoint.cs:190
src/DotLLM.Server/Endpoints/CompletionEndpoint.cs:126
context.Response.Headers.Append("Connection", "keep-alive");
Connection is a hop-by-hop header and is prohibited in HTTP/2 and HTTP/3 (RFC 9113 §8.2.2 —
an endpoint MUST treat a message containing connection-specific header fields as malformed). Under
HTTP/1.1 it is merely redundant, since keep-alive is the default.
Impact
Kestrel does not send it on HTTP/2, so this is not currently breaking anything observable in the
common configuration — which is why it has gone unnoticed. It becomes a problem when a strict
intermediary is in the path, or if the header is ever set somewhere Kestrel does not filter. It also
reads as intentional to anyone copying the pattern into a new endpoint, which is how it reached the
Anthropic endpoint in the first place.
Proposed change
Remove the Connection header from both endpoints. Content-Type: text/event-stream and
Cache-Control: no-cache are the headers that actually matter for SSE, and both are already set.
Optionally add a brief comment recording why it is deliberately absent, so it is not re-added by the
next endpoint author.
Acceptance criteria
References
Observation
Found while addressing review feedback on #326, which removed this header from the new
/v1/messagesSSE response. The same header is set on the two pre-existing streaming endpoints:src/DotLLM.Server/Endpoints/ChatCompletionEndpoint.cs:190src/DotLLM.Server/Endpoints/CompletionEndpoint.cs:126Connectionis a hop-by-hop header and is prohibited in HTTP/2 and HTTP/3 (RFC 9113 §8.2.2 —an endpoint MUST treat a message containing connection-specific header fields as malformed). Under
HTTP/1.1 it is merely redundant, since keep-alive is the default.
Impact
Kestrel does not send it on HTTP/2, so this is not currently breaking anything observable in the
common configuration — which is why it has gone unnoticed. It becomes a problem when a strict
intermediary is in the path, or if the header is ever set somewhere Kestrel does not filter. It also
reads as intentional to anyone copying the pattern into a new endpoint, which is how it reached the
Anthropic endpoint in the first place.
Proposed change
Remove the
Connectionheader from both endpoints.Content-Type: text/event-streamandCache-Control: no-cacheare the headers that actually matter for SSE, and both are already set.Optionally add a brief comment recording why it is deliberately absent, so it is not re-added by the
next endpoint author.
Acceptance criteria
Connectionheader.AnthropicStreamingTestscan be reused).References
/v1/messages; this issue covers the two endpoints that PRdoes not touch, since it is additive and they are pre-existing