Skip to content

feat: add WebSocket extension - #1547

Open
jlouvel wants to merge 6 commits into
feat/rpc-c7-sse-apifrom
feat/rpc-c8-websocket
Open

jlouvel wants to merge 6 commits into
feat/rpc-c7-sse-apifrom
feat/rpc-c8-websocket

Conversation

@jlouvel

@jlouvel jlouvel commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds experimental WebSocket support as a new org.restlet.ext.websocket extension module, on top of the Netty connectors (stacked on #1546). It keeps the blocking, virtual-thread programming model. The core only gains a small, generic connection-upgrade hook.

Core (org.restlet, org.restlet.engine.netty)

  • NettyConnectionUpgrade: if a Restlet returns 101 Switching Protocols with this response attribute, the Netty server connector removes its HTTP handlers and hands the HTTP/1.1 connection to the upgrade instead of writing the response. HTTP/2 and HTTP/3 calls get 501. If the upgrade fails, the connection is closed.
  • NettyUpgradeContext: the channel, the upgrade request head, TLS flag, connector parameters and attributes, idle timeout and logger.
  • No WebSocket types or parameters in the core.

Extension (org.restlet.ext.websocket)

  • WebSocketUpgrader: a Restlet that accepts or rejects upgrades and can pick a subprotocol. The upgrade goes through normal routing, filters and authenticators.
  • WebSocketUpgrade: lower-level hook (isRequested, getRequestedSubprotocols, accept(response, handler, subprotocol)).
  • WebSocketHandler: runs on its own virtual thread per session. Returning closes with 1000; throwing closes with 1011.
  • WebSocketSession: blocking receive() (null once closed), sendText / sendBinary / send, close(code, reason), getSubprotocol, close status and reason.
  • WebSocketMessage: immutable text or binary message.
  • WebSocketClient: builder-configured client for ws / wss (SSL context, subprotocols, extra handshake headers, timeouts, max message and frame sizes, compression, hostname verification).
  • Internals: on-demand reads with a bounded inbound queue (back-pressure), writes wait for channel writability, ping→pong, idle ping then close, close-handshake echo, 1009 on oversized messages.
  • permessage-deflate (RFC 7692) on server and client, on by default; inflated messages are capped by the message size (1009 otherwise).
  • Server connector parameters read by the extension: websocket.maxSessions (extra upgrades get 503), websocket.maxMessageSize (default 65536), websocket.maxFrameSize (defaults to, and capped by, the message size) and websocket.compression (default true).

Scope / limits

  • HTTP/1.1 upgrade only: no RFC 8441 WebSocket over HTTP/2 yet.
  • No Autobahn conformance run yet (listed for m5 in the migration memo).

Validation

  • ./mvnw -B -pl org.restlet,org.restlet.ext.websocket verify -P default,test passes for both modules, including Spotless, JaCoCo 80% and SpotBugs (0 findings in the extension).
  • Core: NettyConnectionUpgradeTestCase covers the connection hand-over and a failing upgrade.
  • Extension: 27 tests:
    • text and binary echo with subprotocol
    • closes initiated by the server and by the client, with code and reason
    • 1009 on oversized messages
    • routing + authenticator (401 / 404) on upgrades
    • 400 for plain GETs
    • session limit and permit release
    • wss over TLS
    • idle pings kept alive by pongs
    • handler failure closing with 1011
    • connection failures and builder validation
    • interop with the JDK java.net.http.WebSocket client
    • permessage-deflate negotiation (accepted, disabled, not offered), compressed round trips, inflated messages capped at the message size, frame size limits on server and client

jlouvel and others added 2 commits October 18, 2026 14:33
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jerome Louvel <374450+jlouvel@users.noreply.github.com>
Keep only a generic NettyConnectionUpgrade hook in the core connector.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jerome Louvel <374450+jlouvel@users.noreply.github.com>
@jlouvel jlouvel changed the title feat: add WebSocket API feat: add WebSocket extension Oct 18, 2026
jlouvel and others added 4 commits October 18, 2026 18:38
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jerome Louvel <374450+jlouvel@users.noreply.github.com>
org.restlet.ext.websocket.internal is not exported by the module.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jerome Louvel <374450+jlouvel@users.noreply.github.com>
Negotiate permessage-deflate (RFC 7692) on the server and the client, cap inflated messages by the message size, and add a separate frame size limit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jerome Louvel <374450+jlouvel@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sonarqubecloud

Copy link
Copy Markdown

@jlouvel jlouvel self-assigned this Oct 20, 2026
@jlouvel
jlouvel added this pull request to stack #1548 October 20, 2026 12:42
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