Skip to content

fix: send the SSE response head before the first event - #1605

Merged
jlouvel merged 1 commit into
3.0from
fix/sse-early-response-head
Nov 2, 2026
Merged

jlouvel merged 1 commit into
3.0from
fix/sse-early-response-head

Conversation

@jlouvel

@jlouvel jlouvel commented Oct 30, 2026

Copy link
Copy Markdown
Collaborator

Fixes #1598.

Summary

The Netty server connector writes the response head without flushing it, and flushes it with the first body bytes. So an EventStreamRepresentation whose writer waited before its first event, with heartbeats off, sent no status or headers until that event.

EventStreamRepresentation.write() now flushes the output stream before running the writer. This commits the head at once, at the cost of one empty flush per stream, with no API change.

Testing

EventStreamConnectorTestCase has two new tests, over HTTP/1.1 and HTTP/2 (h2c upgrade). Each serves an idle stream without heartbeats and checks that the status, protocol version and Content-Type arrive within 5 seconds, before the first event. The event is then read.

These tests use the JDK HTTP client, which returns a response as soon as its head arrives. Both fail without the fix (timeout) and pass with it. EventStreamTestCase and EventStreamConnectorTestCase pass locally (12 tests). The full core suite runs on CI.

Note: the Restlet client still waits for the first byte

The Restlet HTTP client returns a response only after peeking at the first body byte (NettyClientCall.nonEmpty). With the Restlet client, Client.handle() therefore still blocks on an idle stream, even though the head has arrived. #1556 (R0) removes that peek for HTTP/2 streams. HTTP/1.1 would need a separate change, so it isn't part of this PR.

🤖 Generated with Claude Code

@jlouvel jlouvel self-assigned this Oct 31, 2026
@jlouvel
jlouvel requested a balanced review from Copilot October 31, 2026 07:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues were identified for the change enabling early SSE header delivery.

No open issues 🎉

What changed in this PR

Fixes #1598 by flushing the SSE output stream before invoking the event writer, allowing clients to receive status and headers while a stream is idle, without waiting for an event or heartbeat.

Changes:

  • Adds an initial flush to EventStreamRepresentation without changing its API.
  • Adds HTTP/1.1 and HTTP/2 regression tests using the JDK client to verify headers arrive before the first event.
  • Records the fix in the changelog; Restlet client body-peeking behavior remains outside this PR’s scope.
File Description
org.restlet/​src/​test/​java/​org/​restlet/​engine/​connector/​EventStreamConnectorTestCase.java Tests early header delivery and subsequent event reading over both HTTP versions.
org.restlet/​src/​main/​java/​org/​restlet/​representation/​EventStreamRepresentation.java Flushes the output stream before running the event writer.
changes.md Documents early SSE header delivery for issue #1598.

Review effort: Balanced

@jlouvel
jlouvel force-pushed the fix/sse-early-response-head branch from bd2d8c1 to 1086af9 Compare November 1, 2026 14:49
The Netty server connector writes the response head without flushing
it, and flushes it with the first body bytes. An EventStreamRepresentation
whose writer waited before its first event, without heartbeats, so sent
no status or headers until then.

EventStreamRepresentation.write() now flushes the output stream before
running the writer. A connector test checks, with the JDK HTTP client,
that the head of an idle stream arrives over HTTP/1.1 and HTTP/2.

Fixes #1598.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Jerome Louvel <374450+jlouvel@users.noreply.github.com>
@jlouvel
jlouvel force-pushed the fix/sse-early-response-head branch from 1086af9 to bcf28bb Compare November 1, 2026 21:29
@sonarqubecloud

sonarqubecloud Bot commented Nov 1, 2026

Copy link
Copy Markdown

@jlouvel
jlouvel merged commit 079619e into 3.0 Nov 2, 2026
3 checks passed
@jlouvel
jlouvel deleted the fix/sse-early-response-head branch November 2, 2026 00:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants