Skip to content

Add server-side WebSocket compression#1114

Open
mkurz wants to merge 2 commits into
apache:mainfrom
mkurz:websocket-compression
Open

Add server-side WebSocket compression#1114
mkurz wants to merge 2 commits into
apache:mainfrom
mkurz:websocket-compression

Conversation

@mkurz

@mkurz mkurz commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

What changed

Adds server-side support for RFC 7692 permessage-deflate WebSocket compression.

Compression is negotiated during the WebSocket handshake when the client offers permessage-deflate in Sec-WebSocket-Extensions. It is enabled by default and can be disabled globally through configuration.

Also adds an API option to decline negotiated compression for a single accepted WebSocket upgrade.

Details

This PR adds:

  • permessage-deflate negotiation for server-side WebSockets
  • inbound compressed message inflation
  • outbound message deflation
  • fragmented compressed message handling
  • context takeover and no-context-takeover negotiation
  • configurable compression level
  • configurable max decompressed allocation
  • configurable preferred client_max_window_bits
  • per-upgrade compression disabling via new WebSocketUpgrade overloads
  • documentation, reference config, release notes, and MiMa filters

Netty comparison

The implementation follows Netty’s permessage-deflate behavior where it makes sense for Pekko HTTP:

  • compressed inbound messages are inflated before they reach the application
  • outbound text/binary messages are compressed when compression was negotiated
  • fragmented compressed messages keep RSV1 only on the first frame
  • control frames can be interleaved with fragmented compressed messages
  • context takeover is retained by default
  • server_no_context_takeover and client_no_context_takeover can be negotiated
  • client_max_window_bits can be negotiated
  • decompressed output is bounded through max-allocation

One deliberate difference is zlib implementation scope. Netty also uses the JDK Deflater and Inflater APIs for the default zlib settings, and only switches to JZlib when non-default zlib windowBits or memLevel support is needed. Pekko HTTP currently uses only the JDK Deflater and Inflater APIs, like Tomcat and Jetty. The JDK API does not expose zlib windowBits or memLevel, so Pekko HTTP does not accept server_max_window_bits values below 15 and does not provide server window-size or memory-level settings.

Clients may still request client_max_window_bits; when they do, Pekko HTTP can include the configured preferred-client-window-size in the handshake response to ask the client to use that window size for client-to-server messages.

Security notes

WebSocket compression can increase CPU and memory usage.

The default context takeover settings match common server defaults and favor compression efficiency. Applications that need a more conservative setup can configure no-context-takeover behavior or disable compression globally/per accepted WebSocket.

max-allocation limits decompressed message size. If the limit is exceeded while inflating a compressed message, Pekko HTTP closes the connection with a WebSocket protocol error.

Testing

Ran:

sbt "http-core / Test / testOnly org.apache.pekko.http.impl.engine.ws.WebSocketServerSpec"
sbt +mimaReportBinaryIssues

Also verified Play Framework integration against the locally published Pekko HTTP artifact:
(This is a WIP pull request for Play which I will submit tomorrow - I will you ping you then)

sbt -Dpekko.http.version=<local-version> \
  "Play-Integration-Test / Test / testOnly play.it.http.websocket.PekkoHttpWebSocketCompressionSpec"

sbt -Dpekko.http.version=<local-version> \
  "Play-Integration-Test / Test / testOnly play.it.http.websocket.PekkoHttpWebSocketSpec"

References

mkurz added 2 commits July 1, 2026 00:19
* Negotiate RFC 7692 permessage-deflate for server-side WebSockets.

* Add compression settings, documentation, release notes, and MiMa filters.

* Cover negotiation, compression, fragmentation, context takeover, max allocation, and low-level frame handling.
* Add WebSocketUpgrade overloads that accept a compressionEnabled flag.

* Wire accepted WebSockets to decline negotiated compression per request.

* Document and test per-upgrade compression disabling.
@@ -0,0 +1,341 @@
/*

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the source header should be the standard Apache header - see https://github.com/apache/pekko/blob/main/CONTRIBUTING.md#pull-request-requirements - unless this code is largely a copy/paste of 3rd party code (in which case, the existing source header in that code would be used)

* use the given handlerFlow to handle WebSocket messages from the client. The given subprotocol must be one
* of the ones offered by the client.
*
* The compressionEnabled flag allows declining negotiated WebSocket compression for this accepted WebSocket.

@pjfanning pjfanning Jun 30, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add @since 2.0.0 on new public API methods?

* Dependency versions have been updated
* Jackson3 is supported in a new pekko-http-jackson3 lib
* Changed Java DSL methods that return Scala Durations to return Java Durations ([PR788](https://github.com/apache/pekko-http/pull/788))
* Server-side WebSocket connections can now negotiate RFC 7692 `permessage-deflate` compression when requested by the client.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2.0.0-M1 is already released. Just revert this and we will form 2.0.0-M2 release notes when that release is ready, hopefully in a month or 2.

@pjfanning pjfanning added this to the 2.0.0-M2 milestone Jun 30, 2026
@He-Pin

He-Pin commented Jul 1, 2026

Copy link
Copy Markdown
Member

I see netty have many compression support, should we do that too?

# Whether the server should support WebSocket compression using the RFC 7692
# permessage-deflate extension. Compression is negotiated during the
# WebSocket handshake and is only used when the client requests it.
enabled = true

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we do adaptive compression?

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.

Please add support for WebSocket compression

3 participants