Skip to content
Closed
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
3 changes: 3 additions & 0 deletions CHANGES/99999.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added ``aiofastnet`` package to ``speedups`` extra. aiofastnet provides faster alternatives to the standard loop functions, which are used to run server or establish connections. If you experience any issues that you think might be related to this change, you can try to disable ``aiofastnet`` either by defining AIOHTTP_NO_EXTENSIONS env var or by uninstalling aiofastnet package.

-- by :user:`tarasko`.
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ Sunit Deshpande
Sviatoslav Bulbakha
Sviatoslav Sydorenko
Taha Jahangir
Taras Kozlov
Taras Voinarovskyi
Terence Honles
Thanos Lefteris
Expand Down
12 changes: 9 additions & 3 deletions aiohttp/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
set_result,
)
from .log import client_logger
from .net_helpers import (
create_connection,
start_tls
)
from .resolver import DefaultResolver

if sys.version_info >= (3, 12):
Expand Down Expand Up @@ -1256,7 +1260,7 @@ async def _wrap_create_connection(
and sys.version_info >= (3, 11)
):
kwargs["ssl_shutdown_timeout"] = self._ssl_shutdown_timeout
return await self._loop.create_connection(*args, **kwargs, sock=sock)
return await create_connection(self._loop, *args, **kwargs, sock=sock) # type: ignore[no-any-return]
except cert_errors as exc:
raise ClientConnectorCertificateError(req.connection_key, exc) from exc
except ssl_errors as exc:
Expand Down Expand Up @@ -1337,7 +1341,8 @@ async def _start_tls_connection(
try:
# ssl_shutdown_timeout is only available in Python 3.11+
if sys.version_info >= (3, 11) and self._ssl_shutdown_timeout:
tls_transport = await self._loop.start_tls(
tls_transport = await start_tls(
self._loop,
underlying_transport,
tls_proto,
sslcontext,
Expand All @@ -1346,7 +1351,8 @@ async def _start_tls_connection(
ssl_shutdown_timeout=self._ssl_shutdown_timeout,
)
else:
tls_transport = await self._loop.start_tls(
tls_transport = await start_tls(
self._loop,
underlying_transport,
tls_proto,
sslcontext,
Expand Down
32 changes: 32 additions & 0 deletions aiohttp/net_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from asyncio import AbstractEventLoop
from .helpers import NO_EXTENSIONS


if NO_EXTENSIONS:
HAS_AIOFASTNET = False
else:
try:
import aiofastnet
HAS_AIOFASTNET = True

create_connection = aiofastnet.create_connection
start_tls = aiofastnet.start_tls
create_server = aiofastnet.create_server
sendfile = aiofastnet.sendfile
except ImportError:
HAS_AIOFASTNET = False


if not HAS_AIOFASTNET:
async def create_connection(loop: AbstractEventLoop, *args, **kwargs): # type: ignore[no-untyped-def]
return await loop.create_connection(*args, **kwargs)

async def start_tls(loop: AbstractEventLoop, *args, **kwargs): # type: ignore[no-untyped-def]
return await loop.start_tls(*args, **kwargs)

async def create_server(loop: AbstractEventLoop, *args, **kwargs): # type: ignore[no-untyped-def]
return await loop.create_server(*args, **kwargs)

async def sendfile(loop: AbstractEventLoop, *args, **kwargs): # type: ignore[no-untyped-def]
return await loop.sendfile(*args, **kwargs)

3 changes: 2 additions & 1 deletion aiohttp/web_fileresponse.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from . import hdrs
from .abc import AbstractStreamWriter
from .helpers import DEFAULT_CHUNK_SIZE, ETAG_ANY, ETag, must_be_empty_body
from .net_helpers import sendfile
from .typedefs import LooseHeaders, PathLike
from .web_exceptions import (
HTTPForbidden,
Expand Down Expand Up @@ -132,7 +133,7 @@ async def _sendfile(
raise ConnectionResetError("Connection lost")

try:
await loop.sendfile(transport, fobj, offset, count)
await sendfile(loop, transport, fobj, offset, count)
except NotImplementedError:
return await self._sendfile_fallback(writer, fobj, offset, count)

Expand Down
8 changes: 5 additions & 3 deletions aiohttp/web_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from .abc import AbstractAccessLogger, AbstractStreamWriter
from .http_parser import RawRequestMessage
from .net_helpers import create_server
from .streams import StreamReader
from .typedefs import PathLike
from .web_app import Application
Expand Down Expand Up @@ -130,7 +131,8 @@ async def start(self) -> None:
loop = asyncio.get_running_loop()
server = self._runner.server
assert server is not None
self._server = await loop.create_server(
self._server = await create_server(
loop,
server,
self._host,
self._port,
Expand Down Expand Up @@ -244,8 +246,8 @@ async def start(self) -> None:
loop = asyncio.get_running_loop()
server = self._runner.server
assert server is not None
self._server = await loop.create_server(
server, sock=self._sock, ssl=self._ssl_context, backlog=self._backlog
self._server = await create_server(
loop, server, sock=self._sock, ssl=self._ssl_context, backlog=self._backlog
)


Expand Down
46 changes: 46 additions & 0 deletions docs/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,52 @@ enable compression in NGINX (you are deploying aiohttp behind reverse
proxy, right?).


How do I enable Kernel TLS, and should I do it?
-----------------------------------------------

Kernel TLS (KTLS) allows aiohttp to move encryption and decryption of
TLS traffic from userspace to the kernel. It was added to the Linux kernel in
4.13, but full support for TLS 1.3 and modern ciphers is available only
since 5.19.

KTLS will be beneficial if you run an HTTPS server that often returns
:class:`~aiohttp.web.FileResponse` objects or you have a high-end NIC that can
offload TLS encryption. For ordinary
dynamic responses, small files, or deployments behind a TLS-terminating reverse
proxy, it is unlikely to help and may actually slightly degrade performance.

KTLS is supported through the ``aiofastnet`` package, which is installed as
part of the ``speedups`` extra.

To enable KTLS, you have to do and check the following:

* Make sure the Linux ``tls`` kernel module is loaded::

sudo modprobe tls

* Make sure the ``ssl.OP_ENABLE_KTLS`` option is enabled in ``SSLContext``
(available since Python 3.12)::

sslcontext.options |= ssl.OP_ENABLE_KTLS

* Make sure Python is using OpenSSL 3.0 or newer. OpenSSL should have been
built on a machine whose Linux headers are new enough. OpenSSL needs Linux
headers at least 4.13.0 to build the transmit path; older headers make it
skip KTLS support. Typically, Python is using the system OpenSSL on Linux,
but some times distributions ship their own OpenSSL. The following commands
will help identify the OpenSSL version and which ``libssl`` and ``libcrypto``
are being used by the ``ssl`` module::

python -c "import ssl; print(ssl.OPENSSL_VERSION)"
ldd "$(python -c 'import _ssl; print(_ssl.__file__)')"


If ``ssl.OP_ENABLE_KTLS`` was requested in ``sslcontext``, but ``aiofastnet``
could not enable KTLS, it will log a warning suggesting the possible reason.

After enabling it, run your own benchmarks and verify that KTLS actually
speeds things up in your case.

How do I manage a ClientSession within a web server?
----------------------------------------------------

Expand Down
4 changes: 4 additions & 0 deletions docs/spelling_wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ABI
addons
aiodns
aioes
aiofastnet
aiohttp
aiohttpdemo
aiohttp’s
Expand Down Expand Up @@ -181,6 +182,7 @@ keepalive
keepalived
keepalives
keepaliving
KTLS
kib
KiB
kwarg
Expand Down Expand Up @@ -225,6 +227,7 @@ namedtuple
nameservers
namespace
netrc
NIC
nginx
Nginx
Nikolay
Expand All @@ -234,6 +237,7 @@ nowait
OAuth
Online
optimizations
OpenSSL
orjson
os
outcoming
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ dynamic = [
[project.optional-dependencies]
speedups = [
"aiodns >= 3.3.0; sys_platform != 'android' and sys_platform != 'ios'",
"aiofastnet >= 0.7.0; platform_python_implementation == 'CPython' and (platform_machine == 'x86_64' or platform_machine == 'AMD64' or platform_machine == 'aarch64')",
"Brotli >= 1.2; platform_python_implementation == 'CPython' and sys_platform != 'android' and sys_platform != 'ios'",
"brotlicffi >= 1.2; platform_python_implementation != 'CPython'",
"backports.zstd; platform_python_implementation == 'CPython' and python_version < '3.14' and sys_platform != 'android' and sys_platform != 'ios'",
Expand Down
2 changes: 2 additions & 0 deletions requirements/base-ft.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#
aiodns==4.0.4 ; sys_platform != "android" and sys_platform != "ios"
# via -r requirements/runtime-deps.in
aiofastnet==0.7.0 ; platform_python_implementation == "CPython" and (platform_machine == "x86_64" or platform_machine == "AMD64" or platform_machine == "aarch64")
# via -r requirements/runtime-deps.in
aiohappyeyeballs==2.6.2
# via -r requirements/runtime-deps.in
aiosignal==1.4.0
Expand Down
2 changes: 2 additions & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#
aiodns==4.0.4 ; sys_platform != "android" and sys_platform != "ios"
# via -r requirements/runtime-deps.in
aiofastnet==0.7.0 ; platform_python_implementation == "CPython" and (platform_machine == "x86_64" or platform_machine == "AMD64" or platform_machine == "aarch64")
# via -r requirements/runtime-deps.in
aiohappyeyeballs==2.6.2
# via -r requirements/runtime-deps.in
aiosignal==1.4.0
Expand Down
2 changes: 2 additions & 0 deletions requirements/constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ aiodns==4.0.4 ; sys_platform != "android" and sys_platform != "ios"
# via
# -r requirements/lint.in
# -r requirements/runtime-deps.in
aiofastnet==0.7.0 ; platform_python_implementation == "CPython" and (platform_machine == "x86_64" or platform_machine == "AMD64" or platform_machine == "aarch64")
# via -r requirements/runtime-deps.in
aiohappyeyeballs==2.6.2
# via
# -r requirements/runtime-deps.in
Expand Down
2 changes: 2 additions & 0 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ aiodns==4.0.4 ; sys_platform != "android" and sys_platform != "ios"
# via
# -r requirements/lint.in
# -r requirements/runtime-deps.in
aiofastnet==0.7.0 ; platform_python_implementation == "CPython" and (platform_machine == "x86_64" or platform_machine == "AMD64" or platform_machine == "aarch64")
# via -r requirements/runtime-deps.in
aiohappyeyeballs==2.6.2
# via
# -r requirements/runtime-deps.in
Expand Down
1 change: 1 addition & 0 deletions requirements/lint.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
aiodns
aiofastnet
backports.zstd; implementation_name == "cpython" and python_version < "3.14"
blockbuster
freezegun
Expand Down
2 changes: 2 additions & 0 deletions requirements/lint.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#
aiodns==4.0.4
# via -r requirements/lint.in
aiofastnet==0.7.0
# via -r requirements/lint.in
aiohappyeyeballs==2.6.2
# via aiohttp
aiohttp==3.13.5
Expand Down
1 change: 1 addition & 0 deletions requirements/runtime-deps.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Extracted from `pyproject.toml` via `make sync-direct-runtime-deps`

aiodns >= 3.3.0; sys_platform != 'android' and sys_platform != 'ios'
aiofastnet >= 0.7.0; platform_python_implementation == 'CPython' and (platform_machine == 'x86_64' or platform_machine == 'AMD64' or platform_machine == 'aarch64')
aiohappyeyeballs >= 2.5.0
aiosignal >= 1.4.0
async-timeout >= 4.0, < 6.0 ; python_version < '3.11'
Expand Down
2 changes: 2 additions & 0 deletions requirements/runtime-deps.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ aiohappyeyeballs==2.6.2
# via -r requirements/runtime-deps.in
aiosignal==1.4.0
# via -r requirements/runtime-deps.in
aiofastnet==0.7.0 ; platform_python_implementation == "CPython" and (platform_machine == "x86_64" or platform_machine == "AMD64" or platform_machine == "aarch64")
# via -r requirements/runtime-deps.in
async-timeout==5.0.1 ; python_version < "3.11"
# via -r requirements/runtime-deps.in
backports-zstd==1.3.0 ; platform_python_implementation == "CPython" and python_version < "3.14" and sys_platform != "android" and sys_platform != "ios"
Expand Down
4 changes: 4 additions & 0 deletions requirements/test-ft.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#
aiodns==4.0.4 ; sys_platform != "android" and sys_platform != "ios"
# via -r requirements/runtime-deps.in
aiofastnet==0.7.0 ; platform_python_implementation == "CPython" and (platform_machine == "x86_64" or platform_machine == "AMD64" or platform_machine == "aarch64")
# via -r requirements/runtime-deps.in
aiohappyeyeballs==2.6.1
# via -r requirements/runtime-deps.in
aiohappyeyeballs==2.6.2
# via
# -r requirements/runtime-deps.in
Expand Down
2 changes: 2 additions & 0 deletions requirements/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#
aiodns==4.0.4 ; sys_platform != "android" and sys_platform != "ios"
# via -r requirements/runtime-deps.in
aiofastnet==0.7.0 ; platform_python_implementation == "CPython" and (platform_machine == "x86_64" or platform_machine == "AMD64" or platform_machine == "aarch64")
# via -r requirements/runtime-deps.in
aiohappyeyeballs==2.6.2
# via
# -r requirements/runtime-deps.in
Expand Down
4 changes: 4 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ def blockbuster(request: pytest.FixtureRequest) -> Iterator[None]:
# synchronization in async code.
# Allow lock.acquire calls to prevent these false positives
bb.functions["threading.Lock.acquire"].deactivate()

# aiofastnet is using sendfile on a non-blocking socket.
# blockbuster triggers anyway. Seems like a false positive
bb.functions["os.sendfile"].deactivate()
yield


Expand Down
Loading
Loading