Skip to content

PerMessageDeflateExtension *_no_context_takeover negotiation is faulty, leading to mismatch #1496

Closed

Description

@robert-s-ubi

Describe the bug
The PerMessageDeflateExtension#getProvidedExtensionAsClient() method unconditionally includes client_no_context_takeover and server_no_context_takeover in the extensions to send to the server, ignoring the clientNoContextTakeover and serverNoContextTakeover configuration variables.

The acceptProvidedExtensionAsServer() on the server will thus ALWAYS set its clientNoContextTakeover variable to true, but the acceptProvidedExtensionAsClient() does NOT update its clientNoContextTakeover configuration variable upon receiving this, leading to a mismatch.

As a result, the second compressed response the client receives from the server yields an exception:

org.java_websocket.exceptions.InvalidDataException: invalid distance too far back
at org.java_websocket.extensions.permessage_deflate.PerMessageDeflateExtension.decodeFrame(PerMessageDeflateExtension.java:193)
at org.java_websocket.drafts.Draft_6455.translateSingleFrame(Draft_6455.java:589)

To Reproduce
Steps to reproduce the behavior:

  1. Set up WebSocketClient and WebSocketServer with the PerMessageDelateExtension
  2. Connect them
  3. Send messages back and forth
  4. The client side will bail out at the second message it receives from the server

Example application to reproduce the issue
https://github.com/ChargeTimeEU/Java-OCA-OCPP was recently enhanced with WebSocket compression support, but it's broken due to this bug.

Expected behavior
Behavior must be as follows:

  1. getProvidedExtensionsAsClient() must add the extensions following the clientNoContextTakeover and serverNoContextTakeover configuration variables (i.e. leave them out if false).
  2. acceptProvidedExtensionsAsServer() must enable the clientNoContextTakeover and/or serverNoContextTakeover if their corresponding extensions are received, effectively ORing them with the locally configured settings.
  3. getProviderExtensionsAsServer() must add the extensions following the (potentially updated) clientNoContextTakeover and serverNoContextTakeover configuration variables (i.e. leave them out if false).
  4. acceptProvidedExtensionsAsClient() must enable the clientNoContextTakeover and/or serverNoContextTakeover if their corresponding extensions are received, effectively ORing them with the locally configured settings.

This ensures these configuration settings are always properly synchronized on both ends, and allows operation with context takeover on both ends (both configuration variables set to false on both ends), which maximizes the compression efficiency.

Activity

  1. robert-s-ubi commented on Dec 19, 2025

    @robert-s-ubi
    ContributorAuthor

    The logic to reset the deflater and inflater is also bugged: You cannot directly infer which to reset by the two configuration variables. Instead, it is swapped on client and server. So if one no_context_takeover is set, it must cause one side to reset the inflater, and the other to reset the deflater.

    Right now both sides will reset the same of these two for one of these variables, that's why it blows up in case both are not the same. I.e. the code works for true/true and false/false, but not for true/false or false/true combinations of clientNoContextTakeover and serverNoContextTakeover.

  2. robert-s-ubi commented on Dec 19, 2025

    @robert-s-ubi
    ContributorAuthor

    I have submitted PR #1497 to fix this. Note that the last verifier run failed, presumably because the server ran out of sockets. Unfortunately, I cannot find a button to rerun the verifier.

  3. robert-s-ubi commented on Dec 23, 2025

    @robert-s-ubi
    ContributorAuthor

    It appears this extension has even more issues, such as not keeping track of whether the current message is to be compressed/decompressed (it might choose not to compress the first fragment, and then start compressing further fragments, which is not allowed). It also does not produce/handle all examples from RFC 7692 chapter 7.2.3 correctly. And the "rogue" inflater reset in line 181 (with the bogus "most likely" explanation) also breaks the context takeover, as it erases the context.

    The above PR fixes the worst bug, but there are many more. I'd advise not to use this extension in this state.

  4. robert-s-ubi commented on Dec 25, 2025

    @robert-s-ubi
    ContributorAuthor

    I have submitted a new PR #1498, which adds a complete reimplementation of the RFC 7962 extension, written for full compliance with the RFC as well as full API compatibility with the existing extension. The new PR supersedes the old PR #1497.

  5. added this to the Release 1.6.1 milestone on Jan 9, 2026
  6. marci4 commented on Jan 13, 2026

    @marci4
    Collaborator

    Fixed #1498

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions