]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Perform sanity checks on request.body only if allow_nonstandard_methods is True.... 1531/head
authorStefan Tjarks <stefan@demonware.net>
Mon, 28 Sep 2015 21:58:15 +0000 (14:58 -0700)
committerStefan Tjarks <stefan@demonware.net>
Thu, 1 Oct 2015 15:48:17 +0000 (08:48 -0700)
tornado/curl_httpclient.py
tornado/test/curl_httpclient_test.py
tornado/test/httpclient_test.py

index 9c9481688ae5c237af5e90a1231c7718ab67f1e4..baa616ba0646083069d5d07877f706d0c0a543dc 100644 (file)
@@ -389,15 +389,22 @@ class CurlAsyncHTTPClient(AsyncHTTPClient):
 
         # Handle curl's cryptic options for every individual HTTP method
         if request.method == "GET":
+            # Even with `allow_nonstandard_methods` we disallow GET with a
+            # body. While the spec doesn't forbid clients from sending a body,
+            # it arguably disallows the server from doing anything with them.
             if request.body is not None:
                 raise ValueError('Body must be None for GET request')
-        elif request.method in ("POST", "PUT") or request.body:
-            if request.body is None:
+        if request.method in ("POST", "PUT") or request.body:
+            # Fail in case POST or PUT method has no body, unless the user has
+            # opted out of sanity checks with allow_nonstandard_methods.
+            if request.body is not None:
+                request_buffer = BytesIO(utf8(request.body))
+            elif not request.allow_nonstandard_methods:
                 raise ValueError(
-                    'Body must not be None for "%s" request'
-                    % request.method)
-
-            request_buffer = BytesIO(utf8(request.body))
+                    'Body must not be None for method %s (unless '
+                    'allow_nonstandard_methods is true)' % request.method)
+            else:
+                request_buffer = BytesIO()
 
             def ioctl(cmd):
                 if cmd == curl.IOCMD_RESTARTREAD:
@@ -405,10 +412,10 @@ class CurlAsyncHTTPClient(AsyncHTTPClient):
             curl.setopt(pycurl.READFUNCTION, request_buffer.read)
             curl.setopt(pycurl.IOCTLFUNCTION, ioctl)
             if request.method == "POST":
-                curl.setopt(pycurl.POSTFIELDSIZE, len(request.body))
+                curl.setopt(pycurl.POSTFIELDSIZE, len(request.body or ''))
             else:
                 curl.setopt(pycurl.UPLOAD, True)
-                curl.setopt(pycurl.INFILESIZE, len(request.body))
+                curl.setopt(pycurl.INFILESIZE, len(request.body or ''))
 
         if request.auth_username is not None:
             userpwd = "%s:%s" % (request.auth_username, request.auth_password or '')
index 3ac21f4d7260be0f4927695e61580a7c6c628118..d06a7bd2ad93b2ecd83340a2f2f8d23b3fc4c990 100644 (file)
@@ -121,3 +121,4 @@ class CurlHTTPClientTestCase(AsyncHTTPTestCase):
     def test_fail_custom_reason(self):
         response = self.fetch('/custom_fail_reason')
         self.assertEqual(str(response.error), "HTTP 400: Custom reason")
+
index 3c6d4c6b991c9942ef0639fb29378333bc3b8ca7..dcf6decb10c4ba481b5fb25a9c66e5405186a983 100644 (file)
@@ -483,6 +483,24 @@ X-XSS-Protection: 1;
 
         self.assertTrue('must not be None' in str(context.exception))
 
+    @gen_test
+    def test_ignore_body_sanity_checks_when_allow_nonstandard_methods(self):
+        all_methods_url = self.get_url('/all_methods')
+        for method in ('POST', 'PUT'):
+            response = yield self.http_client.fetch(
+                all_methods_url, method=method, body=None,
+                allow_nonstandard_methods=True)
+            self.assertEqual(response.code, 200)
+            self.assertIsNone(response.request.body)
+
+        # Don't test for GET with a body. Curl client does not allow it.
+        for method in ('PATCH', 'DELETE', 'OPTIONS'):
+            response = yield self.http_client.fetch(
+                all_methods_url, method=method, body=utf8(method),
+                allow_nonstandard_methods=True)
+            self.assertEqual(response.code, 200)
+            self.assertEqual(response.body, utf8(method))
+
     # This test causes odd failures with the combination of
     # curl_httpclient (at least with the version of libcurl available
     # on ubuntu 12.04), TwistedIOLoop, and epoll.  For POST (but not PUT),