]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Use httputil.HTTPHeaders for outgoing headers in RequestHandler.
authorBen Darnell <ben@bendarnell.com>
Sat, 26 Jan 2013 20:43:01 +0000 (15:43 -0500)
committerBen Darnell <ben@bendarnell.com>
Sat, 26 Jan 2013 20:52:28 +0000 (15:52 -0500)
It's still a bit slower, but less than the 10% noted in the old comment.
Case sensitivity here has proven more surprising and problematic than
expected as users try to overwrite headers set by the framework.

tornado/httputil.py
tornado/test/web_test.py
tornado/web.py
tornado/wsgi.py
website/sphinx/releases/next.rst

index 65ca4e5185e441d7d6936958e726f90c75863d3e..cd0aec7f7677328956b79c0a099a859b13f6db8a 100644 (file)
@@ -85,7 +85,9 @@ class HTTPHeaders(dict):
         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)
+            dict.__setitem__(self, norm_name,
+                             native_str(self[norm_name]) + ',' +
+                             native_str(value))
             self._as_list[norm_name].append(value)
         else:
             self[norm_name] = value
index e9dfb4cff1d4019ab12981d52236c9083de12f58..0f93644332e3ee80bcb48acf7dd2ea3a6eb68cb9 100644 (file)
@@ -431,9 +431,9 @@ class FlowControlHandler(RequestHandler):
 class MultiHeaderHandler(RequestHandler):
     def get(self):
         self.set_header("x-overwrite", "1")
-        self.set_header("x-overwrite", 2)
+        self.set_header("X-Overwrite", 2)
         self.add_header("x-multi", 3)
-        self.add_header("x-multi", "4")
+        self.add_header("X-Multi", "4")
 
 
 class RedirectHandler(RequestHandler):
index 05637034c3ed063cb4e36321e7e88c99b668dba9..306c85eaefb2a37ab54c9e05b7aecf47088d6054 100644 (file)
@@ -228,18 +228,12 @@ class RequestHandler(object):
 
     def clear(self):
         """Resets all headers and content for this response."""
-        # The performance cost of tornado.httputil.HTTPHeaders is significant
-        # (slowing down a benchmark with a trivial handler by more than 10%),
-        # and its case-normalization is not generally necessary for
-        # headers we generate on the server side, so use a plain dict
-        # and list instead.
-        self._headers = {
-            "Server": "TornadoServer/%s" % tornado.version,
-            "Content-Type": "text/html; charset=UTF-8",
-            "Date": datetime.datetime.utcnow().strftime(
-                "%a, %d %b %Y %H:%M:%S GMT"),
-        }
-        self._list_headers = []
+        self._headers = httputil.HTTPHeaders({
+                "Server": "TornadoServer/%s" % tornado.version,
+                "Content-Type": "text/html; charset=UTF-8",
+                "Date": datetime.datetime.utcnow().strftime(
+                    "%a, %d %b %Y %H:%M:%S GMT"),
+                })
         self.set_default_headers()
         if not self.request.supports_http_1_1():
             if self.request.headers.get("Connection") == "Keep-Alive":
@@ -294,7 +288,7 @@ class RequestHandler(object):
         Unlike `set_header`, `add_header` may be called multiple times
         to return multiple values for the same header.
         """
-        self._list_headers.append((name, self._convert_header_value(value)))
+        self._headers.add(name, self._convert_header_value(value))
 
     def clear_header(self, name):
         """Clears an outgoing header, undoing a previous `set_header` call.
@@ -1088,8 +1082,8 @@ class RequestHandler(object):
         lines = [utf8(self.request.version + " " +
                       str(self._status_code) +
                       " " + reason)]
-        lines.extend([(utf8(n) + b": " + utf8(v)) for n, v in
-                      itertools.chain(self._headers.items(), self._list_headers)])
+        lines.extend([utf8(n) + b": " + utf8(v) for n, v in self._headers.get_all()])
+
         if hasattr(self, "_new_cookie"):
             for cookie in self._new_cookie.values():
                 lines.append(utf8("Set-Cookie: " + cookie.OutputString(None)))
index 6c3d6a8b8a8e4b25302098f00d39f2996dc60f20..3d06860f9d8c192525a4db31e4735cf04195ee15 100644 (file)
@@ -122,7 +122,7 @@ class WSGIApplication(web.Application):
         assert handler._finished
         reason = handler._reason
         status = str(handler._status_code) + " " + reason
-        headers = list(handler._headers.items()) + handler._list_headers
+        headers = list(handler._headers.get_all())
         if hasattr(handler, "_new_cookie"):
             for cookie in handler._new_cookie.values():
                 headers.append(("Set-Cookie", cookie.OutputString(None)))
index 164cad6601942011a4748baa2ee90dc8a9fb44a9..3974c2f569dc40660ba205949d43f68a45dd0f61 100644 (file)
@@ -311,6 +311,8 @@ General
   `Application.add_handlers` call.  Now the request will be matched
   against the handlers for any ``host_pattern`` that includes the request's
   ``Host`` header.
+* `RequestHandler.set_header` now overwrites previous header values
+  case-insensitively.
 
 `tornado.websocket`
 ~~~~~~~~~~~~~~~~~~~