Compare RSocket's TCP and WebSocket transports in Spring, and explain what session resumption (resume) is and how it interacts with security.
answer
- TCP = raw framed, fast, internal; WebSocket = HTTP-tunneled, browser/firewall
- Boot: spring.rsocket.server.transport=tcp|websocket (+ mapping-path)
- resume = reconnect + continue via resume token + frame buffer
- resume skips SETUP -> auth identity persists -> token is a bearer secret
- bound timeout + buffer; TLS/WSS mandatory; LB stickiness needed
basics
~20 sRSocket runs over TCP or WebSocket. TCP is a raw framed socket (fast, internal); WebSocket tunnels through HTTP (works through browsers/proxies/firewalls). Resume lets a dropped connection reconnect and continue the same session without losing in-flight streams, using a resume token.
solid answer
~40 sSpring exposes both transports: TCP via TcpServerTransport/TcpClientTransport (Boot: spring.rsocket.server.transport=tcp) and WebSocket via WebsocketServerTransport, mapped onto a WebFlux path (spring.rsocket.server.transport=websocket, mapping-path=/rsocket). TCP is lower overhead and typical for service-to-service; WebSocket traverses proxies/firewalls and reaches browsers. Resume is an RSocket protocol feature: enable Resume on server (RSocketServer.resume(new Resume(...))) and requester (connector.resume(new Resume())). Each side keeps an implied buffer of frames keyed by a resume token; if the transport drops, the client reconnects, presents the token, and the session continues without re-running SETUP or losing streams. Security implication: because resume skips a fresh SETUP, the connection's authenticated identity persists across reconnects — the resume token effectively bears the session, so it must be protected (TLS/WSS) and bounded (timeout, buffer size) to avoid session hijacking or unbounded memory. Per-request auth still applies to new frames.
code
java · 19 lines// Enable resume on the server (via customizer)
@Bean
RSocketServerCustomizer resumeCustomizer() {
return server -> server.resume(new Resume()
.sessionDuration(Duration.ofMinutes(5)) // bound the session
.retry(Retry.fixedDelay(5, Duration.ofSeconds(1))));
}
// Requester side: resumable + secured connection
RSocketRequester requester = RSocketRequester.builder()
.setupMetadata(new UsernamePasswordMetadata("user", "pass"),
MimeTypeUtils.parseMimeType(
WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString()))
.rsocketConnector(connector -> connector
.resume(new Resume().retry(Retry.fixedDelay(5, Duration.ofSeconds(1)))))
.tcp("localhost", 7000);
// application.properties (WebSocket instead of TCP):
// spring.rsocket.server.transport=websocket
// spring.rsocket.server.mapping-path=/rsocketgo deeper
Know RSocket runs over TCP or WebSocket and that resume reconnects a dropped connection.
Configure the transport in Boot and enable resume on both server and requester; know WebSocket is for browsers/firewalls.
Explain the resume token/frame buffer mechanics, buffer sizing trade-offs, and LB stickiness needs.
Reason about resume as a persisted authenticated session (bearer-token risk), bound it, enforce TLS/WSS + per-request auth, and design routing/state topology so resume survives scaling.
**Transports.** RSocket is transport-agnostic and Spring ships two: - **TCP** — a raw TCP socket with RSocket framing. Server: `TcpServerTransport`; client: `TcpClientTransport`. In Boot, `spring.rsocket.server.transport=tcp` and `spring.rsocket.server.port=7000`. Characteristics: lowest overhead, full duplex, ideal for **internal service-to-service** links. Not reachable from browsers; may be blocked by corporate firewalls/proxies that only allow HTTP(S). - **WebSocket** — RSocket framed inside WebSocket frames, which ride on an HTTP upgrade. Server: `WebsocketServerTransport`, integrated with WebFlux and mapped at a path (`spring.rsocket.server.transport=websocket`, `spring.rsocket.server.mapping-path=/rsocket`). Characteristics: traverses HTTP proxies, load balancers, and firewalls; reachable from **browser** clients (rsocket-js); slightly more overhead. Runs on the same server port as the HTTP app when embedded in WebFlux. - You can also run **standalone vs WebFlux-embedded** servers; TLS (TCP) or WSS (WebSocket) provides transport encryption — mandatory when carrying auth metadata. **Resume (session resumption).** RSocket connections are long-lived; transports drop (network blips, LB failover, mobile handover). **Resume** is a protocol capability that lets a client transparently **reconnect and continue the same logical session** instead of tearing down all streams and re-establishing. How it works: - The connection is created **resumable**: both peers agree during SETUP (a resume token is negotiated). In Spring/RSocket-Java you enable it with `RSocketServer.resume(new Resume())` on the server side (often via an `RSocketServerCustomizer`) and, on the requester, `RSocketConnector`/`RSocketRequester.Builder.rsocketConnector(c -> c.resume(new Resume()))`. - Each side keeps a **frame cache/implied-position buffer** of sent frames. On disconnect, the client opens a new transport connection and sends a **RESUME frame** carrying the **resume token** and its last-received position. The server matches the token to the retained session, retransmits missing frames from its buffer, and the in-flight request-streams/channels continue **without re-running SETUP**. - `Resume` is configurable: session duration/timeout, retry/backoff strategy, and the store (in-memory by default; the frame buffer is bounded). **Security interaction (the principal-level insight):** - Because resume **skips a fresh SETUP handshake**, the **authentication established at setup persists** across reconnects — the resume token effectively represents an authenticated session. That's convenient (no re-auth on every network blip) but means the **resume token is a bearer secret**: anyone who steals it could resume the authenticated session. Therefore: - **Always** run resumable connections over **TLS/WSS** so the token can't be sniffed. - **Bound** the resume session (timeout) so a stolen token has a limited window, and bound the **frame buffer size** to prevent memory-exhaustion DoS from a peer that never resumes. - Consider **per-request authentication** for sensitive routes so identity is re-asserted per frame, not solely inherited from the resumed session. - Token rotation/regeneration semantics are limited — treat resume tokens like session cookies: protect, scope, and time-box them. - New request frames after a resume still pass through the `PayloadSocketAcceptorInterceptor` authorization rules, so route-level authorization continues to apply; it's the *authentication identity* that is carried, not a bypass of authorization. **Edge cases / gotchas:** - **Buffer sizing**: too small and resume fails (frames evicted → session can't be recovered, client must reconnect fresh and re-SETUP); too large and it's a memory/DoS vector. - **Both peers must enable resume**; asymmetric config means the server rejects the RESUME frame and the client falls back to a new connection (losing streams). - **Load balancers**: resume requires reconnecting to a server that holds the session state. With multiple instances, sticky routing or a shared/session-aware layer is needed — naive round-robin LBs break resume. - **WebSocket + LB idle timeouts** can silently drop connections; resume mitigates the stream loss but you must tune keepalive. - Resume is **not** message durability/guaranteed delivery — it recovers a live session over a transient drop, not messages across a full session-timeout or server restart (unless a persistent frame store is used). **When to use:** resume shines for **mobile/unreliable networks** and long-lived streams where re-establishing (and re-authenticating) is expensive; internal, stable data-center links often skip it. Choose **TCP** for internal high-throughput services, **WebSocket** for browser reach or firewall traversal.
- Why does session resume have a security implication that a fresh reconnect does not?Resume continues the previously authenticated session without re-running SETUP, so the resume token bears the authenticated identity. A stolen token could hijack the session, so it must ride TLS/WSS and be time-boxed; a fresh reconnect would force re-authentication.
- Why can resume break behind a naive load balancer?Resume state (the frame buffer + session) lives on the specific server instance that held the connection. Round-robin routing may send the RESUME frame to an instance without that state, so it fails; you need sticky routing or shared session state.
- When would you pick WebSocket over TCP for RSocket?When you need browser clients (rsocket-js), must traverse HTTP proxies/firewalls that only permit HTTP(S), or want RSocket on the same port/path as an existing WebFlux app. TCP is preferred for internal, high-throughput service-to-service links.
saying these in an interview costs you the question
- Thinking resume guarantees durable message delivery across restarts rather than recovering a transient live session
- Believing resume re-runs SETUP (and thus re-authenticates) on every reconnect
- Assuming resume works transparently behind any load balancer without stickiness/shared state
- Treating the resume token as harmless rather than a bearer secret needing TLS and time-boxing
- Claiming TCP works for browser clients