From: Ben Darnell Date: Sun, 16 Mar 2014 00:11:02 +0000 (-0400) Subject: Move outgoing HTTP header generation to HTTP1Connection. X-Git-Tag: v4.0.0b1~91^2~49 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=361b61266362feb17cd20b7cf8be8eefc8523548;p=thirdparty%2Ftornado.git Move outgoing HTTP header generation to HTTP1Connection. --- diff --git a/tornado/http1connection.py b/tornado/http1connection.py index e9d6c9a95..3fb582790 100644 --- a/tornado/http1connection.py +++ b/tornado/http1connection.py @@ -17,7 +17,7 @@ from __future__ import absolute_import, division, print_function, with_statement from tornado.concurrent import Future -from tornado.escape import native_str +from tornado.escape import native_str, utf8 from tornado import gen from tornado import httputil from tornado import iostream @@ -154,6 +154,14 @@ class HTTP1Connection(object): # cycle and delay garbage collection of this connection. self._clear_request_state() + def write_headers(self, start_line, headers): + lines = [utf8("%s %s %s" % start_line)] + lines.extend([utf8(n) + b": " + utf8(v) for n, v in headers.get_all()]) + for line in lines: + if b'\n' in line: + raise ValueError('Newline in header: ' + repr(line)) + self.write(b"\r\n".join(lines) + b"\r\n\r\n") + def write(self, chunk, callback=None): """Writes a chunk of output to the stream.""" if not self.stream.closed(): diff --git a/tornado/httputil.py b/tornado/httputil.py index 80cd08ebe..f36284674 100644 --- a/tornado/httputil.py +++ b/tornado/httputil.py @@ -631,9 +631,14 @@ def format_timestamp(ts): return email.utils.formatdate(ts, usegmt=True) +RequestStartLine = collections.namedtuple( + 'RequestStartLine', ['method', 'path', 'version']) + + ResponseStartLine = collections.namedtuple( 'ResponseStartLine', ['version', 'code', 'reason']) + def parse_response_start_line(line): """Returns a (version, code, reason) tuple for an HTTP 1.x response line. diff --git a/tornado/simple_httpclient.py b/tornado/simple_httpclient.py index acc898439..4564c3700 100644 --- a/tornado/simple_httpclient.py +++ b/tornado/simple_httpclient.py @@ -322,21 +322,15 @@ class _HTTPConnection(httputil.HTTPMessageDelegate): self.request.headers["Accept-Encoding"] = "gzip" req_path = ((self.parsed.path or '/') + (('?' + self.parsed.query) if self.parsed.query else '')) - request_lines = [utf8("%s %s HTTP/1.1" % (self.request.method, - req_path))] - for k, v in self.request.headers.get_all(): - line = utf8(k) + b": " + utf8(v) - if b'\n' in line: - raise ValueError('Newline in header: ' + repr(line)) - request_lines.append(line) - request_str = b"\r\n".join(request_lines) + b"\r\n\r\n" - if self.request.body is not None: - request_str += self.request.body self.stream.set_nodelay(True) - self.stream.write(request_str) self.connection = HTTP1Connection( self.stream, self._sockaddr, no_keep_alive=True, protocol=self.parsed.scheme) + start_line = httputil.RequestStartLine(self.request.method, + req_path, 'HTTP/1.1') + self.connection.write_headers(start_line, self.request.headers) + if self.request.body is not None: + self.connection.write(self.request.body) # Ensure that any exception raised in read_response ends up in our # stack context. self.io_loop.add_future( diff --git a/tornado/web.py b/tornado/web.py index 2c11f2bc1..8ff22ca9b 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -787,19 +787,26 @@ class RequestHandler(object): self._status_code, self._headers, chunk = \ transform.transform_first_chunk( self._status_code, self._headers, chunk, include_footers) - headers = self._generate_headers() + # Finalize the cookie headers (which have been stored in a side + # object so an outgoing cookie could be overwritten before it + # is sent). + if hasattr(self, "_new_cookie"): + for cookie in self._new_cookie.values(): + self.add_header("Set-Cookie", cookie.OutputString(None)) + + start_line = httputil.ResponseStartLine(self.request.version, + self._status_code, + self._reason) + self.request.connection.write_headers(start_line, self._headers) else: for transform in self._transforms: chunk = transform.transform_chunk(chunk, include_footers) - headers = b"" # Ignore the chunk and only write the headers for HEAD requests if self.request.method == "HEAD": - if headers: - self.request.write(headers, callback=callback) return - self.request.write(headers + chunk, callback=callback) + self.request.write(chunk, callback=callback) def finish(self, chunk=None): """Finishes this response, ending the HTTP request.""" @@ -1245,18 +1252,6 @@ class RequestHandler(object): if self._auto_finish and not self._finished: self.finish() - def _generate_headers(self): - reason = self._reason - lines = [utf8(self.request.version + " " + - str(self._status_code) + - " " + reason)] - 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))) - return b"\r\n".join(lines) + b"\r\n\r\n" - def _log(self): """Logs the current request.