Skip to content

Commit

Permalink
Don't guess encoding for xsendfile, only content type
Browse files Browse the repository at this point in the history
mod_xsendfile intentionally drops the Content-Encoding header[0] when
responding to a request, but mimetypes.guess_type returns a tuple of
('Content-Type', 'Content-Encoding'). We were already ignoring the
encoding component of this tuple, so if mimetypes.guess_type does guess
that a non-None encoding value should be returned, all x_send would use
was the type component, resulting in the incorrect type being used in
the response.

For example: By default, mimetypes.guess_type returns ('text/xml',
'gzip') for a file name like 'metadata.xml.gz', so xsendfile's response
incorrectly responds with the 'text/xml' Content-Type header. This
change makes mimetypes return ('application/gzip', None) instead,
hopefully resulting in a happy client.

[0]: https://tn123.org/mod_xsendfile -- search for "Content-Encoding"

closes #1781
https://pulp.plan.io/issues/1781
  • Loading branch information
Sean Myers committed Jan 25, 2017
1 parent 261d4ef commit b7ed20b
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 1 deletion.
7 changes: 6 additions & 1 deletion server/pulp/server/content/web/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@

SAFE_STORAGE_SUBDIRS = ('published', 'content', 'static')

# xsendfile doesn't use Content-Encoding, so create a mimetypes instance that has no encodings
# to ensure it only ever returns Content-Type guesses without the Content-Encoding component
mimetypes_noencoding = mimetypes.MimeTypes()
mimetypes_noencoding.encodings_map.clear()


class ContentView(View):
"""
Expand Down Expand Up @@ -76,7 +81,7 @@ def x_send(path):
:rtype: django.http.HttpResponse
"""
if os.access(path, os.R_OK):
content_type = mimetypes.guess_type(path)[0]
content_type = mimetypes_noencoding.guess_type(path)[0]
# If the content type can't be detected by mimetypes, send it as arbitrary
# binary data. See https://tools.ietf.org/html/rfc2046#section-4.5.1 for
# more information.
Expand Down
11 changes: 11 additions & 0 deletions server/test/unit/server/content/web/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@ def test_x_send_mime_type(self, access):
self.assertEqual(reply['X-SENDFILE'], path)
self.assertEqual(reply['Content-Type'], 'application/x-rpm')

@patch('os.access')
def test_x_send_mime_type_noencoding(self, access):
path = '/my/path.xml.gz'
access.return_value = True
reply = ContentView.x_send(path)
access.assert_called_once_with(path, os.R_OK)
self.assertEqual(reply['X-SENDFILE'], path)
# If the normal mimetypes module was used, this would be 'text/xml' instead.
# Most OSes return the 'gzip' version, but some (el6) return 'x-gzip'. Either is fine.
self.assertTrue(reply['Content-Type'] in ('application/gzip', 'application/x-gzip'))

@patch('os.access')
@patch(MODULE + '.HttpResponseForbidden')
def test_x_send_cannot_read(self, forbidden, access):
Expand Down

0 comments on commit b7ed20b

Please sign in to comment.