Skip to content
Merged
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
17 changes: 7 additions & 10 deletions httpcore/_async/http2.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from .._backends.auto import AsyncBackend, AsyncLock, AsyncSemaphore, AsyncSocketStream
from .._bytestreams import AsyncIteratorByteStream
from .._exceptions import PoolTimeout, RemoteProtocolError
from .._exceptions import LocalProtocolError, PoolTimeout, RemoteProtocolError
from .._types import URL, Headers, TimeoutDict
from .._utils import get_logger
from .base import AsyncByteStream, ConnectionState, NewConnectionRequired
Expand Down Expand Up @@ -155,10 +155,6 @@ async def send_connection_init(self, timeout: TimeoutDict) -> None:
data_to_send = self.h2_state.data_to_send()
await self.socket.write(data_to_send, timeout)

@property
def is_closed(self) -> bool:
return False

def is_socket_readable(self) -> bool:
return self.socket.is_readable()

Expand Down Expand Up @@ -318,17 +314,18 @@ async def send_headers(
# HTTP/1.1 style headers, and map them appropriately if we end up on
# an HTTP/2 connection.
authority = None

for k, v in headers:
if k == b"host":
authority = v
break

if authority is None:
default_port = {b"http": 80, b"https": 443}.get(scheme)
if port is not None and port != default_port:
authority = b"%s:%d" % (authority, port)
else:
authority = hostname
# Mirror the same error we'd see with `h11`, so that the behaviour
# is consistent. Although we're dealing with an `:authority`
# pseudo-header by this point, from an end-user perspective the issue
# is that the outgoing request needed to include a `host` header.
raise LocalProtocolError("Missing mandatory Host: header")

headers = [
(b":method", method),
Expand Down
17 changes: 7 additions & 10 deletions httpcore/_sync/http2.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from .._backends.sync import SyncBackend, SyncLock, SyncSemaphore, SyncSocketStream
from .._bytestreams import IteratorByteStream
from .._exceptions import PoolTimeout, RemoteProtocolError
from .._exceptions import LocalProtocolError, PoolTimeout, RemoteProtocolError
from .._types import URL, Headers, TimeoutDict
from .._utils import get_logger
from .base import SyncByteStream, ConnectionState, NewConnectionRequired
Expand Down Expand Up @@ -155,10 +155,6 @@ def send_connection_init(self, timeout: TimeoutDict) -> None:
data_to_send = self.h2_state.data_to_send()
self.socket.write(data_to_send, timeout)

@property
def is_closed(self) -> bool:
return False

def is_socket_readable(self) -> bool:
return self.socket.is_readable()

Expand Down Expand Up @@ -318,17 +314,18 @@ def send_headers(
# HTTP/1.1 style headers, and map them appropriately if we end up on
# an HTTP/2 connection.
authority = None

for k, v in headers:
if k == b"host":
authority = v
break

if authority is None:
default_port = {b"http": 80, b"https": 443}.get(scheme)
if port is not None and port != default_port:
authority = b"%s:%d" % (authority, port)
else:
authority = hostname
# Mirror the same error we'd see with `h11`, so that the behaviour
# is consistent. Although we're dealing with an `:authority`
# pseudo-header by this point, from an end-user perspective the issue
# is that the outgoing request needed to include a `host` header.
raise LocalProtocolError("Missing mandatory Host: header")

headers = [
(b":method", method),
Expand Down
16 changes: 16 additions & 0 deletions tests/async_tests/test_http11.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,19 @@ async def test_get_request_with_unclean_close_after_first_request() -> None:
extensions={},
)
assert str(excinfo.value) == "Server disconnected without sending a response."


@pytest.mark.trio
async def test_request_with_missing_host_header() -> None:
backend = MockBackend(http_buffer=[])

async with httpcore.AsyncConnectionPool(backend=backend) as http:
with pytest.raises(httpcore.LocalProtocolError) as excinfo:
await http.handle_async_request(
method=b"GET",
url=(b"http", b"example.org", None, b"/"),
headers=[],
stream=httpcore.ByteStream(b""),
extensions={},
)
assert str(excinfo.value) == "Missing mandatory Host: header"
Loading