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
# 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():
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.
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(
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."""
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.