until the HTTP conection is closed.
"""
def __init__(self, stream, address, is_client,
- no_keep_alive=False, protocol=None, chunk_size=None):
+ no_keep_alive=False, protocol=None, chunk_size=None,
+ max_header_size=None):
self.is_client = is_client
self.stream = stream
self.address = address
else:
self.protocol = "http"
self._chunk_size = chunk_size or 65536
+ self._max_header_size = max_header_size or 65536
self._disconnect_on_finish = False
self._clear_request_state()
self.stream.set_close_callback(self._on_connection_close)
assert isinstance(delegate, httputil.HTTPMessageDelegate)
self.message_delegate = delegate
try:
- header_data = yield self.stream.read_until_regex(b"\r?\n\r?\n")
+ header_data = yield self.stream.read_until_regex(
+ b"\r?\n\r?\n",
+ max_bytes=self._max_header_size)
self._reading = True
self._finish_future = Future()
start_line, headers = self._parse_headers(header_data)
"""
def __init__(self, request_callback, no_keep_alive=False, io_loop=None,
xheaders=False, ssl_options=None, protocol=None, gzip=False,
- chunk_size=None, **kwargs):
+ chunk_size=None, max_header_size=None, **kwargs):
self.request_callback = request_callback
self.no_keep_alive = no_keep_alive
self.xheaders = xheaders
self.protocol = protocol
self.gzip = gzip
self.chunk_size = chunk_size
+ self.max_header_size = max_header_size
TCPServer.__init__(self, io_loop=io_loop, ssl_options=ssl_options,
**kwargs)
conn = HTTP1Connection(stream, address=address, is_client=False,
no_keep_alive=self.no_keep_alive,
protocol=self.protocol,
- chunk_size=self.chunk_size)
+ chunk_size=self.chunk_size,
+ max_header_size=self.max_header_size)
conn.start_serving(self, gzip=self.gzip)
def start_request(self, connection):
"""
def initialize(self, io_loop, max_clients=10,
hostname_mapping=None, max_buffer_size=104857600,
- resolver=None, defaults=None):
+ resolver=None, defaults=None, max_header_size=None):
"""Creates a AsyncHTTPClient.
Only a single AsyncHTTPClient instance exists per IOLoop
self.active = {}
self.waiting = {}
self.max_buffer_size = max_buffer_size
+ self.max_header_size = max_header_size
if resolver:
self.resolver = resolver
self.own_resolver = False
def _handle_request(self, request, release_callback, final_callback):
_HTTPConnection(self.io_loop, self, request, release_callback,
- final_callback, self.max_buffer_size, self.resolver)
+ final_callback, self.max_buffer_size, self.resolver,
+ self.max_header_size)
def _release_fetch(self, key):
del self.active[key]
_SUPPORTED_METHODS = set(["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"])
def __init__(self, io_loop, client, request, release_callback,
- final_callback, max_buffer_size, resolver):
+ final_callback, max_buffer_size, resolver,
+ max_header_size):
self.start_time = io_loop.time()
self.io_loop = io_loop
self.client = client
self.final_callback = final_callback
self.max_buffer_size = max_buffer_size
self.resolver = resolver
+ self.max_header_size = max_header_size
self.code = None
self.headers = None
self.chunks = []
self.stream.set_nodelay(True)
self.connection = HTTP1Connection(
self.stream, self._sockaddr, is_client=True,
- no_keep_alive=True, protocol=self.parsed.scheme)
+ no_keep_alive=True, protocol=self.parsed.scheme,
+ max_header_size=self.max_header_size)
start_line = httputil.RequestStartLine(self.request.method,
req_path, 'HTTP/1.1')
self.connection.write_headers(
write(compressed[20:])
self.fetch_chunk_sizes(body_producer=body_producer,
headers={'Content-Encoding': 'gzip'})
+
+
+class MaxHeaderSizeTest(AsyncHTTPTestCase):
+ def get_app(self):
+ return Application([('/', HelloWorldRequestHandler)])
+
+ def get_httpserver_options(self):
+ return dict(max_header_size=1024)
+
+ def test_small_headers(self):
+ response = self.fetch("/", headers={'X-Filler': 'a' * 100})
+ response.rethrow()
+ self.assertEqual(response.body, b"Hello world")
+
+ def test_large_headers(self):
+ with ExpectLog(gen_log, "Unsatisfiable read"):
+ response = self.fetch("/", headers={'X-Filler': 'a' * 1000})
+ self.assertEqual(response.code, 599)
def test_resolve_timeout(self):
response = self.fetch('/hello', connect_timeout=0.1)
self.assertEqual(response.code, 599)
+
+
+class MaxHeaderSizeTest(AsyncHTTPTestCase):
+ def get_app(self):
+ class SmallHeaders(RequestHandler):
+ def get(self):
+ self.set_header("X-Filler", "a" * 100)
+ self.write("ok")
+
+ class LargeHeaders(RequestHandler):
+ def get(self):
+ self.set_header("X-Filler", "a" * 1000)
+ self.write("ok")
+
+ return Application([('/small', SmallHeaders),
+ ('/large', LargeHeaders)])
+
+ def get_http_client(self):
+ return SimpleAsyncHTTPClient(io_loop=self.io_loop, max_header_size=1024)
+
+ def test_small_headers(self):
+ response = self.fetch('/small')
+ response.rethrow()
+ self.assertEqual(response.body, b'ok')
+
+ def test_large_headers(self):
+ with ExpectLog(gen_log, "Unsatisfiable read"):
+ response = self.fetch('/large')
+ self.assertEqual(response.code, 599)
self.resolver = Resolver(io_loop=io_loop)
super(WebSocketClientConnection, self).__init__(
io_loop, None, request, lambda: None, self._on_http_response,
- 104857600, self.resolver)
+ 104857600, self.resolver, 65536)
def close(self, code=None, reason=None):
"""Closes the websocket connection.