Repository: pallets/werkzeug

Issue:
request.files: Semicolon in filename truncates following characters
filname:
русс_-{},.ss.»’”›⸃!"#%&',:;?.jpg

request.files misses everything after ":":

```
 <FileStorage: u'"\u0440\u0443\u0441\u0441_-{}[](),.ss.\xbb\u2019\u201d\u203a\u2e03!\\"#%&\',:' ('image/jpeg')>
```

So file now does not have an extension



Discussion:
It might be because `;` is a delimiter for options inside a header value.

Note to self, the code for this is in https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/http.py#L215

Can you paste the headers you are sending?

Firefox 17.0.1

Data from firebug...

Request Headers

```
POST /upload HTTP/1.1
Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-us;q=0.6,en;q=0.4,uk;q=0.2
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive
Referer: http://127.0.0.1:5000/upload
Cookie: csrftoken=9TjPmHMyE5kDtHhumeZobkaTA7XCD8yl; __utma=96992031.474187929.1349787222.1363349980.1363352904.139; __utmz=96992031.1349787222.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); ki_u=f35f1b16-9621-fd3d-634a-8e9691af4b2f; ki_t=1349787223397%3B1362658362445%3B1362658412619%3B15%3B211; sessionaudit=7b16d3ee7c6fa4236dc5229b2cd7a5c8; trac_session=3f9cbbd80161f1562e08b55f; kavyarnya_sid=414a45764407900a738211dc0df5d397; sessionid=dc7d0e8085a1b1a507c1fd3ce60e1560; djdt=hide; education_type=1; session="Q47QJGIXIhulaZvM/WLrJbDiPkk=?_id=UydceGU5XHgxOVx4ODQvTFx4ZWMsXHhjYXM/XHgxZlx4YzlceGJhXHhjYVNceDFmJwpwMQou"
```

Request Headers From Upload Stream:

```
Content-Length  49745
Content-Type    multipart/form-data; boundary=---------------------------18982656315699772871160659570
```

post source:

```
-----------------------------18982656315699772871160659570 Content-Disposition: form-data; name="photo"; filename="adsfasfs235231;sdsd.jpg" Content-Type: image/jpeg 
```

Maybe you need something else?

Ah i see. Will try to work this out.


Resolving patch:
diff --git a/werkzeug/http.py b/werkzeug/http.py
--- a/werkzeug/http.py
+++ b/werkzeug/http.py
@@ -42,7 +42,7 @@
 _etag_re = re.compile(r'([Ww]/)?(?:"(.*?)"|(.*?))(?:\s*,\s*|$)')
 _unsafe_header_chars = set('()<>@,;:\"/[]?={} \t')
 _quoted_string_re = r'"[^"\\]*(?:\\.[^"\\]*)*"'
-_option_header_piece_re = re.compile(r';\s*([^\s;=]+|%s)\s*(?:=\s*([^;]+|%s))?\s*' %
+_option_header_piece_re = re.compile(r';\s*(%s|[^\s;=]+)\s*(?:=\s*(%s|[^;]+))?\s*' %
     (_quoted_string_re, _quoted_string_re))
 
 _entity_headers = frozenset([
diff --git a/werkzeug/testsuite/http.py b/werkzeug/testsuite/http.py
--- a/werkzeug/testsuite/http.py
+++ b/werkzeug/testsuite/http.py
@@ -228,12 +228,18 @@ def test_remove_hop_by_hop_headers(self):
         assert headers2 == datastructures.Headers([('Foo', 'bar')])
 
     def test_parse_options_header(self):
-        assert http.parse_options_header('something; foo="other\"thing"') == \
+        assert http.parse_options_header(r'something; foo="other\"thing"') == \
             ('something', {'foo': 'other"thing'})
-        assert http.parse_options_header('something; foo="other\"thing"; meh=42') == \
+        assert http.parse_options_header(r'something; foo="other\"thing"; meh=42') == \
             ('something', {'foo': 'other"thing', 'meh': '42'})
-        assert http.parse_options_header('something; foo="other\"thing"; meh=42; bleh') == \
+        assert http.parse_options_header(r'something; foo="other\"thing"; meh=42; bleh') == \
             ('something', {'foo': 'other"thing', 'meh': '42', 'bleh': None})
+        assert http.parse_options_header('something; foo="other;thing"; meh=42; bleh') == \
+            ('something', {'foo': 'other;thing', 'meh': '42', 'bleh': None})
+        assert http.parse_options_header('something; foo="otherthing"; meh=; bleh') == \
+            ('something', {'foo': 'otherthing', 'meh': None, 'bleh': None})
+
+
 
     def test_dump_options_header(self):
         assert http.dump_options_header('foo', {'bar': 42}) == \


Test patch: