]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Add PATCH and OPTIONS support by default to curl_httpclient.
authorBen Darnell <ben@bendarnell.com>
Sat, 18 May 2013 20:34:10 +0000 (16:34 -0400)
committerBen Darnell <ben@bendarnell.com>
Sat, 18 May 2013 20:34:52 +0000 (16:34 -0400)
Add some tests to cover all the standard (and non-standard) http methods.

Closes #792.

tornado/curl_httpclient.py
tornado/test/httpclient_test.py
tornado/test/web_test.py

index adc2314fc299d9ce1c967ae7becc53e80f41770a..7d063b7716cca7eb86fc4b6db7487f4765a57a04 100644 (file)
@@ -385,7 +385,7 @@ def _curl_setup_request(curl, request, buffer, headers):
         "PUT": pycurl.UPLOAD,
         "HEAD": pycurl.NOBODY,
     }
-    custom_methods = set(["DELETE"])
+    custom_methods = set(["DELETE", "OPTIONS", "PATCH"])
     for o in curl_options.values():
         curl.setopt(o, False)
     if request.method in curl_options:
index 62645e737a0a409c7d03edeff57f232ef9ec01f1..a513a9f3772e3c5aa284f9bf6715112edb8657ea 100644 (file)
@@ -82,6 +82,13 @@ class ContentLength304Handler(RequestHandler):
         # want to simulate servers that include the headers anyway.
         pass
 
+class AllMethodsHandler(RequestHandler):
+    SUPPORTED_METHODS = RequestHandler.SUPPORTED_METHODS + ('OTHER',)
+
+    def method(self):
+        self.write(self.request.method)
+
+    get = post = put = delete = options = patch = other = method
 
 # These tests end up getting run redundantly: once here with the default
 # HTTPClient implementation, and then again in each implementation's own
@@ -99,6 +106,7 @@ class HTTPClientCommonTestCase(AsyncHTTPTestCase):
             url("/echopost", EchoPostHandler),
             url("/user_agent", UserAgentHandler),
             url("/304_with_content_length", ContentLength304Handler),
+            url("/all_methods", AllMethodsHandler),
         ], gzip=True)
 
     def test_hello_world(self):
@@ -365,6 +373,19 @@ Transfer-Encoding: chunked
         response2 = yield self.http_client.fetch(response.request)
         self.assertEqual(response2.body, b'Hello world!')
 
+    def test_all_methods(self):
+        for method in ['GET', 'DELETE', 'OPTIONS']:
+            response = self.fetch('/all_methods', method=method)
+            self.assertEqual(response.body, utf8(method))
+        for method in ['POST', 'PUT', 'PATCH']:
+            response = self.fetch('/all_methods', method=method, body=b'')
+            self.assertEqual(response.body, utf8(method))
+        response = self.fetch('/all_methods', method='HEAD')
+        self.assertEqual(response.body, b'')
+        response = self.fetch('/all_methods', method='OTHER',
+                              allow_nonstandard_methods=True)
+        self.assertEqual(response.body, b'OTHER')
+
 
 class RequestProxyTest(unittest.TestCase):
     def test_request_set(self):
index a1df2eb83f39202c6229a406bb4cadfbb72858ab..e7dfc85d26116d46145e1d1dcc7b5d234b9a1b9e 100644 (file)
@@ -1280,6 +1280,7 @@ class MultipleExceptionTest(SimpleHandlerTestCase):
         self.assertGreater(MultipleExceptionTest.Handler.exc_count, 2)
 
 
+@wsgi_safe
 class SetCurrentUserTest(SimpleHandlerTestCase):
     class Handler(RequestHandler):
         def prepare(self):
@@ -1293,3 +1294,74 @@ class SetCurrentUserTest(SimpleHandlerTestCase):
         # that want to forgo the lazy get_current_user property
         response = self.fetch('/')
         self.assertEqual(response.body, b'Hello Ben')
+
+
+@wsgi_safe
+class UnimplementedHTTPMethodsTest(SimpleHandlerTestCase):
+    class Handler(RequestHandler):
+        pass
+
+    def test_unimplemented_standard_methods(self):
+        for method in ['HEAD', 'GET', 'DELETE', 'OPTIONS']:
+            response = self.fetch('/', method=method)
+            self.assertEqual(response.code, 405)
+        for method in ['POST', 'PUT']:
+            response = self.fetch('/', method=method, body=b'')
+            self.assertEqual(response.code, 405)
+
+class UnimplementedNonStandardMethodsTest(SimpleHandlerTestCase):
+    # wsgiref.validate complains about unknown methods in a way that makes
+    # this test not wsgi_safe.
+    class Handler(RequestHandler):
+        def other(self):
+            # Even though this method exists, it won't get called automatically
+            # because it is not in SUPPORTED_METHODS.
+            self.write('other')
+
+    def test_unimplemented_patch(self):
+        # PATCH is recently standardized; Tornado supports it by default
+        # but wsgiref.validate doesn't like it.
+        response = self.fetch('/', method='PATCH', body=b'')
+        self.assertEqual(response.code, 405)
+
+    def test_unimplemented_other(self):
+        response = self.fetch('/', method='OTHER',
+                              allow_nonstandard_methods=True)
+        self.assertEqual(response.code, 405)
+
+@wsgi_safe
+class AllHTTPMethodsTest(SimpleHandlerTestCase):
+    class Handler(RequestHandler):
+        def method(self):
+            self.write(self.request.method)
+
+        get = delete = options = post = put = method
+
+    def test_standard_methods(self):
+        response = self.fetch('/', method='HEAD')
+        self.assertEqual(response.body, b'')
+        for method in ['GET', 'DELETE', 'OPTIONS']:
+            response = self.fetch('/', method=method)
+            self.assertEqual(response.body, utf8(method))
+        for method in ['POST', 'PUT']:
+            response = self.fetch('/', method=method, body=b'')
+            self.assertEqual(response.body, utf8(method))
+
+class PatchMethodTest(SimpleHandlerTestCase):
+    class Handler(RequestHandler):
+        SUPPORTED_METHODS = RequestHandler.SUPPORTED_METHODS + ('OTHER',)
+
+        def patch(self):
+            self.write('patch')
+
+        def other(self):
+            self.write('other')
+
+    def test_patch(self):
+        response = self.fetch('/', method='PATCH', body=b'')
+        self.assertEqual(response.body, b'patch')
+
+    def test_other(self):
+        response = self.fetch('/', method='OTHER',
+                              allow_nonstandard_methods=True)
+        self.assertEqual(response.body, b'other')