Skip to content

Commit

Permalink
Content disposition with semicolon in filename #917
Browse files Browse the repository at this point in the history
  • Loading branch information
fafhrd91 committed Mar 21, 2017
1 parent 73a6584 commit 198ff33
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Changes
2.1.0 (2017-xx-xx)
------------------

- Content disposition with semicolon in filename #917


2.0.0 (2017-03-20)
Expand Down
20 changes: 18 additions & 2 deletions aiohttp/multipart.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class BadContentDispositionParam(RuntimeWarning):


def parse_content_disposition(header):

def is_token(string):
return string and TOKEN >= set(string)

Expand Down Expand Up @@ -63,7 +64,9 @@ def unescape(text, *, chars=''.join(map(re.escape, CHAR))):
return None, {}

params = {}
for item in parts:
while parts:
item = parts.pop(0)

if '=' not in item:
warnings.warn(BadContentDispositionHeader(header))
return None, {}
Expand Down Expand Up @@ -102,9 +105,22 @@ def unescape(text, *, chars=''.join(map(re.escape, CHAR))):
continue

else:
failed = True
if is_quoted(value):
failed = False
value = unescape(value[1:-1].lstrip('\\/'))
elif not is_token(value):
elif is_token(value):
failed = False
elif parts:
# maybe just ; in filename, in any case this is just
# one case fix, for proper fix we need to redesign parser
_value = '%s;%s' % (value, parts[0])
if is_quoted(_value):
parts.pop(0)
value = unescape(_value[1:-1].lstrip('\\/'))
failed = False

if failed:
warnings.warn(BadContentDispositionHeader(header))
return None, {}

Expand Down
7 changes: 7 additions & 0 deletions tests/test_multipart.py
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,13 @@ def test_inlonlyquoted(self):
self.assertEqual(None, disptype)
self.assertEqual({}, params)

def test_semicolon(self):
disptype, params = parse_content_disposition(
'form-data; name="data"; filename="file ; name.mp4"')
self.assertEqual(disptype, 'form-data')
self.assertEqual(
params, {'name': 'data', 'filename': 'file ; name.mp4'})

def test_inlwithasciifilename(self):
disptype, params = parse_content_disposition(
'inline; filename="foo.html"')
Expand Down

0 comments on commit 198ff33

Please sign in to comment.