Extensions
**********

The WebSocket protocol supports extensions.

At the time of writing, there's only one registered extension,
WebSocket Per-Message Deflate, specified in **RFC 7692**.


Per-Message Deflate
===================

"serve()" and "connect()" enable the Per-Message Deflate extension by
default. You can disable this with "compression=None".

You can also configure the Per-Message Deflate extension explicitly if
you want to customize its parameters.

Here's an example on the server side:

   import websockets
   from websockets.extensions import permessage_deflate

   websockets.serve(
       ...,
       extensions=[
           permessage_deflate.ServerPerMessageDeflateFactory(
               server_max_window_bits=11,
               client_max_window_bits=11,
               compress_settings={'memLevel': 4},
           ),
       ],
   )

Here's an example on the client side:

   import websockets
   from websockets.extensions import permessage_deflate

   websockets.connect(
       ...,
       extensions=[
           permessage_deflate.ClientPerMessageDeflateFactory(
               server_max_window_bits=11,
               client_max_window_bits=11,
               compress_settings={'memLevel': 4},
           ),
       ],
   )

Refer to the API documentation of "ServerPerMessageDeflateFactory" and
"ClientPerMessageDeflateFactory" for details.


Writing an extension
====================

During the opening handshake, WebSocket clients and servers negotiate
which extensions will be used with which parameters. Then each frame
is processed by extensions before it's sent and after it's received.

As a consequence writing an extension requires implementing several
classes:

1. Extension Factory: it negotiates parameters and instantiates the
   extension. Clients and servers require separate extension factories
   with distinct APIs.

2. Extension: it decodes incoming frames and encodes outgoing
   frames. If the extension is symmetrical, clients and servers can
   use the same class.

"websockets" provides abstract base classes for extension factories
and extensions.

class websockets.extensions.base.ServerExtensionFactory

   Abstract class for server-side extension factories.

   name

      Extension identifier.

      Return type:
         "str"

   process_request_params(params, accepted_extensions)

      Process request parameters received from the client.

      To accept the offer, return a 2-uple containing:

      * response parameters: a list of "(name, value)" pairs

      * an extension: an instance of a subclass of "Extension"

      Parameters:
         * **params** ("Sequence"["Tuple"["str",
           "Optional"["str"]]]) -- list of "(name, value)" pairs.

         * **accepted_extensions** ("Sequence"["Extension"]) -- list
           of previously accepted extensions.

      Raises:
         **NegotiationError** -- to reject the offer, if parameters
         aren't acceptable

      Return type:
         "Tuple"["List"["Tuple"["str", "Optional"["str"]]],
         "Extension"]

class websockets.extensions.base.ClientExtensionFactory

   Abstract class for client-side extension factories.

   get_request_params()

      Build request parameters.

      Return a list of "(name, value)" pairs.

      Return type:
         "List"["Tuple"["str", "Optional"["str"]]]

   name

      Extension identifier.

      Return type:
         "str"

   process_response_params(params, accepted_extensions)

      Process response parameters received from the server.

      Parameters:
         * **params** ("Sequence"["Tuple"["str",
           "Optional"["str"]]]) -- list of "(name, value)" pairs.

         * **accepted_extensions** ("Sequence"["Extension"]) -- list
           of previously accepted extensions.

      Raises:
         **NegotiationError** -- if parameters aren't acceptable

      Return type:
         "Extension"

class websockets.extensions.base.Extension

   Abstract class for extensions.

   decode(frame, *, max_size=None)

      Decode an incoming frame.

      Parameters:
         * **frame** ("Frame") -- incoming frame

         * **max_size** ("Optional"["int"]) -- maximum payload size
           in bytes

      Return type:
         "Frame"

   encode(frame)

      Encode an outgoing frame.

      Parameters:
         **frame** ("Frame") -- outgoing frame

      Return type:
         "Frame"

   name

      Extension identifier.

      Return type:
         "str"
