Skip to content

WIP, add/backport generic server-sent events support to Azure Core - #50081

Draft
Xiaofei Cao (XiaofeiCao) wants to merge 4 commits into
Azure:mainfrom
XiaofeiCao:sse-generic-listener-squashed
Draft

WIP, add/backport generic server-sent events support to Azure Core#50081
Xiaofei Cao (XiaofeiCao) wants to merge 4 commits into
Azure:mainfrom
XiaofeiCao:sse-generic-listener-squashed

Conversation

@XiaofeiCao

@XiaofeiCao Xiaofei Cao (XiaofeiCao) commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Scope

Adds Azure Core support for single-response generic SSE consumption. It parses one established Response<BinaryData>; it never reconnects, replays, or sends Last-Event-Id.

  • New: ServerSentEvent<T>, ServerSentEventListener<T>, ServerSentEventStreams, incremental SSE parsing, close-owning response handling, and optional typed terminal-event predicates.
  • Updated: REST proxy live-body preservation, response logging protection, and SSE media-type helpers.
  • Unchanged: HTTP pipeline, general policies, transports, BinaryData, and Reactor.
  • Separate stacked work: generated client APIs, shared proxy declarations, and generated event conversion.

Contract

ServerSentEventStreams is exported from com.azure.core.http; parser and response-owner types remain internal. Response overloads require a Closeable response and fail fast with IllegalArgumentException otherwise. Non-204 responses require exactly one text/event-stream content type; explicit non-UTF-8 charsets are rejected. Invalid or null-body responses are closed before failure.

Existing overloads complete on EOF or HTTP 204. Predicate overloads deliver the matching typed terminal event, close the response, and complete; EOF before a match is an incomplete-stream error. All paths close the physical response on completion, failure, interruption, or Reactor cancellation.

Accept: text/event-stream preserves a live body only when its q value is syntactically valid and greater than zero.

Validation

  • Focused SSE, media-type, and REST proxy tests
  • Azure Core package build
  • Checkstyle and SpotBugs

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff0a367c-664e-4de0-902b-ddaae2c86546
@github-actions github-actions Bot added the Azure.Core azure-core label Aug 10, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
34 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@XiaofeiCao Xiaofei Cao (XiaofeiCao) changed the title Add/backport generic server-sent events support to Azure Core WIP, add/backport generic server-sent events support to Azure Core Aug 11, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: ff0a367c-664e-4de0-902b-ddaae2c86546

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The incremental parser needs a bounded pending-event size before this is safe to ship.

appendByte doubles lineBytes without a maximum, and completed data: lines are accumulated in data until a blank line. A server (or intermediary) can therefore send either one unterminated line or an unlimited sequence of data: lines without an empty-line dispatch and make the client retain the entire stream until heap exhaustion. This affects both the async and listener paths.

Please enforce a documented maximum line/event size and terminate the stream with a clear exception when it is exceeded. Add tests for both an oversized single line and many bounded lines without a terminating blank line.

@XiaofeiCao

Copy link
Copy Markdown
Contributor Author

The incremental parser needs a bounded pending-event size before this is safe to ship.

appendByte doubles lineBytes without a maximum, and completed data: lines are accumulated in data until a blank line. A server (or intermediary) can therefore send either one unterminated line or an unlimited sequence of data: lines without an empty-line dispatch and make the client retain the entire stream until heap exhaustion. This affects both the async and listener paths.

Please enforce a documented maximum line/event size and terminate the stream with a clear exception when it is exceeded. Add tests for both an oversized single line and many bounded lines without a terminating blank line.

Some thoughts(evidence collected by agent):

Spring's 256kb limit doesn't seem to fit our knowledgebase retrieval case. Since currently we don't have configuration for response body size(correct me if I'm wrong), I'd say we don't enforce this.

@weidongxu-microsoft

Copy link
Copy Markdown
Member

Three minor follow-ups from the API/protocol pass:

  1. ServerSentEventStreams publicly accepts any Response<BinaryData>, but internally requires the runtime response to implement Closeable. Consider making that ownership requirement explicit in the API/type contract, or at least documenting it, so wrapped/custom responses don't fail unexpectedly.
  2. isTextEventStreamContentType currently accepts an explicitly non-UTF-8 charset such as text/event-stream; charset=iso-8859-1, while the parser always decodes UTF-8. SSE is UTF-8-only, so an incompatible charset declaration should be rejected.
  3. acceptsTextEventStream treats malformed or out-of-range quality values such as q=bogus, q=-1, and q=2 as enabled. It would be safer to validate the HTTP q-value grammar and only enable the media range for a valid value greater than zero.

These are non-blocking compared with the pending-event size concern.

@weidongxu-microsoft

Copy link
Copy Markdown
Member

Agent-generated Java SSE interface design comparison and recommendations: https://gist.github.com/weidongxu-microsoft/f99f792a78f16cef8c9c1674c68e7d1b

@weidongxu-microsoft

Weidong Xu (weidongxu-microsoft) commented Aug 12, 2026

Copy link
Copy Markdown
Member

Agent-generated Java SSE interface design comparison and recommendations: https://gist.github.com/weidongxu-microsoft/f99f792a78f16cef8c9c1674c68e7d1b

Summary aside, this is more or less the "alternative design" we've discussed. A closable stream pattern for sync.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: daa3657a-91d5-48fa-b7ae-6983091cab6a
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: daa3657a-91d5-48fa-b7ae-6983091cab6a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Azure.Core azure-core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants