]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Catch exceptions from parse_qs_bytes in POST bodies and log them.
authorBen Darnell <ben@bendarnell.com>
Wed, 6 Nov 2013 19:16:01 +0000 (14:16 -0500)
committerBen Darnell <ben@bendarnell.com>
Wed, 6 Nov 2013 19:16:01 +0000 (14:16 -0500)
This is consistent with error handling for multipart/form-data.
parse_qs is very liberal, but the conversion to unicode
on python 3 may fail.  This is most common for binary data sent from
clients where x-www-form-urlencoded is the default, which is not
actually intended to be interpreted as arguments.

Closes #921.

tornado/httputil.py
tornado/test/httpserver_test.py

index 3e7337d99818dc9c6b3145452374a4fe2f5ec754..2575bc56849df87f6e92f7e6ba9c401e7cab731b 100644 (file)
@@ -320,7 +320,11 @@ def parse_body_arguments(content_type, body, arguments, files):
     with the parsed contents.
     """
     if content_type.startswith("application/x-www-form-urlencoded"):
-        uri_arguments = parse_qs_bytes(native_str(body), keep_blank_values=True)
+        try:
+            uri_arguments = parse_qs_bytes(native_str(body), keep_blank_values=True)
+        except Exception as e:
+            gen_log.warning('Invalid x-www-form-urlencoded body: %s', e)
+            uri_arguments = {}
         for name, values in uri_arguments.items():
             if values:
                 arguments.setdefault(name, []).extend(values)
index 1d45ca6042a02c6823d5601ed4c87e72d968da6e..47607d4bc6b40b8e7f7b5b7b4913a20f17c4493f 100644 (file)
@@ -344,6 +344,21 @@ class HTTPServerTest(AsyncHTTPTestCase):
         self.assertEqual(200, response.code)
         self.assertEqual(json_decode(response.body), {})
 
+    def test_malformed_body(self):
+        # parse_qs is pretty forgiving, but it will fail on python 3
+        # if the data is not utf8.  On python 2 parse_qs will work,
+        # but then the recursive_unicode call in EchoHandler will
+        # fail.
+        if str is bytes_type:
+            return
+        with ExpectLog(gen_log, 'Invalid x-www-form-urlencoded body'):
+            response = self.fetch(
+                '/echo', method="POST",
+                headers={'Content-Type': 'application/x-www-form-urlencoded'},
+                body=b'\xe9')
+        self.assertEqual(200, response.code)
+        self.assertEqual(b'{}', response.body)
+
 
 class HTTPServerRawTest(AsyncHTTPTestCase):
     def get_app(self):