From: Ben Darnell Date: Sat, 26 Jan 2013 20:43:01 +0000 (-0500) Subject: Use httputil.HTTPHeaders for outgoing headers in RequestHandler. X-Git-Tag: v3.0.0~149 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9df23246564a8c8f53904fcf02f84000c9eeec77;p=thirdparty%2Ftornado.git Use httputil.HTTPHeaders for outgoing headers in RequestHandler. 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. --- diff --git a/tornado/httputil.py b/tornado/httputil.py index 65ca4e518..cd0aec7f7 100644 --- a/tornado/httputil.py +++ b/tornado/httputil.py @@ -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 diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index e9dfb4cff..0f9364433 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -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): diff --git a/tornado/web.py b/tornado/web.py index 05637034c..306c85eae 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -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))) diff --git a/tornado/wsgi.py b/tornado/wsgi.py index 6c3d6a8b8..3d06860f9 100644 --- a/tornado/wsgi.py +++ b/tornado/wsgi.py @@ -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))) diff --git a/website/sphinx/releases/next.rst b/website/sphinx/releases/next.rst index 164cad660..3974c2f56 100644 --- a/website/sphinx/releases/next.rst +++ b/website/sphinx/releases/next.rst @@ -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` ~~~~~~~~~~~~~~~~~~~