Skip to content

Commit

Permalink
Support HTTP/3
Browse files Browse the repository at this point in the history
  • Loading branch information
karpetrosyan committed Oct 19, 2023
1 parent 8780c9c commit e2af16a
Show file tree
Hide file tree
Showing 12 changed files with 1,149 additions and 11 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## 1.0.0 (November 6th, 2023)
## Unreleased

- Fix pool timeout to account for the total time spent retrying. (#823)

## 1.0.0 (October 6th, 2023)

From version 1.0 our async support is now optional, as the package has minimal dependencies by default.

Expand Down
4 changes: 4 additions & 0 deletions httpcore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
AsyncConnectionInterface,
AsyncConnectionPool,
AsyncHTTP2Connection,
AsyncHTTP3Connection,
AsyncHTTP11Connection,
AsyncHTTPConnection,
AsyncHTTPProxy,
Expand Down Expand Up @@ -40,6 +41,7 @@
ConnectionInterface,
ConnectionPool,
HTTP2Connection,
HTTP3Connection,
HTTP11Connection,
HTTPConnection,
HTTPProxy,
Expand Down Expand Up @@ -85,6 +87,7 @@ def __init__(self, *args, **kwargs): # type: ignore
"AsyncHTTPProxy",
"AsyncHTTP11Connection",
"AsyncHTTP2Connection",
"AsyncHTTP3Connection",
"AsyncConnectionInterface",
"AsyncSOCKSProxy",
# sync
Expand All @@ -93,6 +96,7 @@ def __init__(self, *args, **kwargs): # type: ignore
"HTTPProxy",
"HTTP11Connection",
"HTTP2Connection",
"HTTP3Connection",
"ConnectionInterface",
"SOCKSProxy",
# network backends, implementations
Expand Down
13 changes: 13 additions & 0 deletions httpcore/_async/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ def __init__(self, *args, **kwargs) -> None: # type: ignore
)


try:
from .http3 import AsyncHTTP3Connection
except ImportError: # pragma: nocover

class AsyncHTTP3Connection: # type: ignore
def __init__(self, *args, **kwargs) -> None: # type: ignore
raise RuntimeError(
"Attempted to use http3 support, but the `aioquic` package is not "
"installed. Use 'pip install httpcore[http3]'."
)


try:
from .socks_proxy import AsyncSOCKSProxy
except ImportError: # pragma: nocover
Expand All @@ -34,6 +46,7 @@ def __init__(self, *args, **kwargs) -> None: # type: ignore
"AsyncHTTPProxy",
"AsyncHTTP11Connection",
"AsyncHTTP2Connection",
"AsyncHTTP3Connection",
"AsyncConnectionInterface",
"AsyncSOCKSProxy",
]
16 changes: 13 additions & 3 deletions httpcore/_async/connection_pool.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import ssl
import sys
import time
from types import TracebackType
from typing import AsyncIterable, AsyncIterator, Iterable, List, Optional, Type

from .._backends.auto import AutoBackend
from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend
from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol
from .._exceptions import ConnectionNotAvailable, PoolTimeout, UnsupportedProtocol
from .._models import Origin, Request, Response
from .._synchronization import AsyncEvent, AsyncLock, AsyncShieldCancellation
from .connection import AsyncHTTPConnection
Expand Down Expand Up @@ -220,15 +221,20 @@ async def handle_async_request(self, request: Request) -> Response:
)

status = RequestStatus(request)
timeouts = request.extensions.get("timeout", {})
timeout = timeouts.get("pool", None)

if timeout is not None:
deadline = time.monotonic() + timeout
else:
deadline = float("inf")

async with self._pool_lock:
self._requests.append(status)
await self._close_expired_connections()
await self._attempt_to_acquire_connection(status)

while True:
timeouts = request.extensions.get("timeout", {})
timeout = timeouts.get("pool", None)
try:
connection = await status.wait_for_connection(timeout=timeout)
except BaseException as exc:
Expand Down Expand Up @@ -263,6 +269,10 @@ async def handle_async_request(self, request: Request) -> Response:
else:
break

timeout = deadline - time.monotonic()
if timeout < 0:
raise PoolTimeout # pragma: nocover

# When we return the response, we wrap the stream in a special class
# that handles notifying the connection pool once the response
# has been released.
Expand Down
Loading

0 comments on commit e2af16a

Please sign in to comment.