Skip to content

Commit 9fc4fa9

Browse files
authored
Merge c387455 into 6a50939
2 parents 6a50939 + c387455 commit 9fc4fa9

3 files changed

Lines changed: 47 additions & 3 deletions

File tree

README.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,21 @@ should start with a slash, but not end with one; for example::
105105
daphne --root-path=/forum django_project.asgi:application
106106

107107

108+
Permessage compression
109+
----------------------
110+
111+
Daphne supports and by default accepts ``permessage-deflate`` compression
112+
(`permessage-deflate specification <http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression>`_).
113+
Additional ``permessage-bzip2``, ``permessage-snappy`` compressions will be also enabled by default if
114+
``bz2`` and `snappy <https://snappy.math.uic.edu/>`_ python packages are available in daphne environment.
115+
The compression implementation is provided by
116+
`Autobahn|Python <https://github.com/crossbario/autobahn-python>`_ package, see:
117+
`permessage-deflate <https://github.com/crossbario/autobahn-python/blob/master/autobahn/websocket/compress_deflate.py>`_,
118+
`permessage-bzip2 <https://github.com/crossbario/autobahn-python/blob/master/autobahn/websocket/compress_bzip2.py>`_,
119+
`permessage-snappy <https://github.com/crossbario/autobahn-python/blob/master/autobahn/websocket/compress_snappy.py>`_.
120+
121+
122+
108123
Python Support
109124
--------------
110125

daphne/server.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from concurrent.futures import CancelledError
2525
from functools import partial
2626

27+
from autobahn.websocket.compress import PERMESSAGE_COMPRESSION_EXTENSION as EXTENSIONS
2728
from twisted.internet import defer, reactor
2829
from twisted.internet.endpoints import serverFromString
2930
from twisted.logger import STDLibLogObserver, globalLogBeginner
@@ -46,6 +47,11 @@ def __init__(
4647
request_buffer_size=8192,
4748
websocket_timeout=86400,
4849
websocket_connect_timeout=20,
50+
websocket_permessage_compression_extensions=(
51+
"permessage-deflate",
52+
"permessage-bzip2",
53+
"permessage-snappy",
54+
),
4955
ping_interval=20,
5056
ping_timeout=30,
5157
root_path="",
@@ -76,6 +82,9 @@ def __init__(
7682
self.websocket_timeout = websocket_timeout
7783
self.websocket_connect_timeout = websocket_connect_timeout
7884
self.websocket_handshake_timeout = websocket_handshake_timeout
85+
self.websocket_permessage_compression_extensions = (
86+
websocket_permessage_compression_extensions
87+
)
7988
self.application_close_timeout = application_close_timeout
8089
self.root_path = root_path
8190
self.verbosity = verbosity
@@ -97,6 +106,7 @@ def run(self):
97106
autoPingTimeout=self.ping_timeout,
98107
allowNullOrigin=True,
99108
openHandshakeTimeout=self.websocket_handshake_timeout,
109+
perMessageCompressionAccept=self.accept_permessage_compression_extension,
100110
)
101111
if self.verbosity <= 1:
102112
# Redirect the Twisted log to nowhere
@@ -251,6 +261,21 @@ def check_headers_type(message):
251261
)
252262
)
253263

264+
def accept_permessage_compression_extension(self, offers):
265+
"""
266+
Accepts websocket compression extension as required by `autobahn` package.
267+
"""
268+
for offer in offers:
269+
for ext in self.websocket_permessage_compression_extensions:
270+
if ext in EXTENSIONS and isinstance(offer, EXTENSIONS[ext]["Offer"]):
271+
return EXTENSIONS[ext]["OfferAccept"](offer)
272+
elif ext not in EXTENSIONS:
273+
logger.warning(
274+
"Compression extension %s could not be accepted. "
275+
"It is not supported or a dependency is missing.",
276+
ext,
277+
)
278+
254279
### Utility
255280

256281
def application_checker(self):

daphne/ws_protocol.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def handle_reply(self, message):
182182
if "type" not in message:
183183
raise ValueError("Message has no type defined")
184184
if message["type"] == "websocket.accept":
185-
self.serverAccept(message.get("subprotocol", None))
185+
self.serverAccept(message.get("subprotocol", None), message.get("headers", None))
186186
elif message["type"] == "websocket.close":
187187
if self.state == self.STATE_CONNECTING:
188188
self.serverReject()
@@ -214,11 +214,15 @@ def handle_exception(self, exception):
214214
else:
215215
self.sendCloseFrame(code=1011)
216216

217-
def serverAccept(self, subprotocol=None):
217+
def serverAccept(self, subprotocol=None, headers=None):
218218
"""
219219
Called when we get a message saying to accept the connection.
220220
"""
221-
self.handshake_deferred.callback(subprotocol)
221+
if headers is None:
222+
self.handshake_deferred.callback(subprotocol)
223+
else:
224+
headers_dict = {key.decode(): value.decode() for key, value in headers}
225+
self.handshake_deferred.callback((subprotocol, headers_dict))
222226
del self.handshake_deferred
223227
logger.debug("WebSocket %s accepted by application", self.client_addr)
224228

0 commit comments

Comments
 (0)