]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Support multi-line headers
authorBen Darnell <ben@bendarnell.com>
Sun, 10 Jul 2011 23:13:45 +0000 (16:13 -0700)
committerBen Darnell <ben@bendarnell.com>
Sun, 10 Jul 2011 23:13:45 +0000 (16:13 -0700)
Closes #9.

tornado/httputil.py
tornado/test/httputil_test.py

index 6ba34f7a02058ed8b3750d2f4841987e238c1e57..3b78dc64029533d85915c6ff2f873c7bfe6b0362 100644 (file)
@@ -54,6 +54,7 @@ class HTTPHeaders(dict):
         # our __setitem__
         dict.__init__(self)
         self._as_list = {}
+        self._last_key = None
         self.update(*args, **kwargs)
 
     # new public methods
@@ -61,6 +62,7 @@ class HTTPHeaders(dict):
     def add(self, name, value):
         """Adds a new value for the given key."""
         norm_name = HTTPHeaders._normalize_name(name)
+        self._last_key = norm_name
         if norm_name in self:
             # bypass our override of __setitem__ since it modifies _as_list
             dict.__setitem__(self, norm_name, self[norm_name] + ',' + value)
@@ -91,8 +93,15 @@ class HTTPHeaders(dict):
         >>> h.get('content-type')
         'text/html'
         """
-        name, value = line.split(":", 1)
-        self.add(name, value.strip())
+        if line[0].isspace():
+            # continuation of a multi-line header
+            new_part = ' ' + line.lstrip()
+            self._as_list[self._last_key][-1] += new_part
+            dict.__setitem__(self, self._last_key,
+                             self[self._last_key] + new_part)
+        else:
+            name, value = line.split(":", 1)
+            self.add(name, value.strip())
 
     @classmethod
     def parse(cls, headers):
index a1fcf61cbb5d236155f8512366898ba5fabbc01b..0566b6e0e87f45bd209c406c1d21da63b6399ab8 100644 (file)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-from tornado.httputil import url_concat, parse_multipart_form_data
+from tornado.httputil import url_concat, parse_multipart_form_data, HTTPHeaders
 from tornado.escape import utf8
 from tornado.testing import LogTrapTestCase
 from tornado.util import b
@@ -113,3 +113,28 @@ Foo
             file = files["files"][0]
             self.assertEqual(file["filename"], filename)
             self.assertEqual(file["body"], b("Foo"))
+
+class HTTPHeadersTest(unittest.TestCase):
+    def test_multi_line(self):
+        # Lines beginning with whitespace are appended to the previous line
+        # with any leading whitespace replaced by a single space.
+        # Note that while multi-line headers are a part of the HTTP spec,
+        # their use is strongly discouraged.
+        data = """\
+Foo: bar
+ baz
+Asdf: qwer
+\tzxcv
+Foo: even
+     more
+     lines
+""".replace("\n", "\r\n")
+        headers = HTTPHeaders.parse(data)
+        self.assertEqual(headers["asdf"], "qwer zxcv")
+        self.assertEqual(headers.get_list("asdf"), ["qwer zxcv"])
+        self.assertEqual(headers["Foo"], "bar baz,even more lines")
+        self.assertEqual(headers.get_list("foo"), ["bar baz", "even more lines"])
+        self.assertEqual(sorted(list(headers.get_all())),
+                         [("Asdf", "qwer zxcv"),
+                          ("Foo", "bar baz"),
+                          ("Foo", "even more lines")])