Skip to content

feat(server): add opt-in HTTP gzip and WebSocket permessage-deflate compression#934

Open
efiten wants to merge 2 commits intoKpa-clawbot:masterfrom
efiten:feat/opt-in-compression
Open

feat(server): add opt-in HTTP gzip and WebSocket permessage-deflate compression#934
efiten wants to merge 2 commits intoKpa-clawbot:masterfrom
efiten:feat/opt-in-compression

Conversation

@efiten
Copy link
Copy Markdown
Contributor

@efiten efiten commented Apr 30, 2026

Summary

  • Adds "compression": {"gzip": true, "websocket": true} config option (both false by default — no behavior change)
  • HTTP gzip middleware wraps the entire router; skips WebSocket upgrade requests and clients without Accept-Encoding: gzip
  • WebSocket permessage-deflate enabled via hub.upgrader.EnableCompression when websocket: true
  • CompressionConfig struct and GZipEnabled() / WSCompressionEnabled() helpers on Config
  • Hub.upgrader moved from package-level var to struct field so tests using NewHub() don't need changes

Why opt-in / off by default

Operators behind a reverse proxy that already compresses (nginx, Caddy with encode gzip) should leave this off to avoid double-compression. Only enable when the proxy does not compress.

Test plan

  • TestCompressionConfigDefaults — both helpers return false when Compression is nil
  • TestCompressionConfigExplicitFalse — both helpers return false when set to false
  • TestCompressionConfigEnabled — both helpers return true when set to true
  • TestGZipMiddlewareCompresses — response body is valid gzip, headers set correctly
  • TestGZipMiddlewareSkipsNoAcceptEncoding — passthrough when client doesn't send Accept-Encoding: gzip
  • TestGZipMiddlewareSkipsWebSocket — WebSocket upgrades are never gzip-wrapped

All 6 tests pass (go test ./... in cmd/server).

🤖 Generated with Claude Code

efiten and others added 2 commits April 30, 2026 16:37
Adds a `compression` config block (disabled by default) to let operators
enable HTTP gzip and WebSocket permessage-deflate when sitting behind a
reverse proxy that does not already compress upstream responses.

  "compression": { "gzip": true, "websocket": true }

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
page.$() captures an element handle at query time. When the nodes page
WebSocket auto-refresh fires between the querySelector and the .click()
call, the table is re-rendered and the element is detached, causing
"Element is not attached to the DOM".

Replace both occurrences with page.click(selector), which re-queries
the DOM at click time and retries until the element is stable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

1 participant