]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
handle HTTP 303 redirects correctly
authorAaron Morton <aaron@the-mortons.org>
Wed, 28 Sep 2011 10:26:58 +0000 (23:26 +1300)
committerAaron Morton <aaron@the-mortons.org>
Wed, 28 Sep 2011 10:26:58 +0000 (23:26 +1300)
see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4

In response to a 303 the client SHOULD make a GET to the Location,
was using the original method.

tornado/simple_httpclient.py
tornado/test/simple_httpclient_test.py

index a98eb54484bda91ef34f6efd7788b7a3b4f2d31d..79a5960c31a2f57fc7b8deb1d891633340070ae0 100644 (file)
@@ -350,12 +350,17 @@ class _HTTPConnection(object):
                                    self.request)
         if (self.request.follow_redirects and
             self.request.max_redirects > 0 and
-            self.code in (301, 302)):
+            self.code in (301, 302, 303)):
             new_request = copy.copy(self.request)
             new_request.url = urlparse.urljoin(self.request.url,
                                                self.headers["Location"])
             new_request.max_redirects -= 1
             del new_request.headers["Host"]
+            # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4
+            # client SHOULD make a GET request
+            if self.code == 303:
+                new_request.method = "GET"
+                new_request.body = None
             new_request.original_request = original_request
             final_callback = self.final_callback
             self.final_callback = None
index f6d7235ae5b562079f199cb30ae5b3199cbaa6c4..55d5cf14453f95efa6f31d1a6f1f45120fa9a7cd 100644 (file)
@@ -44,6 +44,16 @@ class ContentLengthHandler(RequestHandler):
         self.set_header("Content-Length", self.get_argument("value"))
         self.write("ok")
 
+class PRGPostHandler(RequestHandler):
+    def post(self):
+        self.set_header("Location", "/prg_get")
+        self.set_status(303)
+
+class PRGGetHandler(RequestHandler):    
+    def get(self):
+        self.write("ok")
+        
+        
 class SimpleHTTPClientTestCase(AsyncHTTPTestCase, LogTrapTestCase):
     def get_app(self):
         # callable objects to finish pending /trigger requests
@@ -56,6 +66,8 @@ class SimpleHTTPClientTestCase(AsyncHTTPTestCase, LogTrapTestCase):
             url("/hang", HangHandler),
             url("/hello", HelloWorldHandler),
             url("/content_length", ContentLengthHandler),
+            url("/prg_post", PRGPostHandler),
+            url("/prg_get", PRGGetHandler),
             ], gzip=True)
 
     def test_singleton(self):
@@ -134,6 +146,14 @@ class SimpleHTTPClientTestCase(AsyncHTTPTestCase, LogTrapTestCase):
         self.assertTrue(response.effective_url.endswith("/countdown/2"))
         self.assertTrue(response.headers["Location"].endswith("/countdown/1"))
 
+    def test_303_redirect(self):
+       response = self.fetch("/prg_post", method="POST", body="")
+       self.assertEqual(200, response.code)
+       self.assertTrue(response.request.url.endswith("/prg_post"))
+       self.assertTrue(response.effective_url.endswith("/prg_get"))
+       #request is the original request, is a POST still
+       self.assertEqual("POST", response.request.method)
+        
     def test_request_timeout(self):
         response = self.fetch('/hang', request_timeout=0.1)
         self.assertEqual(response.code, 599)