From ed06c68b7b622cf43dc09b0e475ad6c978ec3de4 Mon Sep 17 00:00:00 2001 From: David Glick Date: Wed, 9 Nov 2016 23:31:24 -0800 Subject: [PATCH 1/2] Avoid setting Content-Encoding header for static view responses. This was causing clients to decode the content of gzipped files when downloading them. We discussed this on IRC and @mmerickel pointed out that it may be a goal in some cases to serve gzipped precompiled assets (i.e. CSS/Javascript) with this header. But that's a new feature that would require thought about how to specify which files to serve that way. And it can already be implemented for a project using a tween. This just aims to fix the existing use case of serving files for download. --- CHANGES.txt | 5 +++++ pyramid/response.py | 25 +++++++++++++++---------- pyramid/static.py | 12 ++++++++++-- pyramid/tests/test_static.py | 4 ++-- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 434557f89f..e6a0157367 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -97,6 +97,11 @@ Bug Fixes from previous orders have executed. See https://github.com/Pylons/pyramid/pull/2757 +- Fix static view to avoid setting the ``Content-Encoding`` response header + to an encoding guessed using Python's ``mimetypes`` module. + This was causing clients to decode the content of gzipped files + when downloading them. + Deprecations ------------ diff --git a/pyramid/response.py b/pyramid/response.py index 892e5dfff7..1d9daae7de 100644 --- a/pyramid/response.py +++ b/pyramid/response.py @@ -54,16 +54,7 @@ class FileResponse(Response): def __init__(self, path, request=None, cache_max_age=None, content_type=None, content_encoding=None): if content_type is None: - content_type, content_encoding = mimetypes.guess_type( - path, - strict=False - ) - if content_type is None: - content_type = 'application/octet-stream' - # str-ifying content_type is a workaround for a bug in Python 2.7.7 - # on Windows where mimetypes.guess_type returns unicode for the - # content_type. - content_type = str(content_type) + content_type, content_encoding = _guess_type(path) super(FileResponse, self).__init__( conditional_response=True, content_type=content_type, @@ -180,3 +171,17 @@ def _get_response_factory(registry): ) return response_factory + + +def _guess_type(path): + content_type, content_encoding = mimetypes.guess_type( + path, + strict=False + ) + if content_type is None: + content_type = 'application/octet-stream' + # str-ifying content_type is a workaround for a bug in Python 2.7.7 + # on Windows where mimetypes.guess_type returns unicode for the + # content_type. + content_type = str(content_type) + return content_type, content_encoding diff --git a/pyramid/static.py b/pyramid/static.py index 0965be95c7..31e500e704 100644 --- a/pyramid/static.py +++ b/pyramid/static.py @@ -32,7 +32,12 @@ ) from pyramid.path import caller_package -from pyramid.response import FileResponse + +from pyramid.response import ( + _guess_type, + FileResponse, +) + from pyramid.traversal import traversal_path_info slash = text_('/') @@ -134,7 +139,10 @@ def __call__(self, context, request): if not exists(filepath): raise HTTPNotFound(request.url) - return FileResponse(filepath, request, self.cache_max_age) + content_type, content_encoding = _guess_type(filepath) + return FileResponse( + filepath, request, self.cache_max_age, + content_type, content_encoding=None) def add_slash_redirect(self, request): url = request.path_url + '/' diff --git a/pyramid/tests/test_static.py b/pyramid/tests/test_static.py index 2ca86bc441..2b200d72b3 100644 --- a/pyramid/tests/test_static.py +++ b/pyramid/tests/test_static.py @@ -186,14 +186,14 @@ def test_not_found(self): from pyramid.httpexceptions import HTTPNotFound self.assertRaises(HTTPNotFound, inst, context, request) - def test_resource_with_content_encoding(self): + def test_gz_resource_no_content_encoding(self): inst = self._makeOne('pyramid.tests:fixtures/static') request = self._makeRequest({'PATH_INFO':'/arcs.svg.tgz'}) context = DummyContext() response = inst(context, request) self.assertEqual(response.status, '200 OK') self.assertEqual(response.content_type, 'application/x-tar') - self.assertEqual(response.content_encoding, 'gzip') + self.assertEqual(response.content_encoding, None) response.app_iter.close() def test_resource_no_content_encoding(self): From 734f241a961b6b1e4b2a43c0c4b5a4d972b65b80 Mon Sep 17 00:00:00 2001 From: David Glick Date: Thu, 10 Nov 2016 08:42:39 -0800 Subject: [PATCH 2/2] add link to PR --- CHANGES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.txt b/CHANGES.txt index e6a0157367..1d69471f1e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -101,6 +101,7 @@ Bug Fixes to an encoding guessed using Python's ``mimetypes`` module. This was causing clients to decode the content of gzipped files when downloading them. + See https://github.com/Pylons/pyramid/pull/2810 Deprecations ------------