Updated mirrored methods of custom tornado http server

Should now be up to date with stock implementation again.
This commit is contained in:
Gina Häußge 2017-02-21 13:21:18 +01:00
parent cf20b3a3c3
commit 5d07c5a0b2

View file

@ -7,11 +7,7 @@ __copyright__ = "Copyright (C) 2014 The OctoPrint Project - Released under terms
import logging
import os
import datetime
import stat
import mimetypes
import email
import time
import re
import tornado
@ -530,7 +526,8 @@ class WsgiInputContainer(object):
if not data:
raise Exception("WSGI app did not call start_response")
status_code = int(data["status"].split()[0])
status_code, reason = data["status"].split(" ", 1)
status_code = int(status_code)
headers = data["headers"]
header_set = set(k.lower() for (k, v) in headers)
body = tornado.escape.utf8(body)
@ -542,13 +539,12 @@ class WsgiInputContainer(object):
if "server" not in header_set:
headers.append(("Server", "TornadoServer/%s" % tornado.version))
parts = [tornado.escape.utf8("HTTP/1.1 " + data["status"] + "\r\n")]
start_line = tornado.httputil.ResponseStartLine("HTTP/1.1", status_code, reason)
header_obj = tornado.httputil.HTTPHeaders()
for key, value in headers:
parts.append(tornado.escape.utf8(key) + b": " + tornado.escape.utf8(value) + b"\r\n")
parts.append(b"\r\n")
parts.append(body)
request.write(b"".join(parts))
request.finish()
header_obj.add(key, value)
request.connection.write_headers(start_line, header_obj, chunk=body)
request.connection.finish()
self._log(status_code, request)
@staticmethod
@ -583,22 +579,22 @@ class WsgiInputContainer(object):
host = request.host
port = 443 if request.protocol == "https" else 80
environ = {
"REQUEST_METHOD": request.method,
"SCRIPT_NAME": "",
"PATH_INFO": to_wsgi_str(tornado.escape.url_unescape(
request.path, encoding=None, plus=False)),
"QUERY_STRING": request.query,
"REMOTE_ADDR": request.remote_ip,
"SERVER_NAME": host,
"SERVER_PORT": str(port),
"SERVER_PROTOCOL": request.version,
"wsgi.version": (1, 0),
"wsgi.url_scheme": request.protocol,
"wsgi.input": request_body,
"wsgi.errors": sys.stderr,
"wsgi.multithread": False,
"wsgi.multiprocess": True,
"wsgi.run_once": False,
"REQUEST_METHOD": request.method,
"SCRIPT_NAME": "",
"PATH_INFO": to_wsgi_str(tornado.escape.url_unescape(
request.path, encoding=None, plus=False)),
"QUERY_STRING": request.query,
"REMOTE_ADDR": request.remote_ip,
"SERVER_NAME": host,
"SERVER_PORT": str(port),
"SERVER_PROTOCOL": request.version,
"wsgi.version": (1, 0),
"wsgi.url_scheme": request.protocol,
"wsgi.input": request_body,
"wsgi.errors": sys.stderr,
"wsgi.multithread": False,
"wsgi.multiprocess": True,
"wsgi.run_once": False,
}
if "Content-Type" in request.headers:
environ["CONTENT_TYPE"] = request.headers.pop("Content-Type")
@ -619,7 +615,7 @@ class WsgiInputContainer(object):
log_method = access_log.error
request_time = 1000.0 * request.request_time()
summary = request.method + " " + request.uri + " (" + \
request.remote_ip + ")"
request.remote_ip + ")"
log_method("%d %s %.2fms", status_code, summary, request_time)
@ -645,35 +641,21 @@ class CustomHTTPServer(tornado.httpserver.HTTPServer):
def __init__(self, *args, **kwargs):
pass
def initialize(self, request_callback, no_keep_alive=False, io_loop=None,
xheaders=False, ssl_options=None, protocol=None,
decompress_request=False,
chunk_size=None, max_header_size=None,
idle_connection_timeout=None, body_timeout=None,
max_body_sizes=None, default_max_body_size=None, max_buffer_size=None):
self.request_callback = request_callback
self.no_keep_alive = no_keep_alive
self.xheaders = xheaders
self.protocol = protocol
self.conn_params = CustomHTTP1ConnectionParameters(
decompress=decompress_request,
chunk_size=chunk_size,
max_header_size=max_header_size,
header_timeout=idle_connection_timeout or 3600,
max_body_sizes=max_body_sizes,
default_max_body_size=default_max_body_size,
body_timeout=body_timeout)
tornado.tcpserver.TCPServer.__init__(self, io_loop=io_loop, ssl_options=ssl_options,
max_buffer_size=max_buffer_size,
read_chunk_size=chunk_size)
self._connections = set()
def initialize(self, *args, **kwargs):
default_max_body_size = kwargs.pop("default_max_body_size", None)
max_body_sizes = kwargs.pop("max_body_sizes", None)
tornado.httpserver.HTTPServer.initialize(self, *args, **kwargs)
additional = dict(default_max_body_size=default_max_body_size,
max_body_sizes=max_body_sizes)
self.conn_params = CustomHTTP1ConnectionParameters.from_stock_params(self.conn_params, **additional)
def handle_stream(self, stream, address):
context = tornado.httpserver._HTTPRequestContext(stream, address,
self.protocol)
conn = CustomHTTP1ServerConnection(
stream, self.conn_params, context)
self.protocol)
conn = CustomHTTP1ServerConnection(stream, self.conn_params, context)
self._connections.add(conn)
conn.start_serving(self)
@ -690,7 +672,7 @@ class CustomHTTP1ServerConnection(tornado.http1connection.HTTP1ServerConnection)
try:
while True:
conn = CustomHTTP1Connection(self.stream, False,
self.params, self.context)
self.params, self.context)
request_delegate = delegate.start_request(self, conn)
try:
ret = yield conn.read_response(request_delegate)
@ -734,8 +716,13 @@ class CustomHTTP1Connection(tornado.http1connection.HTTP1Connection):
current request exceeds the individual max content length, the request processing is aborted and an
``HTTPInputError`` is raised.
"""
content_length = headers.get("Content-Length")
if "Content-Length" in headers:
if "Transfer-Encoding" in headers:
# Response cannot contain both Content-Length and
# Transfer-Encoding headers.
# http://tools.ietf.org/html/rfc7230#section-3.3.3
raise tornado.httputil.HTTPInputError(
"Response with both Transfer-Encoding and Content-Length")
if "," in headers["Content-Length"]:
# Proxies sometimes cause Content-Length headers to get
# duplicated. If all the values are identical then we can
@ -746,9 +733,14 @@ class CustomHTTP1Connection(tornado.http1connection.HTTP1Connection):
"Multiple unequal Content-Lengths: %r" %
headers["Content-Length"])
headers["Content-Length"] = pieces[0]
content_length = int(headers["Content-Length"])
content_length = int(content_length)
try:
content_length = int(headers["Content-Length"])
except ValueError:
# Handles non-integer Content-Length value.
raise tornado.httputil.HTTPInputError(
"Only integer Content-Length is allowed: %s" % headers["Content-Length"])
max_content_length = self._get_max_content_length(self._request_start_line.method, self._request_start_line.path)
if max_content_length is not None and 0 <= max_content_length < content_length:
raise tornado.httputil.HTTPInputError("Content-Length too long")
@ -800,9 +792,20 @@ class CustomHTTP1ConnectionParameters(tornado.http1connection.HTTP1ConnectionPar
"""
def __init__(self, *args, **kwargs):
tornado.http1connection.HTTP1ConnectionParameters.__init__(self, args, kwargs)
self.max_body_sizes = kwargs["max_body_sizes"] if "max_body_sizes" in kwargs else list()
self.default_max_body_size = kwargs["default_max_body_size"] if "default_max_body_size" in kwargs else None
max_body_sizes = kwargs.pop("max_body_sizes", list())
default_max_body_size = kwargs.pop("default_max_body_size", None)
tornado.http1connection.HTTP1ConnectionParameters.__init__(self, *args, **kwargs)
self.max_body_sizes = max_body_sizes
self.default_max_body_size = default_max_body_size
@classmethod
def from_stock_params(cls, other, **additional):
kwargs = dict(other.__dict__)
for key, value in additional.items():
kwargs[key] = value
return cls(**kwargs)
#~~ customized large response handler