Skip to content

Commit

Permalink
enable HTTP/1.1 when server has multiple workers
Browse files Browse the repository at this point in the history
HTTP/1.1 with the base single worker server seems to be unreliable,
sometimes simultaneous requests never complete. When the server is
multithread or multiprocess, and the handler doesn't directly set a
protocol version, enable HTTP/1.1. This enables keep-alive
connections and chunked streaming responses.
  • Loading branch information
davidism committed Jan 28, 2022
1 parent d062807 commit 4795b9a
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Expand Up @@ -71,6 +71,9 @@ Unreleased
- The development server uses ``Transfer-Encoding: chunked`` for
streaming responses when it is configured for HTTP/1.1.
:issue:`2090, 1327`, :pr:`2091`
- The development server uses HTTP/1.1, which enables keep-alive
connections and chunked streaming responses, when ``threaded`` or
``processes`` is enabled. :pr:`2323`


Version 2.0.3
Expand Down
8 changes: 8 additions & 0 deletions src/werkzeug/serving.py
Expand Up @@ -654,6 +654,14 @@ def __init__(
if handler is None:
handler = WSGIRequestHandler

# If the handler doesn't directly set a protocol version and
# thread or process workers are used, then allow chunked
# responses and keep-alive connections by enabling HTTP/1.1.
if "protocol_version" not in vars(handler) and (
self.multithread or self.multiprocess
):
handler.protocol_version = "HTTP/1.1"

self.host = host
self.port = port
self.app = app
Expand Down
9 changes: 0 additions & 9 deletions tests/live_apps/run.py
Expand Up @@ -4,15 +4,9 @@

from werkzeug.serving import generate_adhoc_ssl_context
from werkzeug.serving import run_simple
from werkzeug.serving import WSGIRequestHandler
from werkzeug.wrappers import Request
from werkzeug.wrappers import Response


class WSGI11RequestHandler(WSGIRequestHandler):
protocol_version = "HTTP/1.1"


name = sys.argv[1]
mod = import_module(f"{name}_app")

Expand All @@ -30,9 +24,6 @@ def app(request):
kwargs.update(json.loads(sys.argv[2]))
ssl_context = kwargs.get("ssl_context")

if kwargs.get("request_handler") == "HTTP/1.1":
kwargs["request_handler"] = WSGI11RequestHandler

if ssl_context == "custom":
kwargs["ssl_context"] = generate_adhoc_ssl_context()
elif isinstance(ssl_context, list):
Expand Down
4 changes: 2 additions & 2 deletions tests/test_serving.py
Expand Up @@ -259,7 +259,7 @@ def test_streaming_chunked_response(dev_server):
https://tools.ietf.org/html/rfc2616#section-3.6.1
"""
r = dev_server("streaming", request_handler="HTTP/1.1").request("/")
r = dev_server("streaming", threaded=True).request("/")
assert r.getheader("transfer-encoding") == "chunked"
assert r.data == "".join(str(x) + "\n" for x in range(5)).encode()

Expand All @@ -270,4 +270,4 @@ def test_streaming_chunked_truncation(dev_server):
content truncated by a prematurely closed connection.
"""
with pytest.raises(http.client.IncompleteRead):
dev_server("streaming", request_handler="HTTP/1.1").request("/crash")
dev_server("streaming", threaded=True).request("/crash")

0 comments on commit 4795b9a

Please sign in to comment.