-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow gzip compression in high-level server response interface #403
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
__all__ = ('Request', 'StreamResponse', 'Response') | ||
__all__ = ('ContentCoding', 'Request', 'StreamResponse', 'Response') | ||
|
||
import asyncio | ||
import binascii | ||
|
@@ -12,6 +12,11 @@ | |
import time | ||
import warnings | ||
|
||
try: | ||
import enum | ||
except ImportError: | ||
from flufl import enum | ||
|
||
from email.utils import parsedate | ||
from types import MappingProxyType | ||
from urllib.parse import urlsplit, parse_qsl, unquote | ||
|
@@ -72,6 +77,16 @@ def content_length(self, _CONTENT_LENGTH=hdrs.CONTENT_LENGTH): | |
FileField = collections.namedtuple('Field', 'name filename file content_type') | ||
|
||
|
||
class ContentCoding(enum.Enum): | ||
# The content codings that we have support for. | ||
# | ||
# Additional registered codings are listed at: | ||
# https://www.iana.org/assignments/http-parameters/http-parameters.xhtml#content-coding | ||
deflate = 'deflate' | ||
gzip = 'gzip' | ||
identity = 'identity' | ||
|
||
|
||
############################################################ | ||
# HTTP Request | ||
############################################################ | ||
|
@@ -436,8 +451,12 @@ def enable_chunked_encoding(self, chunk_size=None): | |
self._chunked = True | ||
self._chunk_size = chunk_size | ||
|
||
def enable_compression(self, force=False): | ||
"""Enables response compression with `deflate` encoding.""" | ||
def enable_compression(self, force=None): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest not change function signature without strict requirement. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder why there is no way to specify exact encoding to use? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea. |
||
"""Enables response compression encoding.""" | ||
# Backwards compatibility for when force was a bool <0.17. | ||
if type(force) == bool: | ||
force = ContentCoding.deflate if force else ContentCoding.identity | ||
|
||
self._compression = True | ||
self._compression_force = force | ||
|
||
|
@@ -577,6 +596,22 @@ def _start_pre_check(self, request): | |
else: | ||
return None | ||
|
||
def _start_compression(self, request): | ||
def start(coding): | ||
if coding != ContentCoding.identity: | ||
self.headers[hdrs.CONTENT_ENCODING] = coding.value | ||
self._resp_impl.add_compression_filter(coding.value) | ||
|
||
if self._compression_force: | ||
start(self._compression_force) | ||
else: | ||
accept_encoding = request.headers.get( | ||
hdrs.ACCEPT_ENCODING, '').lower() | ||
for coding in ContentCoding: | ||
if coding.value in accept_encoding: | ||
start(coding) | ||
return | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If encoding is not acceptable, HTTP 406 must be returned. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that if we want to do this we need complete support for this header, in particular the handling of * when its alone, which is easy, and when its paired with other codings, which is a little more difficult. I was kind of hoping to avoid this work, unless it must be done as part of this patch. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we added full support for content negotiation on this header we would also want to support q values. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm ok for leaving it to next PR. Please file an issue than. |
||
|
||
def start(self, request): | ||
resp_impl = self._start_pre_check(request) | ||
if resp_impl is not None: | ||
|
@@ -598,10 +633,7 @@ def start(self, request): | |
self._copy_cookies() | ||
|
||
if self._compression: | ||
if (self._compression_force or | ||
'deflate' in request.headers.get( | ||
hdrs.ACCEPT_ENCODING, '')): | ||
resp_impl.add_compression_filter() | ||
self._start_compression(request) | ||
|
||
if self._chunked: | ||
resp_impl.enable_chunked_encoding() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add
identity
coding for no compression.