]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Support argument origin
authorTravis Beauvais <tbeauvais@gmail.com>
Sat, 28 Sep 2013 19:53:16 +0000 (12:53 -0700)
committerTravis Beauvais <tbeauvais@gmail.com>
Sat, 28 Sep 2013 19:53:16 +0000 (12:53 -0700)
tornado/httpserver.py [changed mode: 0644->0755]
tornado/httputil.py [changed mode: 0644->0755]
tornado/test/httputil_test.py [changed mode: 0644->0755]
tornado/test/web_test.py
tornado/web.py [changed mode: 0644->0755]
tornado/wsgi.py [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index cacb514..eba184a
@@ -29,6 +29,7 @@ from __future__ import absolute_import, division, print_function, with_statement
 import socket
 import ssl
 import time
+import copy
 
 from tornado.escape import native_str, parse_qs_bytes
 from tornado import httputil
@@ -336,7 +337,7 @@ class HTTPConnection(object):
         if self._request.method in ("POST", "PATCH", "PUT"):
             httputil.parse_body_arguments(
                 self._request.headers.get("Content-Type", ""), data,
-                self._request.arguments, self._request.files)
+                self._request.arguments, self._request.body_arguments, self._request.files)
         self.request_callback(self._request)
 
 
@@ -457,6 +458,8 @@ class HTTPRequest(object):
 
         self.path, sep, self.query = uri.partition('?')
         self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)
+        self.query_arguments = copy.deepcopy(self.arguments)
+        self.body_arguments = {}
 
     def supports_http_1_1(self):
         """Returns True if this request supports HTTP/1.1 semantics"""
old mode 100644 (file)
new mode 100755 (executable)
index 3e7337d..afd1bb2
@@ -310,7 +310,7 @@ def _int_or_none(val):
     return int(val)
 
 
-def parse_body_arguments(content_type, body, arguments, files):
+def parse_body_arguments(content_type, body, arguments, body_arguments, files):
     """Parses a form request body.
 
     Supports ``application/x-www-form-urlencoded`` and
@@ -324,18 +324,19 @@ def parse_body_arguments(content_type, body, arguments, files):
         for name, values in uri_arguments.items():
             if values:
                 arguments.setdefault(name, []).extend(values)
+                body_arguments.setdefault(name, []).extend(values)
     elif content_type.startswith("multipart/form-data"):
         fields = content_type.split(";")
         for field in fields:
             k, sep, v = field.strip().partition("=")
             if k == "boundary" and v:
-                parse_multipart_form_data(utf8(v), body, arguments, files)
+                parse_multipart_form_data(utf8(v), body, arguments, body_arguments, files)
                 break
         else:
             gen_log.warning("Invalid multipart/form-data")
 
 
-def parse_multipart_form_data(boundary, data, arguments, files):
+def parse_multipart_form_data(boundary, data, arguments, body_arguments, files):
     """Parses a ``multipart/form-data`` body.
 
     The ``boundary`` and ``data`` parameters are both byte strings.
@@ -379,6 +380,7 @@ def parse_multipart_form_data(boundary, data, arguments, files):
                 content_type=ctype))
         else:
             arguments.setdefault(name, []).append(value)
+            body_arguments.setdefault(name, []).append(value)
 
 
 def format_timestamp(ts):
old mode 100644 (file)
new mode 100755 (executable)
index 1e84da7..7a7f755
@@ -74,8 +74,9 @@ Content-Disposition: form-data; name="files"; filename="ab.txt"
 Foo
 --1234--""".replace(b"\n", b"\r\n")
         args = {}
+        body_args = {}
         files = {}
-        parse_multipart_form_data(b"1234", data, args, files)
+        parse_multipart_form_data(b"1234", data, args, body_args, files)
         file = files["files"][0]
         self.assertEqual(file["filename"], "ab.txt")
         self.assertEqual(file["body"], b"Foo")
@@ -89,8 +90,9 @@ Content-Disposition: form-data; name=files; filename=ab.txt
 Foo
 --1234--""".replace(b"\n", b"\r\n")
         args = {}
+        body_args = {}
         files = {}
-        parse_multipart_form_data(b"1234", data, args, files)
+        parse_multipart_form_data(b"1234", data, args, body_args, files)
         file = files["files"][0]
         self.assertEqual(file["filename"], "ab.txt")
         self.assertEqual(file["body"], b"Foo")
@@ -114,8 +116,9 @@ Foo
 --1234--""" % filename.replace('\\', '\\\\').replace('"', '\\"')
             data = utf8(data.replace("\n", "\r\n"))
             args = {}
+            body_args = {}
             files = {}
-            parse_multipart_form_data(b"1234", data, args, files)
+            parse_multipart_form_data(b"1234", data, args, body_args, files)
             file = files["files"][0]
             self.assertEqual(file["filename"], filename)
             self.assertEqual(file["body"], b"Foo")
@@ -128,8 +131,9 @@ Content-Disposition: form-data; name="files"; filename="ab.txt"
 Foo
 --1234--'''.replace(b"\n", b"\r\n")
         args = {}
+        body_args = {}
         files = {}
-        parse_multipart_form_data(b'"1234"', data, args, files)
+        parse_multipart_form_data(b'"1234"', data, args, body_args, files)
         file = files["files"][0]
         self.assertEqual(file["filename"], "ab.txt")
         self.assertEqual(file["body"], b"Foo")
@@ -141,9 +145,10 @@ Foo
 Foo
 --1234--'''.replace(b"\n", b"\r\n")
         args = {}
+        body_args = {}
         files = {}
         with ExpectLog(gen_log, "multipart/form-data missing headers"):
-            parse_multipart_form_data(b"1234", data, args, files)
+            parse_multipart_form_data(b"1234", data, args, body_args, files)
         self.assertEqual(files, {})
 
     def test_invalid_content_disposition(self):
@@ -154,9 +159,10 @@ Content-Disposition: invalid; name="files"; filename="ab.txt"
 Foo
 --1234--'''.replace(b"\n", b"\r\n")
         args = {}
+        body_args = {}
         files = {}
         with ExpectLog(gen_log, "Invalid multipart/form-data"):
-            parse_multipart_form_data(b"1234", data, args, files)
+            parse_multipart_form_data(b"1234", data, args, body_args, files)
         self.assertEqual(files, {})
 
     def test_line_does_not_end_with_correct_line_break(self):
@@ -166,9 +172,10 @@ Content-Disposition: form-data; name="files"; filename="ab.txt"
 
 Foo--1234--'''.replace(b"\n", b"\r\n")
         args = {}
+        body_args = {}
         files = {}
         with ExpectLog(gen_log, "Invalid multipart/form-data"):
-            parse_multipart_form_data(b"1234", data, args, files)
+            parse_multipart_form_data(b"1234", data, args, body_args, files)
         self.assertEqual(files, {})
 
     def test_content_disposition_header_without_name_parameter(self):
@@ -179,9 +186,10 @@ Content-Disposition: form-data; filename="ab.txt"
 Foo
 --1234--""".replace(b"\n", b"\r\n")
         args = {}
+        body_args = {}
         files = {}
         with ExpectLog(gen_log, "multipart/form-data value missing name"):
-            parse_multipart_form_data(b"1234", data, args, files)
+            parse_multipart_form_data(b"1234", data, args, body_args, files)
         self.assertEqual(files, {})
 
     def test_data_after_final_boundary(self):
@@ -196,8 +204,9 @@ Foo
 --1234--
 """.replace(b"\n", b"\r\n")
         args = {}
+        body_args = {}
         files = {}
-        parse_multipart_form_data(b"1234", data, args, files)
+        parse_multipart_form_data(b"1234", data, args, body_args, files)
         file = files["files"][0]
         self.assertEqual(file["filename"], "ab.txt")
         self.assertEqual(file["body"], b"Foo")
index 08093c79b6c9b364a28f7c4adc2515037e7306ce..f7e06d709c098c2802fcd62ff8382ed398487946 100644 (file)
@@ -288,7 +288,7 @@ class EchoHandler(RequestHandler):
                 if type(value) != bytes_type:
                     raise Exception("incorrect type for value: %r" %
                                     type(value))
-            for value in self.get_arguments(key):
+            for value in self.get_arguments(key, self.request.arguments):
                 if type(value) != unicode_type:
                     raise Exception("incorrect type for value: %r" %
                                     type(value))
old mode 100644 (file)
new mode 100755 (executable)
index 140fc1c..52e9137
@@ -348,14 +348,45 @@ class RequestHandler(object):
 
         The returned value is always unicode.
         """
-        args = self.get_arguments(name, strip=strip)
+        return self._get_argument(name, self.request.arguments, default, strip)
+
+    def get_body_argument(self, name, default=_ARG_DEFAULT, strip=True):
+        """Returns the value of the argument with the given name
+        from the request body.
+
+        If default is not provided, the argument is considered to be
+        required, and we raise a `MissingArgumentError` if it is missing.
+
+        If the argument appears in the url more than once, we return the
+        last value.
+
+        The returned value is always unicode.
+        """
+        return self._get_argument(name, self.request.body_arguments, default, strip)
+
+    def get_query_argument(self, name, default=_ARG_DEFAULT, strip=True):
+        """Returns the value of the argument with the given name
+        from the request query string.
+
+        If default is not provided, the argument is considered to be
+        required, and we raise a `MissingArgumentError` if it is missing.
+
+        If the argument appears in the url more than once, we return the
+        last value.
+
+        The returned value is always unicode.
+        """
+        return self._get_argument(name, self.request.query_arguments, default, strip)
+
+    def _get_argument(self, name, source, default=_ARG_DEFAULT, strip=True):
+        args = self.get_arguments(name, source, strip=strip)
         if not args:
             if default is self._ARG_DEFAULT:
                 raise MissingArgumentError(name)
             return default
         return args[-1]
 
-    def get_arguments(self, name, strip=True):
+    def get_arguments(self, name, source, strip=True):
         """Returns a list of the arguments with the given name.
 
         If the argument is not present, returns an empty list.
@@ -364,7 +395,7 @@ class RequestHandler(object):
         """
 
         values = []
-        for v in self.request.arguments.get(name, []):
+        for v in source.get(name, []):
             v = self.decode_argument(v, name=name)
             if isinstance(v, unicode_type):
                 # Get rid of any weird control chars (unless decoding gave
old mode 100644 (file)
new mode 100755 (executable)
index 5e25a56..f85e86c
@@ -33,6 +33,7 @@ from __future__ import absolute_import, division, print_function, with_statement
 
 import sys
 import time
+import copy
 import tornado
 
 from tornado import escape
@@ -142,11 +143,14 @@ class HTTPRequest(object):
         self.path += urllib_parse.quote(from_wsgi_str(environ.get("PATH_INFO", "")))
         self.uri = self.path
         self.arguments = {}
+        self.query_arguments = {}
+        self.body_arguments = {}
         self.query = environ.get("QUERY_STRING", "")
         if self.query:
             self.uri += "?" + self.query
             self.arguments = parse_qs_bytes(native_str(self.query),
                                             keep_blank_values=True)
+            self.query_arguments = copy.deepcopy(self.arguments)
         self.version = "HTTP/1.1"
         self.headers = httputil.HTTPHeaders()
         if environ.get("CONTENT_TYPE"):
@@ -171,7 +175,7 @@ class HTTPRequest(object):
         # Parse request body
         self.files = {}
         httputil.parse_body_arguments(self.headers.get("Content-Type", ""),
-                                      self.body, self.arguments, self.files)
+                                      self.body, self.arguments, self.body_arguments, self.files)
 
         self._start_time = time.time()
         self._finish_time = None