1
0

Add the sse-websocket module

This commit is contained in:
2026-09-04 00:52:18 +05:30
parent e1f8aa7402
commit 5224afdad2
51 changed files with 2761 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
=== spring.mvc.async.request-timeout ABSENT ===
{"spring.mvc.async.request-timeout":"<unset>","servletContainer":"Apache Tomcat/11.0.24","effectiveAsyncTimeoutMs":30000}
=== spring.mvc.async.request-timeout=5s ===
{"spring.mvc.async.request-timeout":"5s","servletContainer":"Apache Tomcat/11.0.24","effectiveAsyncTimeoutMs":5000}

View File

@@ -0,0 +1,4 @@
=== GET /ws handshake, varying only the Origin header ===
no Origin header -> HTTP/1.1 101
Origin: http://localhost -> HTTP/1.1 101
Origin: https://evil... -> HTTP/1.1 403

View File

@@ -0,0 +1,6 @@
=== server.tomcat.threads.max=10, clients=40 ===
emitters open : 40
connector pool size : 10 (max 10)
connector active : 0
one broadcast reached: 40 streams
clients that read it : 40

View File

@@ -0,0 +1,23 @@
=== GET /sse/silent?timeoutMs=1200 : whole response ===
| HTTP/1.1 200
| Content-Type: text/event-stream
| Transfer-Encoding: chunked
| Date: Thu, 03 Sep 2026 18:59:34 GMT
| Connection: close
|
| 1f
| event:hello
| data:then silence
|
|
| 0
|
=== stream ended after ~1697 ms ===
=== registry.timedOut(): 0 -> 1 ===
=== client closed the socket, then: ===
broadcasts before the write failed : 2
registry.sendsOk : 1
registry.sendsFailed : 0 -> 1
registry.open : 0
=== writes that appeared to succeed after the client was gone: 1 ===

View File

@@ -0,0 +1,8 @@
=== SseEmitter.event().data(record, APPLICATION_JSON) ===
{"seq":7,"host":"node-a","cpu":0.42,"heapMb":512,"at":"2026-09-03T10:00:00Z"}
=== SseEmitter.event().data(record) [no media type] ===
{"seq":7,"host":"node-a","cpu":0.42,"heapMb":512,"at":"2026-09-03T10:00:00Z"}
=== POJO: identical? true ===
=== String payload, no media type -> {"already":"json"}
=== String payload, APPLICATION_JSON -> {"already":"json"}
=== String payload, APPLICATION_JSON -> {"already":"json"}

View File

@@ -0,0 +1,22 @@
=== GET /sse/raw : raw bytes, one line per row ===
| HTTP/1.1 200
| Content-Type: text/event-stream
| Transfer-Encoding: chunked
| Date: Thu, 03 Sep 2026 18:59:33 GMT
| Connection: close
|
| ac
| :stream open
|
| id:1
| event:metric
| retry:3000
| data:{"seq":1,"host":"node-a","cpu":0.42,"heapMb":512,"at":"2026-09-03T10:00:00Z"}
|
| id:2
| event:note
| data:line one
| data:line two
|
|
| 0

View File

@@ -0,0 +1,23 @@
=== SEND /app/chat.send -> @SendTo("/topic/room") ===
alice received : ChatMessage[from=alice, text=is this thing on?, at=2026-09-03T18:59:36.632180396Z]
bob received : ChatMessage[from=alice, text=is this thing on?, at=2026-09-03T18:59:36.632180396Z]
=== presence events the server saw ===
| CONNECTED 122616fa-6e84-4c09-a317-6dee68f17794
| CONNECTED 22633c5f-f886-4ff2-94d0-156e43d92870
| SUBSCRIBE 122616fa-6e84-4c09-a317-6dee68f17794 -> /topic/room
| SUBSCRIBE 22633c5f-f886-4ff2-94d0-156e43d92870 -> /topic/room
| DISCONNECT 122616fa-6e84-4c09-a317-6dee68f17794 status=CloseStatus[code=1002, reason=null]
=== @MessageMapping("/chat.echo") with NO @SendTo ===
subscribed to /topic/chat.echo, received: ChatMessage[from=echo, text=who can see this?, at=2026-09-03T18:59:38.089388303Z]
=== SEND straight to /topic/room ===
received: ChatMessage[from=not-checked-by-anyone, text=unvalidated, at=2000-01-01T00:00:00Z]
=== the controller's Instant.now() rewrite did NOT happen ===
alice.getSessionId() [client side] : 97d9d368-53ab-0f29-0dd4-2c0515124971
server-side session id : c6ddbdda-36a6-4a9e-8a15-6714379ecdb9
=== convertAndSendToUser(aliceSession, "/queue/whisper", ..) ===
both subscribed to the SAME string : /user/queue/whisper
alice received : ChatMessage[from=42eda7c9-16b6-4ffc-bf68-60e8edfe4239, text=just for you, at=2026-09-03T19:00:15.135586620Z]
bob received : null

View File

@@ -0,0 +1,16 @@
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 25.88 s -- in com.ankurm.ssews.StompSizeLimitTunedBufferTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.620 s -- in com.ankurm.ssews.AsyncTimeoutUnsetTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.044 s -- in com.ankurm.ssews.SseWireFormatTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.042 s -- in com.ankurm.ssews.WebSocketHandshakeOriginTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.416 s -- in com.ankurm.ssews.AsyncTimeoutPropertyTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.144 s -- in com.ankurm.ssews.SseDisconnectTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.342 s -- in com.ankurm.ssews.SseConcurrencyTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.023 s -- in com.ankurm.ssews.SseTimeoutTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.146 s -- in com.ankurm.ssews.StompChatTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.647 s -- in com.ankurm.ssews.StompRoutingTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 13.52 s -- in com.ankurm.ssews.StompSizeLimitSpringLimitTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.040 s -- in com.ankurm.ssews.SseDataConversionTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.042 s -- in com.ankurm.ssews.WebSocketContainerRaisedTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 22.80 s -- in com.ankurm.ssews.StompSizeLimitDefaultBufferTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.143 s -- in com.ankurm.ssews.StompUserDestinationTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.025 s -- in com.ankurm.ssews.WebSocketContainerDefaultsTest

View File

@@ -0,0 +1,36 @@
The limit that fires first is the servlet container's WebSocket buffer, not Spring's
messageSizeLimit. 'body' below is the length of the JSON string field; the STOMP frame
carries about 90 bytes of headers on top of it.
=== container buffer: Tomcat default (8192, see /diag) ===
8 KB body -> delivered, body length 8192
16 KB body -> delivered, body length 16384
60 KB body -> NOT delivered, connection dropped
largest body delivered : 16459 bytes
smallest body rejected : 16522 bytes
=== container buffer set to 16384 ===
largest body delivered : 16446 bytes
smallest body rejected : 16496 bytes
=== container buffer set to 32768 ===
largest body delivered : 32615 bytes
smallest body rejected : 32665 bytes
=== container buffer set to 65536 ===
largest body delivered : 65350 bytes
smallest body rejected : 65400 bytes
=== bigframes profile: container buffer 256 KB, Spring limit 64 KB ===
16 KB body -> delivered, body length 16384
60 KB body -> delivered, body length 61440
desti..], byteCount=82068, last=true] in session 1655473b-76fe-4489-99d6-e3f8200b41b4. Sending STOMP ERROR to client.
org.springframework.messaging.simp.stomp.StompConversionException: The configured STOMP buffer size limit of 65536 bytes has been exceeded
80 KB body -> NOT delivered, connection dropped
desti..], byteCount=204949, last=true] in session 8dcce90c-48db-43a5-8d32-659da1fe32d8. Sending STOMP ERROR to client.
org.springframework.messaging.simp.stomp.StompConversionException: The configured STOMP buffer size limit of 65536 bytes has been exceeded
200 KB body -> NOT delivered, connection dropped
Spring's own limit, once the container is out of the way:
org.springframework.messaging.simp.stomp.StompConversionException: The configured STOMP buffer size limit of 65536 bytes has been exceeded
"ws.container.defaultMaxTextMessageBufferSize":262144
"ws.container.defaultMaxTextMessageBufferSize":8192