Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,10 @@ The Connection object

True if the client sent a request with the ``Expect:
100-continue`` header, and is still waiting for a response
(i.e., the server has not sent a 100 Continue or any other kind
of response, and the client has not gone ahead and started
sending the body anyway).
(i.e., the server has not sent a 100 Continue, switched protocols,
or sent a final response, and the client has not gone ahead and
started sending the body anyway). Other informational responses,
such as 103 Early Hints, do not clear this flag.

See `RFC 7231 section 5.1.1
<https://tools.ietf.org/html/rfc7231#section-5.1.1>`_ for details.
Expand Down Expand Up @@ -695,12 +696,13 @@ have to be prepared to handle :class:`Request`\s that have an
``Expect: 100-continue`` header. You can `read the spec
<https://tools.ietf.org/html/rfc7231#section-5.1.1>`_ for the full
details, but basically what this header means is that after sending
the :class:`Request`, the client plans to pause and wait until they
see some response from the server before they send that request's
:class:`Data`. The server's response would normally be an
:class:`InformationalResponse` with status ``100 Continue``, but it
could be anything really (e.g. a full :class:`Response` with a 4xx
status code). The crucial thing as a server, though, is that you
the :class:`Request`, the client plans to pause and wait for a
``100 Continue`` or a final response before they send that request's
:class:`Data`. The server can send an :class:`InformationalResponse`
with status ``100 Continue`` to request the body, or a final
:class:`Response` (e.g. with a 4xx status code). Other informational
responses, such as ``103 Early Hints``, leave the client waiting for
``100 Continue``. The crucial thing as a server, though, is that you
should never block trying to read a request body if the client is
blocked waiting for you to tell them to send the request body.

Expand Down
6 changes: 5 additions & 1 deletion h11/_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,11 @@ def _process_event(self, role: Type[Sentinel], event: Event) -> None:
# 100-continue
if type(event) is Request and has_expect_100_continue(event):
self.client_is_waiting_for_100_continue = True
if type(event) in (InformationalResponse, Response):
# Other informational responses, such as 103 Early Hints, do not
# tell the client to send its request body.
if type(event) is Response or (
type(event) is InformationalResponse and event.status_code in (100, 101)
):
self.client_is_waiting_for_100_continue = False
if role is CLIENT and type(event) in (Data, EndOfMessage):
self.client_is_waiting_for_100_continue = False
Expand Down
11 changes: 10 additions & 1 deletion h11/tests/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,8 @@ def test_automagic_connection_close_handling() -> None:
assert conn.states == {CLIENT: MUST_CLOSE, SERVER: MUST_CLOSE}


def test_100_continue() -> None:
@pytest.mark.parametrize("informational_status", [None, 102, 103])
def test_100_continue(informational_status: Optional[int]) -> None:
def setup() -> ConnectionPair:
p = ConnectionPair()
p.send(
Expand All @@ -382,6 +383,14 @@ def setup() -> ConnectionPair:
)
for conn in p.conns:
assert conn.client_is_waiting_for_100_continue
if informational_status is not None:
for _ in range(2):
p.send(
SERVER,
InformationalResponse(status_code=informational_status, headers=[]),
)
for conn in p.conns:
assert conn.client_is_waiting_for_100_continue
assert not p.conn[CLIENT].they_are_waiting_for_100_continue
assert p.conn[SERVER].they_are_waiting_for_100_continue
return p
Expand Down
3 changes: 3 additions & 0 deletions newsfragments/211.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Preserve the waiting-for-100-continue state after informational responses
such as 103 Early Hints, so servers still send 100 Continue before waiting
for the request body.