Skip to content

Commit

Permalink
Move make_content_disposition into HTTPResponse module
Browse files Browse the repository at this point in the history
modified:   src/OFS/ObjectManager.py
modified:   src/ZPublisher/HTTPResponse.py
deleted:    src/ZPublisher/http_header_utils.py
modified:   src/ZPublisher/tests/testHTTPResponse.py
deleted:    src/ZPublisher/tests/test_http_header_utils.py
  • Loading branch information
jugmac00 committed Sep 29, 2020
1 parent 8381276 commit 8fed81c
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 83 deletions.
2 changes: 1 addition & 1 deletion src/OFS/ObjectManager.py
Expand Up @@ -61,7 +61,7 @@
from zope.interface.interfaces import ComponentLookupError
from zope.lifecycleevent import ObjectAddedEvent
from zope.lifecycleevent import ObjectRemovedEvent
from ZPublisher.http_header_utils import make_content_disposition
from ZPublisher.HTTPResponse import make_content_disposition


# Constants: __replaceable__ flags:
Expand Down
24 changes: 24 additions & 0 deletions src/ZPublisher/HTTPResponse.py
Expand Up @@ -115,6 +115,30 @@ def build_http_date(when):
WEEKDAYNAME[wd], day, MONTHNAME[month], year, hh, mm, ss)


def make_content_disposition(disposition, file_name):
"""Create HTTP header for downloading a file with a UTF-8 filename.
See this and related answers: https://stackoverflow.com/a/8996249/2173868.
"""
header = f'{disposition}'
try:
file_name.encode('us-ascii')
except UnicodeEncodeError:
# the file cannot be encoded using the `us-ascii` encoding
# which is advocated by RFC 7230 - 7237
#
# a special header has to be crafted
# also see https://tools.ietf.org/html/rfc6266#appendix-D
encoded_file_name = file_name.encode('us-ascii', errors='ignore')
header += f'; filename="{encoded_file_name}"'
quoted_file_name = quote(file_name)
header += f'; filename*=UTF-8\'\'{quoted_file_name}'
return header
else:
header += f'; filename="{file_name}"'
return header


class HTTPBaseResponse(BaseResponse):
""" An object representation of an HTTP response.
Expand Down
39 changes: 0 additions & 39 deletions src/ZPublisher/http_header_utils.py

This file was deleted.

27 changes: 27 additions & 0 deletions src/ZPublisher/tests/testHTTPResponse.py
Expand Up @@ -8,6 +8,7 @@
from zExceptions import NotFound
from zExceptions import ResourceLockedError
from zExceptions import Unauthorized
from ZPublisher.HTTPResponse import make_content_disposition


class HTTPResponseTests(unittest.TestCase):
Expand Down Expand Up @@ -1373,3 +1374,29 @@ def test_exception_500_text(self):
def test_isHTML_not_decodable_bytes(self):
response = self._makeOne()
self.assertFalse(response.isHTML('bïñårÿ'.encode('latin1')))


class MakeDispositionHeaderTests(unittest.TestCase):

def test_ascii(self):
self.assertEqual(
make_content_disposition('inline', 'iq.png'),
'inline; filename="iq.png"')

def test_latin_one(self):
self.assertEqual(
make_content_disposition('inline', 'Dänemark.png'),
'inline; filename="b\'Dnemark.png\'"; filename*=UTF-8\'\'D%C3%A4nemark.png' # noqa: E501
)

def test_unicode(self):
"""HTTP headers need to be latin-1 compatible
In order to offer file downloads which contain unicode file names,
the file name has to be treated in a special way, see
https://stackoverflow.com/questions/1361604 .
"""
self.assertEqual(
make_content_disposition('inline', 'ıq.png'),
'inline; filename="b\'q.png\'"; filename*=UTF-8\'\'%C4%B1q.png'
)
43 changes: 0 additions & 43 deletions src/ZPublisher/tests/test_http_header_utils.py

This file was deleted.

0 comments on commit 8fed81c

Please sign in to comment.