]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Improve curl_httpclient so it supports custom methods with payload.
authorTatiana Al-Chueyr <tatiana.alchueyr@gmail.com>
Tue, 1 Jul 2014 17:39:14 +0000 (14:39 -0300)
committerTatiana Al-Chueyr <tatiana.alchueyr@gmail.com>
Tue, 1 Jul 2014 17:48:20 +0000 (14:48 -0300)
Before this, no custom method (e.g. PATCH) added body to the CURL request.

tornado/curl_httpclient.py
tornado/test/curl_httpclient_test.py

index ae4471fdb9730a43564c3d8f79ac129424625edb..2940277847a5dd413876c7c98ba00ffd890d5b4c 100644 (file)
@@ -390,7 +390,10 @@ def _curl_setup_request(curl, request, buffer, headers):
         raise KeyError('unknown method ' + request.method)
 
     # Handle curl's cryptic options for every individual HTTP method
-    if request.method in ("POST", "PUT"):
+    if request.method == "GET":
+        if request.body is not None:
+            raise AssertionError('Body must be empty for GET request')
+    elif request.method in ("POST", "PUT") or request.body:
         if request.body is None:
             raise AssertionError(
                 'Body must not be empty for "%s" request'
@@ -405,10 +408,8 @@ def _curl_setup_request(curl, request, buffer, headers):
             curl.setopt(pycurl.IOCTLFUNCTION, ioctl)
             curl.setopt(pycurl.POSTFIELDSIZE, len(request.body))
         else:
+            curl.setopt(pycurl.UPLOAD, True)
             curl.setopt(pycurl.INFILESIZE, len(request.body))
-    elif request.method == "GET":
-        if request.body is not None:
-            raise AssertionError('Body must be empty for GET request')
 
     if request.auth_username is not None:
         userpwd = "%s:%s" % (request.auth_username, request.auth_password or '')
index 3873cf1e3182f8911649755fa00bcff5ba8976eb..5330ca387b85ed0d16ca499406101dd58bcf82de 100644 (file)
@@ -1,5 +1,6 @@
 from __future__ import absolute_import, division, print_function, with_statement
 
+import json
 from hashlib import md5
 
 from tornado.escape import utf8
@@ -8,7 +9,8 @@ from tornado.stack_context import ExceptionStackContext
 from tornado.testing import AsyncHTTPTestCase
 from tornado.test import httpclient_test
 from tornado.test.util import unittest
-from tornado.web import Application, RequestHandler
+from tornado.web import Application, RequestHandler, URLSpec
+
 
 try:
     import pycurl
@@ -120,3 +122,86 @@ class CurlHTTPClientTestCase(AsyncHTTPTestCase):
     def test_fail_custom_reason(self):
         response = self.fetch('/custom_fail_reason')
         self.assertEqual(str(response.error), "HTTP 400: Custom reason")
+
+
+class ContactListHandler(RequestHandler):
+
+    contact_list = {
+        "someone": {
+            "telephone": "1-800-247-9792",
+            "email": "some@email.com"
+        },
+        "another": {
+            "telephone": "1-104-132-7713",
+            "email": "other@email.com"
+        }
+    }
+
+    def get(self, contact_name):
+        data = self.contact_list.get(contact_name)
+        self.write(data)
+
+    def patch(self, contact_name):
+        """
+        Patch implementation according to RFC-6902
+        http://tools.ietf.org/html/rfc6902
+        """
+        patch_data = json.loads(self.request.body)
+        for patch_item in patch_data:
+            if patch_item["op"] == "replace":
+                attribute = patch_item["path"]
+                value = patch_item["value"]
+                self.contact_list[contact_name][attribute] = value
+
+
+@unittest.skipIf(pycurl is None, "pycurl module not present")
+class NonStandardMethodCurlHTTPClientTestCase(AsyncHTTPTestCase):
+
+    def setUp(self):
+        super(NonStandardMethodCurlHTTPClientTestCase, self).setUp()
+        self.http_client = CurlAsyncHTTPClient(self.io_loop,
+                                               defaults=dict(allow_ipv6=False))
+
+    def get_app(self):
+        return Application([
+            ('/(?P<contact_name>[\w\-]+)', ContactListHandler),
+        ])
+
+    def fetch(self, path, body=None, **kwargs):
+        kwargs['url'] = self.get_url(path)
+        request = HTTPRequest(**kwargs)
+        if body is not None:
+            request.body = body
+        request.allow_nonstandard_methods = True
+        self.http_client.fetch(request, self.stop, method=None)
+        return self.wait()
+
+    def test_get(self):
+        response = self.fetch("/someone", method='GET')
+        self.assertEqual(response.code, 200)
+        computed_body = json.loads(response.body)
+        expected_body = {
+            "telephone": "1-800-247-9792",
+            "email": "some@email.com"
+        }
+        self.assertEqual(computed_body, expected_body)
+
+    def test_patch_with_payload(self):
+        patch_list = [
+            {
+                "op": "replace",
+                "path": "telephone",
+                "value": "55-21-99756-1934"
+            }
+        ]
+        body = json.dumps(patch_list)
+        response_patch = self.fetch("/someone", method='PATCH', body=body)
+        self.assertEqual(response_patch.code, 200)
+
+        response_get = self.fetch("/someone", method="GET")
+        computed_body = json.loads(response_get.body)
+        expected_body = {
+            "telephone": "55-21-99756-1934",
+            "email": "some@email.com"
+        }
+        self.assertEqual(computed_body, expected_body)