Don't negotiate leafnode compression over WebSockets#7969
Don't negotiate leafnode compression over WebSockets#7969neilalexander wants to merge 1 commit intomainfrom
Conversation
WebSockets already have compression, so this would be wasteful and likely counter-productive to do so twice. Signed-off-by: Neil Twigg <neil@nats.io>
|
Claude finished @neilalexander's task in 2m 1s —— View job PR Review
SummaryThe change is correct and well-motivated. WebSocket already negotiates compression at the framing layer (permessage-deflate), so layering S2 compression on top would waste CPU without benefit. The fix is minimal and focused. Control flow (
One issue to address (see inline comment):
Test ( No other issues found. |
| func (s *Server) negotiateLeafCompression(c *client, didSolicit bool, infoCompression string, co *CompressionOpts) (bool, error) { | ||
| // WebSockets already have compression available so shouldn't negotiate | ||
| // a second layer of it. | ||
| if c.isWebsocket() { |
There was a problem hiding this comment.
isWebsocket() is documented as "Lock held on entry" but is called here without c.mu (the lock is released before negotiateLeafCompression is invoked). In practice this is safe since c.ws is set once at connection creation and never mutated, but it violates the stated locking contract. Consider either acquiring the lock first, or simply checking c.ws != nil directly (inlining the check without the locking requirement).
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3dd37dc7f8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if c.isWebsocket() { | ||
| c.mu.Lock() | ||
| c.leaf.compression = CompressionOff | ||
| c.mu.Unlock() | ||
| return false, nil |
There was a problem hiding this comment.
Preserve leaf compression when WS per-message deflate is off
This unconditional c.isWebsocket() fast-path disables leafnode compression for all WebSocket leaf links, but WS compression is only negotiated when the remote explicitly asks for ws_compression (server/leafnode.go:3277-3328) and the accept side has websocket.compression enabled (server/websocket.go:840-843; server/opts.go:590-593). Leafnode compression still defaults to s2_auto for both listeners and remotes (server/opts.go:5915-5937), so a previously supported setup like url: "ws://..." with compression: s2_fast but no WS compression now becomes completely uncompressed. That is a real regression for existing WS leaf deployments that relied on leaf compression without per-message deflate.
Useful? React with 👍 / 👎.
| } | ||
|
|
||
| func (s *Server) negotiateLeafCompression(c *client, didSolicit bool, infoCompression string, co *CompressionOpts) (bool, error) { | ||
| // WebSockets already have compression available so shouldn't negotiate |
There was a problem hiding this comment.
You should lock before c.isWebsocket() although I do believe that it is immutable. But, as also pointed out by codex, it is not necessary that web socket connection uses their own compression (it can be disabled or negotiated as off). So I wonder, should it be instead more something like:
c.mu.Lock()
if c.isWebsocket() && c.ws.compress {
c.leaf.compression = CompressionOff
c.mu.Unlock()
return false, nil
}
c.mu.Unlock()
| websocket { | ||
| listen: "127.0.0.1:-1" | ||
| no_tls: true | ||
| } |
There was a problem hiding this comment.
If you accept the changes in negotiateLeafCompression(), then you would likely need a multiple-case test where you try with compression: true here and in the remote ws_compression: true and then verify that there is no s2 compression in that case. However, if either one is not set (or set to false), then s2 compression should be used.
WebSockets already have compression, so this would be wasteful and likely counter-productive to do so twice.
Signed-off-by: Neil Twigg neil@nats.io