1. Project Overview & Quickstart (aio-libs/aiohttp)
File: docs/abc.rst
.. module:: aiohttp.abc
.. _aiohttp-abc:
Abstract Base Classes
Abstract routing
aiohttp has abstract classes for managing web interfaces.
The most part of :mod:aiohttp.web is not intended to be inherited
but few of them are.
aiohttp.web is built on top of few concepts: application, router,
request and response.
router is a pluggable part: a library user may build a router
from scratch, all other parts should work with new router seamlessly.
:class:aiohttp.abc.AbstractRouter has the only mandatory method:
:meth:aiohttp.abc.AbstractRouter.resolve coroutine. It must return an
:class:aiohttp.abc.AbstractMatchInfo instance.
If the requested URL handler is found
:meth:aiohttp.abc.AbstractMatchInfo.handler is a :term:web-handler for
requested URL and :attr:aiohttp.abc.AbstractMatchInfo.http_exception is None.
Otherwise :attr:aiohttp.abc.AbstractMatchInfo.http_exception is an instance of
:exc:~aiohttp.web.HTTPException like 404: NotFound or 405: Method
Not Allowed. :meth:aiohttp.abc.AbstractMatchInfo.handler raises
:attr:~aiohttp.abc.AbstractMatchInfo.http_exception on call.
.. class:: AbstractRouter
Abstract router, :class:aiohttp.web.Application accepts it as
router parameter and returns as
:attr:aiohttp.web.Application.router.
.. method:: resolve(request)
:async:
Performs URL resolving. It's an abstract method, should be
overridden in *router* implementation.
:param request: :class:`aiohttp.web.Request` instance for
resolving, the request has
:attr:`aiohttp.web.Request.match_info` equals to
``None`` at resolving stage.
:return: :class:`aiohttp.abc.AbstractMatchInfo` instance... class:: AbstractMatchInfo
Abstract match info, returned by :meth:aiohttp.abc.AbstractRouter.resolve call.
.. attribute:: http_exception
:exc:`aiohttp.web.HTTPException` if no match was found, ``None``
otherwise. .. method:: handler(request)
:async:
Abstract method performing :term:`web-handler` processing.
:param request: :class:`aiohttp.web.Request` instance for
resolving, the request has
:attr:`aiohttp.web.Request.match_info` equals to
``None`` at resolving stage.
:return: :class:`aiohttp.web.StreamResponse` or descendants.
:raise: :class:`aiohttp.web.HTTPException` on error .. method:: expect_handler(request)
:async:
Abstract method for handling *100-continue* processing.Abstract Class Based Views
For class based view support aiohttp has abstract
:class:AbstractView class which is awaitable (may be uses likeawait Cls() or yield from Cls() and has a request as an
attribute.
.. class:: AbstractView
An abstract class, base for all class based views implementations.
Methods __iter__ and __await__ should be overridden.
.. attribute:: request
:class:`aiohttp.web.Request` instance for performing the request.Abstract Cookie Jar
.. class:: AbstractCookieJar
The cookie jar instance is available as :attr:aiohttp.ClientSession.cookie_jar.
The jar contains :class:~http.cookies.Morsel items for storing
internal cookie data.
API provides a count of saved cookies::
len(session.cookie_jar)These cookies may be iterated over::
for cookie in session.cookie_jar:
print(cookie.key)
print(cookie["domain"]) An abstract class for cookie storage. Implements
:class:collections.abc.Iterable and
:class:collections.abc.Sized.
.. method:: update_cookies(cookies, response_url=None)
Update cookies returned by server in ``Set-Cookie`` header.
:param cookies: a :class:`collections.abc.Mapping`
(e.g. :class:`dict`, :class:`~http.cookies.SimpleCookie`) or
*iterable* of *pairs* with cookies returned by server's
response.
:param str response_url: URL of response, ``None`` for *shared
cookies*. Regular cookies are coupled with server's URL and
are sent only to this server, shared ones are sent in every
client request... method:: filter_cookies(request_url)
Return jar's cookies acceptable for URL and available in
``Cookie`` header for sending client requests for given URL.
:param str response_url: request's URL for which cookies are asked.
:return: :class:`http.cookies.SimpleCookie` with filtered
cookies for given URL... method:: clear(predicate=None)
Removes all cookies from the jar if the predicate is ``None``. Otherwise remove only those :class:`~http.cookies.Morsel` that ``predicate(morsel)`` returns ``True``.
:param predicate: callable that gets :class:`~http.cookies.Morsel` as a parameter and returns ``True`` if this :class:`~http.cookies.Morsel` must be deleted from the jar.
.. versionadded:: 3.8.. method:: clear_domain(domain)
Remove all cookies from the jar that belongs to the specified domain or its subdomains.
:param str domain: domain for which cookies must be deleted from the jar.
.. versionadded:: 3.8Abstract Access Logger
.. class:: AbstractAccessLogger
An abstract class, base for all :class:aiohttp.web.RequestHandler
access_logger implementations
Method log should be overridden.
.. method:: log(request, response, time)
:param request: :class:`aiohttp.web.Request` object.
:param response: :class:`aiohttp.web.Response` object.
:param float time: Time taken to serve the request... attribute:: enabled
Return True if logger is enabled.
Override this property if logging is disabled to avoid the
overhead of calculating details to feed the logger.
This property may be omitted if logging is always enabled.Abstract Resolver
.. class:: AbstractResolver
An abstract class, base for all resolver implementations.
Method resolve should be overridden.
.. method:: resolve(host, port, family)
Resolve host name to IP address.
:param str host: host name to resolve.
:param int port: port number.
:param int family: socket family.
:return: list of :class:`aiohttp.abc.ResolveResult` instances... method:: close()
Release resolver... class:: ResolveResult
Result of host name resolution.
.. attribute:: hostname
The host name that was provided... attribute:: host
The IP address that was resolved... attribute:: port
The port that was resolved... attribute:: family
The address family that was resolved... attribute:: proto
The protocol that was resolved... attribute:: flags
The flags that were resolved.File: docs/built_with.rst
.. _aiohttp-built-with:
Built with aiohttp
aiohttp is used to build useful libraries built on top of it,
and there's a page dedicated to list them: :ref:aiohttp-3rd-party.
There are also projects that leverage the power of aiohttp to
provide end-user tools, like command lines or software with
full user interfaces.
This page aims to list those projects. If you are using aiohttp
in your software and if it's playing a central role, you
can add it here in this list.
You can also add a Built with aiohttp link somewhere in your
project, pointing to <https://github.com/aio-libs/aiohttp>_.
Pulp <https://pulpproject.org>_ Platform for managing repositories
of software packages and making them available to consumers.repo-peek <https://github.com/rahulunair/repo-peek>_ CLI tool to open a remote repo locally quickly.Molotov <http://molotov.readthedocs.io>_ Load testing tool.Arsenic <https://github.com/hde/arsenic>_ Async WebDriver.Home Assistant <https://home-assistant.io>_ Home Automation Platform.Backend.AI <https://backend.ai>_ Code execution API service.doh-proxy <https://github.com/facebookexperimental/doh-proxy>_ DNS Over HTTPS Proxy.Mariner <https://gitlab.com/radek-sprta/mariner>_ Command-line torrent searcher.DEEPaaS API <https://github.com/indigo-dc/DEEPaaS>_ REST API for Machine learning, Deep learning and artificial intelligence applications.BentoML <https://github.com/bentoml/BentoML>_ Machine Learning model serving frameworksalted <https://github.com/RuedigerVoigt/salted>_ fast link check library (for HTML, Markdown, LaTeX, ...) with CLIUnofficial Tabdeal API <https://github.com/MohsenHNSJ/unofficial_tabdeal_api>_ A package to communicate with the Tabdeal trading platform.
File: docs/changes.rst
.. _aiohttp_changes:
========= Changelog
.. only:: not is_release
To be included in v\ |release| (if present)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. towncrier-draft-entries:: |release| [UNRELEASED DRAFT]
Released versions
^^^^^^^^^^^^^^^^^
.. include:: ../CHANGES.rst
:start-after: .. towncrier release notes start
File: docs/client.rst
.. _aiohttp-client:
Client
.. currentmodule:: aiohttp
The page contains all information about aiohttp Client API:
.. toctree::
:name: client
:maxdepth: 3
Quickstart
Advanced Usage
Client Middleware Cookbook
Reference
Tracing Reference
The aiohttp Request Lifecycle
File: docs/client_advanced.rst
.. currentmodule:: aiohttp
.. _aiohttp-client-advanced:
Advanced Client Usage
.. _aiohttp-client-session:
Client Session
:class:ClientSession is the heart and the main entry point for all
client API operations.
Create the session first, use the instance for performing HTTP
requests and initiating WebSocket connections.
The session contains a cookie storage and connection pool, thus
cookies and connections are shared between HTTP requests sent by the
same session.
Custom Request Headers
If you need to add HTTP headers to a request, pass them in a
:class:dict to the headers parameter.
For example, if you want to specify the content-type directly::
url = 'http://example.com/image'
payload = b'GIF89a\x01\x00\x01\x00\x00\xff\x00,\x00\x00'
b'\x00\x00\x01\x00\x01\x00\x00\x02\x00;'
headers = {'content-type': 'image/gif'}
await session.post(url,
data=payload,
headers=headers)You also can set default headers for all session requests::
headers={"Authorization": "Basic bG9naW46cGFzcw=="}
async with aiohttp.ClientSession(headers=headers) as session:
async with session.get("http://httpbin.org/headers") as r:
json_body = await r.json()
assert json_body['headers']['Authorization'] == \
'Basic bG9naW46cGFzcw=='Typical use case is sending JSON body. You can specify content type
directly as shown above, but it is more convenient to use special keywordjson::
await session.post(url, json={'example': 'text'})For text/plain::
await session.post(url, data='ะัะธะฒะตั, ะะธั!')Authentication
For HTTP Basic Authentication, build the Authorization header using
:func:encode_basic_auth and pass it via headers::
from aiohttp import ClientSession, encode_basic_auth
headers = {"Authorization": encode_basic_auth("user", "pass")}
async with ClientSession(headers=headers) as session:
...For HTTP digest authentication, use the :class:DigestAuthMiddleware client middleware::
from aiohttp import ClientSession, DigestAuthMiddleware
# Create the middleware with your credentials
digest_auth = DigestAuthMiddleware(login="user", password="password")
# Pass it to the ClientSession as a tuple
async with ClientSession(middlewares=(digest_auth,)) as session:
# The middleware will automatically handle auth challenges
async with session.get("https://example.com/protected") as resp:
print(await resp.text())The :class:DigestAuthMiddleware implements HTTP Digest Authentication according to RFC 7616,
providing a more secure alternative to Basic Authentication. It supports all
standard hash algorithms including MD5, SHA, SHA-256, SHA-512 and their session
variants, as well as both 'auth' and 'auth-int' quality of protection (qop) options.
The middleware automatically handles the authentication flow by intercepting 401 responses
and retrying with proper credentials.
Note that if the request is redirected and the redirect URL contains
credentials, those credentials will supersede any previously set credentials.
In other words, if http://[email protected] redirects tohttp://[email protected], the second request will be authenticated
as other_user. Providing both the auth parameter and authentication in
the initial URL will result in a :exc:ValueError.
For other authentication flows, the Authorization header can be set
directly::
headers = {"Authorization": "Bearer eyJh...0M30"}
async with ClientSession(headers=headers) as session:
...The authentication header for a session may be updated as and when required.
For example::
session.headers["Authorization"] = "Bearer eyJh...1OH0"Note that a copy of the headers dictionary is set as an attribute when
creating a :class:ClientSession instance (as a :class:multidict.CIMultiDict
object). Updating the original dictionary does not have any effect.
In cases where the authentication header value expires periodically, an
:mod:asyncio task may be used to update the session's default headers in the
background.
.. _aiohttp-client-middleware:
Client Middleware
The client supports middleware to intercept requests and responses. This can be
useful for authentication, logging, request/response modification, retries etc.
For more examples and common middleware patterns, see the :ref:aiohttp-client-middleware-cookbook.
Creating a middleware
^^^^^^^^^^^^^^^^^^^^^
To create a middleware, define an async function (or callable class) that accepts a request object
and a handler function, and returns a response. Middlewares must follow the
:type:ClientMiddlewareType signature::
async def auth_middleware(req: ClientRequest, handler: ClientHandlerType) -> ClientResponse:
req.headers["Authorization"] = get_auth_header()
return await handler(req)Using Middlewares
^^^^^^^^^^^^^^^^^
You can apply middlewares to a client session or to individual requests::
# Apply to all requests in a session
async with ClientSession(middlewares=(my_middleware,)) as session:
resp = await session.get("http://example.com")
# Apply to a specific request
async with ClientSession() as session:
resp = await session.get("http://example.com", middlewares=(my_middleware,))Middleware Chaining
^^^^^^^^^^^^^^^^^^^
Multiple middlewares are applied in the order they are listed::
# Middlewares are applied in order: logging -> auth -> request
async with ClientSession(middlewares=(logging_middleware, auth_middleware)) as session:
async with session.get("http://example.com") as resp:
...A key aspect to understand about the middleware sequence is that the execution flow follows this pattern:
- The first middleware in the list is called first and executes its code before calling the handler
- The handler is the next middleware in the chain (or the request handler if there are no more middlewares)
- When the handler returns a response, execution continues from the last middleware right after the handler call
- This creates a nested "onion-like" pattern for execution
For example, with middlewares=(middleware1, middleware2), the execution order would be:
- Enter
middleware1(pre-request code) - Enter
middleware2(pre-request code) - Execute the actual request handler
- Exit
middleware2(post-response code) - Exit
middleware1(post-response code)
This flat structure means that a middleware is applied on each retry attempt inside the client's retry loop,
not just once before all retries. This allows middleware to modify requests freshly on each retry attempt.
For example, if we had a retry middleware and a logging middleware, and we want every retried request to be
logged separately, then we'd need to specify middlewares=(retry_mw, logging_mw). If we reversed the order
to middlewares=(logging_mw, retry_mw), then we'd only log once regardless of how many retries are done.
.. note::
Client middleware is a powerful feature but should be used judiciously.
Each middleware adds overhead to request processing. For simple use cases
like adding static headers, you can often use request parameters
(e.g., headers) or session configuration instead.
Custom Cookies
To send your own cookies to the server, you can use the cookies
parameter of :class:ClientSession constructor::
url = 'http://httpbin.org/cookies'
cookies = {'cookies_are': 'working'}
async with ClientSession(cookies=cookies) as session:
async with session.get(url) as resp:
assert await resp.json() == {
"cookies": {"cookies_are": "working"}}.. note::
httpbin.org/cookies endpoint returns request cookies
in JSON-encoded body.
To access session cookies see :attr:ClientSession.cookie_jar.
:class:~aiohttp.ClientSession may be used for sharing cookies
between multiple requests::
async with aiohttp.ClientSession() as session:
async with session.get(
"http://httpbin.org/cookies/set?my_cookie=my_value",
allow_redirects=False
) as resp:
assert resp.cookies["my_cookie"].value == "my_value"
async with session.get("http://httpbin.org/cookies") as r:
json_body = await r.json()
assert json_body["cookies"]["my_cookie"] == "my_value"Response Headers and Cookies
We can view the server's response :attr:ClientResponse.headers using
a :class:~multidict.CIMultiDictProxy::
assert resp.headers == {
'ACCESS-CONTROL-ALLOW-ORIGIN': '*',
'CONTENT-TYPE': 'application/json',
'DATE': 'Tue, 15 Jul 2014 16:49:51 GMT',
'SERVER': 'gunicorn/18.0',
'CONTENT-LENGTH': '331',
'CONNECTION': 'keep-alive'}The dictionary is special, though: it's made just for HTTP
headers. According to RFC 7230 <http://tools.ietf.org/html/rfc7230#section-3.2>_, HTTP Header names
are case-insensitive. It also supports multiple values for the same
key as HTTP protocol does.
So, we can access the headers using any capitalization we want::
assert resp.headers['Content-Type'] == 'application/json'
assert resp.headers.get('content-type') == 'application/json'All headers are converted from binary data using UTF-8 withsurrogateescape option. That works fine on most cases but
sometimes unconverted data is needed if a server uses nonstandard
encoding. While these headers are malformed from :rfc:7230
perspective they may be retrieved by using
:attr:ClientResponse.raw_headers property::
assert resp.raw_headers == (
(b'SERVER', b'nginx'),
(b'DATE', b'Sat, 09 Jan 2016 20:28:40 GMT'),
(b'CONTENT-TYPE', b'text/html; charset=utf-8'),
(b'CONTENT-LENGTH', b'12150'),
(b'CONNECTION', b'keep-alive'))If a response contains some HTTP Cookies, you can quickly access them::
url = 'http://example.com/some/cookie/setting/url'
async with session.get(url) as resp:
print(resp.cookies['example_cookie_name']).. note::
Response cookies contain only values, that were in Set-Cookie headers
of the last request in redirection chain. To gather cookies between all
redirection requests please use :ref:aiohttp.ClientSession <aiohttp-client-session> object.
Redirection History
If a request was redirected, it is possible to view previous responses using
the :attr:~ClientResponse.history attribute::
resp = await session.get('http://example.com/some/redirect/')
assert resp.status == 200
assert resp.url == URL('http://example.com/some/other/url/')
assert len(resp.history) == 1
assert resp.history[0].status == 301
assert resp.history[0].url == URL(
'http://example.com/some/redirect/')If no redirects occurred or allow_redirects is set to False,
history will be an empty sequence.
Cookie Jar
.. _aiohttp-client-cookie-safety:
Cookie Safety
^^^^^^^^^^^^^
By default :class:~aiohttp.ClientSession uses strict version of
:class:aiohttp.CookieJar. :rfc:2109 explicitly forbids cookie
accepting from URLs with IP address instead of DNS name
(e.g. http://127.0.0.1:80/cookie).
It's good but sometimes for testing we need to enable support for such
cookies. It should be done by passing unsafe=True to
:class:aiohttp.CookieJar constructor::
jar = aiohttp.CookieJar(unsafe=True)
session = aiohttp.ClientSession(cookie_jar=jar)
.. _aiohttp-client-cookie-quoting-routine:
Cookie Quoting Routine
^^^^^^^^^^^^^^^^^^^^^^
The client uses the :class:~aiohttp.SimpleCookie quoting routines
conform to the :rfc:2109, which in turn references the character definitions
from :rfc:2068. They provide a two-way quoting algorithm where any non-text
character is translated into a 4 character sequence: a forward-slash
followed by the three-digit octal equivalent of the character.
Any \ or " is quoted with a preceding \ slash.
Because of the way browsers really handle cookies (as opposed to what the RFC
says) we also encode , and ;.
Some backend systems does not support quoted cookies. You can skip this
quotation routine by passing quote_cookie=False to the
:class:~aiohttp.CookieJar constructor::
jar = aiohttp.CookieJar(quote_cookie=False)
session = aiohttp.ClientSession(cookie_jar=jar)
.. _aiohttp-client-dummy-cookie-jar:
Dummy Cookie Jar
^^^^^^^^^^^^^^^^
Sometimes cookie processing is not desirable. For this purpose it's
possible to pass :class:aiohttp.DummyCookieJar instance into client
session::
jar = aiohttp.DummyCookieJar()
session = aiohttp.ClientSession(cookie_jar=jar)
Uploading pre-compressed data
To upload data that is already compressed before passing it to
aiohttp, call the request function with the used compression algorithm
name (usually deflate or gzip) as the value of theContent-Encoding header::
async def my_coroutine(session, headers, my_data):
data = zlib.compress(my_data)
headers = {'Content-Encoding': 'deflate'}
async with session.post('http://httpbin.org/post',
data=data,
headers=headers)
passDisabling content type validation for JSON responses
The standard explicitly restricts JSON Content-Type HTTP header toapplication/json or any extended form, e.g. application/vnd.custom-type+json.
Unfortunately, some servers send a wrong type, like text/html.
This can be worked around in two ways:
Pass the expected type explicitly (in this case checking will be strict, without the extended form support,
socustom/xxx+typewon't be accepted):await resp.json(content_type='custom/type').Disable the check entirely:
await resp.json(content_type=None).
.. _aiohttp-client-tracing:
Client Tracing
The execution flow of a specific request can be followed attaching
listeners coroutines to the signals provided by the
:class:TraceConfig instance, this instance will be used as a
parameter for the :class:ClientSession constructor having as a
result a client that triggers the different signals supported by the
:class:TraceConfig. By default any instance of
:class:ClientSession class comes with the signals ability
disabled. The following snippet shows how the start and the end
signals of a request flow can be followed::
async def on_request_start(
session, trace_config_ctx, params):
print("Starting request")
async def on_request_end(session, trace_config_ctx, params):
print("Ending request")
trace_config = aiohttp.TraceConfig()
trace_config.on_request_start.append(on_request_start)
trace_config.on_request_end.append(on_request_end)
async with aiohttp.ClientSession(
trace_configs=[trace_config]) as client:
client.get('http://example.com/some/redirect/')The trace_configs is a list that can contain instances of
:class:TraceConfig class that allow run the signals handlers coming
from different :class:TraceConfig instances. The following example
shows how two different :class:TraceConfig that have a different
nature are installed to perform their job in each signal handle::
from mylib.traceconfig import AuditRequest
from mylib.traceconfig import XRay
async with aiohttp.ClientSession(
trace_configs=[AuditRequest(), XRay()]) as client:
client.get('http://example.com/some/redirect/')All signals take as a parameters first, the :class:ClientSession
instance used by the specific request related to that signals and
second, a :class:~types.SimpleNamespace instance calledtrace_config_ctx. The trace_config_ctx object can be used to
share the state through to the different signals that belong to the
same request and to the same :class:TraceConfig class, perhaps::
async def on_request_start(
session, trace_config_ctx, params):
trace_config_ctx.start = asyncio.get_event_loop().time()
async def on_request_end(session, trace_config_ctx, params):
elapsed = asyncio.get_event_loop().time() - trace_config_ctx.start
print("Request took {}".format(elapsed))The trace_config_ctx param is by default a
:class:~types.SimpleNamespace that is initialized at the beginning of the
request flow. However, the factory used to create this object can be
overwritten using the trace_config_ctx_factory constructor param of
the :class:TraceConfig class.
The trace_request_ctx param can given at the beginning of the
request execution, accepted by all of the HTTP verbs, and will be
passed as a keyword argument for the trace_config_ctx_factory
factory. This param is useful to pass data that is only available at
request time, perhaps::
async def on_request_start(
session, trace_config_ctx, params):
print(trace_config_ctx.trace_request_ctx)
session.get('http://example.com/some/redirect/',
trace_request_ctx={'foo': 'bar'}).. seealso:: :ref:aiohttp-client-tracing-reference section for
more information about the different signals supported.
Connectors
To tweak or change transport layer of requests you can pass a custom
connector to :class:~aiohttp.ClientSession and family. For example::
conn = aiohttp.TCPConnector()
session = aiohttp.ClientSession(connector=conn).. note::
By default session object takes the ownership of the connector, among
other things closing the connections once the session is closed. If
you are keen on share the same connector through different session
instances you must give the connector_owner parameter as False
for each session instance.
.. seealso:: :ref:aiohttp-client-reference-connectors section for
more information about different connector types and
configuration options.
Limiting connection pool size
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To limit amount of simultaneously opened connections you can pass limit
parameter to connector::
conn = aiohttp.TCPConnector(limit=30)The example limits total amount of parallel connections to 30.
The default is 100.
If you explicitly want not to have limits, pass 0. For example::
conn = aiohttp.TCPConnector(limit=0)To limit amount of simultaneously opened connection to the same
endpoint ((host, port, is_ssl) triple) you can pass limit_per_host
parameter to connector::
conn = aiohttp.TCPConnector(limit_per_host=30)The example limits amount of parallel connections to the same to 30.
The default is 0 (no limit on per host bases).
Tuning the DNS cache
^^^^^^^^^^^^^^^^^^^^
By default :class:~aiohttp.TCPConnector comes with the DNS cache
table enabled, and resolutions will be cached by default for 10 seconds.
This behavior can be changed either to change of the TTL for a resolution,
as can be seen in the following example::
conn = aiohttp.TCPConnector(ttl_dns_cache=300)or disabling the use of the DNS cache table, meaning that all requests will
end up making a DNS resolution, as the following example shows::
conn = aiohttp.TCPConnector(use_dns_cache=False)Resolving using custom nameservers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In order to specify the nameservers to when resolving the hostnames,
:term:aiodns is required::
from aiohttp.resolver import AsyncResolver
resolver = AsyncResolver(nameservers=["8.8.8.8", "8.8.4.4"])
conn = aiohttp.TCPConnector(resolver=resolver)Unix domain sockets
^^^^^^^^^^^^^^^^^^^
If your HTTP server uses UNIX domain sockets you can use
:class:~aiohttp.UnixConnector::
conn = aiohttp.UnixConnector(path='/path/to/socket')
session = aiohttp.ClientSession(connector=conn)
Request URLs continue to work much the same as any other connector.
The protocol is still HTTP, therefore the http:// scheme should still be used.
While the connector always routes to the socket, the domain/port in the URL is
still used to create the Host header and must be included.
For example::
async with session.get('http://localhost/get') as resp:
...
Custom socket creation
^^^^^^^^^^^^^^^^^^^^^^
If the default socket is insufficient for your use case, pass an optionalsocket_factory to the :class:~aiohttp.TCPConnector, which implements
:class:SocketFactoryType. This will be used to create all sockets for the
lifetime of the class object. For example, we may want to change the
conditions under which we consider a connection dead. The following would
make all sockets respect 9*7200 = 18 hours::
import socket
def socket_factory(addr_info):
family, type_, proto, , _ = addr_info
sock = socket.socket(family=family, type=type, proto=proto)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, True)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 7200)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 9)
return sock
conn = aiohttp.TCPConnector(socket_factory=socket_factory)
socket_factory may also be used for binding to the specific network
interface on supported platforms::
def socket_factory(addr_info):
family, type_, proto, , _ = addr_info
sock = socket.socket(family=family, type=type, proto=proto)
sock.setsockopt(
socket.SOL_SOCKET, socket.SO_BINDTODEVICE, b'eth0'
)
return sock
conn = aiohttp.TCPConnector(socket_factory=socket_factory)
Named pipes in Windows
^^^^^^^^^^^^^^^^^^^^^^
If your HTTP server uses Named pipes you can use
:class:~aiohttp.NamedPipeConnector::
conn = aiohttp.NamedPipeConnector(path=r'\.\pipe<name-of-pipe>')
session = aiohttp.ClientSession(connector=conn)
It will only work with the ProactorEventLoop
SSL control for TCP sockets
By default aiohttp uses strict checks for HTTPS protocol. Certification
checks can be relaxed by setting ssl to False::
r = await session.get('https://example.com', ssl=False)
If you need to setup custom ssl parameters (use own certification
files for example) you can create a :class:ssl.SSLContext instance and
pass it into the :meth:ClientSession.request methods or set it for the
entire session with ClientSession(ssl=ssl_context).
There are explicit errors when ssl verification fails
:class:aiohttp.ClientConnectorSSLError::
try:
await session.get('https://expired.badssl.com/')
except aiohttp.ClientConnectorSSLError as e:
assert isinstance(e, ssl.SSLError)
:class:aiohttp.ClientConnectorCertificateError::
try:
await session.get('https://wrong.host.badssl.com/')
except aiohttp.ClientConnectorCertificateError as e:
assert isinstance(e, ssl.CertificateError)
If you need to skip both ssl related errors
:class:aiohttp.ClientSSLError::
try:
await session.get('https://expired.badssl.com/')
except aiohttp.ClientSSLError as e:
assert isinstance(e, ssl.SSLError)
try:
await session.get('https://wrong.host.badssl.com/')
except aiohttp.ClientSSLError as e:
assert isinstance(e, ssl.CertificateError)
Example: Use certifi
^^^^^^^^^^^^^^^^^^^^
By default, Python uses the system CA certificates. In rare cases, these may not be
installed or Python is unable to find them, resulting in a error likessl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate
One way to work around this problem is to use the certifi package::
ssl_context = ssl.create_default_context(cafile=certifi.where())
async with ClientSession(ssl=ssl_context) as sess:
...
Example: Use self-signed certificate
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you need to verify self-signed certificates, you need to add a call to
:meth:ssl.SSLContext.load_cert_chain with the key pair::
ssl_context = ssl.create_default_context()
ssl_context.load_cert_chain("/path/to/client/public/device.pem",
"/path/to/client/private/device.key")
async with sess.get("https://example.com", ssl=ssl_context) as resp:
...
Example: Verify certificate fingerprint
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You may also verify certificates via SHA256 fingerprint::
Attempt to connect to https://www.python.org
with a pin to a bogus certificate:
bad_fp = b'0'*64
exc = None
try:
r = await session.get('https://www.python.org',
ssl=aiohttp.Fingerprint(bad_fp))
except aiohttp.FingerprintMismatch as e:
exc = e
assert exc is not None
assert exc.expected == bad_fp
www.python.org cert's actual fingerprint
assert exc.got == b'...'
Note that this is the fingerprint of the DER-encoded certificate.
If you have the certificate in PEM format, you can convert it to
DER with e.g::
openssl x509 -in crt.pem -inform PEM -outform DER > crt.der
.. note::
Tip: to convert from a hexadecimal digest to a binary byte-string,
you can use :func:binascii.unhexlify.
ssl parameter could be passed to :class:ClientSession as the
session-wide default, the value from :meth:ClientSession.get and
others override it.
.. _aiohttp-client-proxy-support:
Proxy support
aiohttp supports plain HTTP proxies and HTTP proxies that can be
upgraded to HTTPS via the HTTP CONNECT method. aiohttp has a limited
support for proxies that must be connected to via https:// โ see
the info box below for more details.
To connect, use the proxy parameter::
async with aiohttp.ClientSession() as session:
async with session.get("http://python.org",
proxy="http://proxy.com") as resp:
print(resp.status)
It also supports proxy authorization::
from aiohttp import encode_basic_auth
async with aiohttp.ClientSession() as session:
proxy_headers = {"Proxy-Authorization": encode_basic_auth("user", "pass")}
async with session.get("http://python.org",
proxy="http://proxy.com",
proxy_headers=proxy_headers) as resp:
print(resp.status)
Authentication credentials can be passed in proxy URL::
session.get("http://python.org",
proxy="http://user:[email protected]")
And you may set default proxy::
proxy_headers = {"Proxy-Authorization": encode_basic_auth("user", "pass")}
async with aiohttp.ClientSession(
proxy="http://proxy.com", proxy_headers=proxy_headers
) as session:
async with session.get("http://python.org") as resp:
print(resp.status)
Contrary to the requests library, it won't read environment
variables by default. But you can do so by passingtrust_env=True into :class:aiohttp.ClientSession
constructor.::
async with aiohttp.ClientSession(trust_env=True) as session:
async with session.get("http://python.org") as resp:
print(resp.status)
.. note::
aiohttp uses :func:urllib.request.getproxies
for reading the proxy configuration (e.g. from the HTTP_PROXY etc. environment variables) and applies them for the HTTP, HTTPS, WS and WSS schemes.
Hosts defined in ``no_proxy`` will bypass the proxy.Proxy credentials are given from ~/.netrc file if present (see
:class:aiohttp.ClientSession for more details).
.. attention::
As of now (Python 3.10), support for TLS in TLS is disabled for the transports that
:py:mod:asyncio uses. If the further release of Python (say v3.11)
toggles one attribute, it'll just workโข.
aiohttp v3.8 and higher is ready for this to happen and has code in
place supports TLS-in-TLS, hence sending HTTPS requests over HTTPS
proxy tunnels.
โ ๏ธ For as long as your Python runtime doesn't declare the support for
TLS-in-TLS, please don't file bugs with aiohttp but rather try to
help the CPython upstream enable this feature. Meanwhile, if you
really need this to work, there's a patch that may help you make
it happen, include it into your app's code base:
https://github.com/aio-libs/aiohttp/discussions/6044#discussioncomment-1432443.
.. important::
When supplying a custom :py:class:ssl.SSLContext instance, bear in
mind that it will be used not only to establish a TLS session with
the HTTPS endpoint you're hitting but also to establish a TLS tunnel
to the HTTPS proxy. To avoid surprises, make sure to set up the trust
chain that would recognize TLS certificates used by both the endpoint
and the proxy.
.. _aiohttp-persistent-session:
Persistent session
Even though creating a session on demand seems like a tempting idea, we
advise against it. :class:aiohttp.ClientSession maintains a
connection pool. Contained connections can be reused if necessary to gain some
performance improvements. If you plan on reusing the session, a.k.a. creating
persistent session, you can use either :ref:aiohttp-web-signals or
:ref:aiohttp-web-cleanup-ctx. If possible we advise using :ref:aiohttp-web-cleanup-ctx,
as it results in more compact code::
session = aiohttp.web.AppKey("session", aiohttp.ClientSession)
@contextlib.asynccontextmanager
async def persistent_session(app):
app[persistent_session] = session = aiohttp.ClientSession()
yield
await session.close()
async def my_request_handler(request):
sess = request.app[session]
async with sess.get("http://python.org") as resp:
print(resp.status)
app.cleanup_ctx.append(persistent_session)This approach can be successfully used to define numerous sessions given certain
requirements. It benefits from having a single location where :class:aiohttp.ClientSession
instances are created and where artifacts such as :class:aiohttp.BaseConnector
can be safely shared between sessions if needed.
In the end all you have to do is to close all sessions after the yield statement::
async def multiple_sessions(app):
app[persistent_session_1] = session_1 = aiohttp.ClientSession()
app[persistent_session_2] = session_2 = aiohttp.ClientSession()
app[persistent_session_3] = session_3 = aiohttp.ClientSession()
yield
await asyncio.gather(
session_1.close(),
session_2.close(),
session_3.close(),
)Graceful Shutdown
When :class:ClientSession closes at the end of an async with
block (or through a direct :meth:ClientSession.close call), the
underlying connection remains open due to asyncio internal details. In
practice, the underlying connection will close after a short
while. However, if the event loop is stopped before the underlying
connection is closed, a ResourceWarning: unclosed transport
warning is emitted (when warnings are enabled).
To avoid this situation, a small delay must be added before closing
the event loop to allow any open underlying connections to close.
For a :class:ClientSession without SSL, a simple zero-sleep (await asyncio.sleep(0)) will suffice::
async def read_website():
async with aiohttp.ClientSession() as session:
async with session.get('http://example.org/') as resp:
await resp.read()
# Zero-sleep to allow underlying connections to close
await asyncio.sleep(0)For a :class:ClientSession with SSL, the application must wait a
short duration before closing::
...
# Wait 250 ms for the underlying SSL connections to close
await asyncio.sleep(0.250)Note that the appropriate amount of time to wait will vary from
application to application.
All of this will eventually become obsolete when the asyncio internals
are changed so that aiohttp itself can wait on the underlying
connection to close. Please follow issue #1925 <https://github.com/aio-libs/aiohttp/issues/1925>_ for the progress
on this.
HTTP Pipelining
aiohttp does not support HTTP/HTTPS pipelining.
Character Set Detection
If you encounter a :exc:UnicodeDecodeError when using :meth:ClientResponse.text
this may be because the response does not include the charset needed
to decode the body.
If you know the correct encoding for a request, you can simply specify
the encoding as a parameter (e.g. resp.text("windows-1252")).
Alternatively, :class:ClientSession accepts a fallback_charset_resolver parameter which
can be used to introduce charset guessing functionality. When a charset is not found
in the Content-Type header, this function will be called to get the charset encoding. For
example, this can be used with the chardetng_py library.::
from chardetng_py import detect
def charset_resolver(resp: ClientResponse, body: bytes) -> str:
tld = resp.url.host.rsplit(".", maxsplit=1)[-1]
return detect(body, allow_utf8=True, tld=tld.encode())
ClientSession(fallback_charset_resolver=charset_resolver)Or, if chardetng_py doesn't work for you, then charset-normalizer is another option::
from charset_normalizer import detect
ClientSession(fallback_charset_resolver=lambda r, b: detect(b)["encoding"] or "utf-8")File: docs/client_quickstart.rst
.. currentmodule:: aiohttp
.. _aiohttp-client-quickstart:
=================== Client Quickstart
Eager to get started? This page gives a good introduction in how to
get started with aiohttp client API.
First, make sure that aiohttp is :ref:installed <aiohttp-installation> and up-to-date
Let's get started with some simple examples.
Make a Request
Begin by importing the aiohttp module, and asyncio::
import aiohttp
import asyncioNow, let's try to get a web-page. For example let's queryhttp://httpbin.org/get::
async def main():
async with aiohttp.ClientSession() as session:
async with session.get('http://httpbin.org/get') as resp:
print(resp.status)
print(await resp.text())
asyncio.run(main())Now, we have a :class:ClientSession called session and a
:class:ClientResponse object called resp. We can get all the
information we need from the response. The mandatory parameter of
:meth:ClientSession.get coroutine is an HTTP url (:class:str or
class:yarl.URL instance).
In order to make an HTTP POST request use :meth:ClientSession.post coroutine::
session.post('http://httpbin.org/post', data=b'data')Other HTTP methods are available as well::
session.put('http://httpbin.org/put', data=b'data')
session.delete('http://httpbin.org/delete')
session.head('http://httpbin.org/get')
session.options('http://httpbin.org/get')
session.patch('http://httpbin.org/patch', data=b'data')To make several requests to the same site more simple, the parameter base_url
of :class:ClientSession constructor can be used. For example to request different
endpoints of http://httpbin.org can be used the following code::
async with aiohttp.ClientSession('http://httpbin.org') as session:
async with session.get('/get'):
pass
async with session.post('/post', data=b'data'):
pass
async with session.put('/put', data=b'data'):
pass.. note::
Don't create a session per request. Most likely you need a session
per application which performs all requests together.
More complex cases may require a session per site, e.g. one for
Github and other one for Facebook APIs. Anyway making a session for
every request is a very bad idea.
A session contains a connection pool inside. Connection reusage and
keep-alive (both are on by default) may speed up total performance.
You may find more information about creating persistent sessions
in :ref:aiohttp-persistent-session.
A session context manager usage is not mandatory
but await session.close() method
should be called in this case, e.g.::
session = aiohttp.ClientSession()
async with session.get('...'):
# ...
await session.close()Passing Parameters In URLs
You often want to send some sort of data in the URL's query string. If
you were constructing the URL by hand, this data would be given as key/value
pairs in the URL after a question mark, e.g. httpbin.org/get?key=val.
aiohttp allows you to provide these arguments as a :class:dict, using theparams keyword argument. As an example, if you wanted to passkey1=value1 and key2=value2 to httpbin.org/get, you would use the
following code::
params = {'key1': 'value1', 'key2': 'value2'}
async with session.get('http://httpbin.org/get',
params=params) as resp:
expect = 'http://httpbin.org/get?key1=value1&key2=value2'
assert str(resp.url) == expectYou can see that the URL has been correctly encoded by printing the URL.
For sending data with multiple values for the same key
:class:~multidict.MultiDict may be used; the library support nested lists
({'key': ['value1', 'value2']}) alternative as well.
It is also possible to pass a list of 2 item tuples as parameters, in
that case you can specify multiple values for each key::
params = [('key', 'value1'), ('key', 'value2')]
async with session.get('http://httpbin.org/get',
params=params) as r:
expect = 'http://httpbin.org/get?key=value2&key=value1'
assert str(r.url) == expectYou can also pass :class:str content as param. The value is used as a
query string, but passing params does not disable URL
canonicalization. Note that + is not encoded::
async with session.get('http://httpbin.org/get',
params='key=value+1') as r:
assert str(r.url) == 'http://httpbin.org/get?key=value+1'.. note::
aiohttp internally performs URL canonicalization before sending request.
Canonicalization encodes host part by :term:IDNA codec and applies
:term:requoting to path and query parts.
For example URL('http://example.com/ะฟััั/%30?a=%31') is converted to
URL('http://example.com/%D0%BF%D1%83%D1%82%D1%8C/0?a=1').
Sometimes canonicalization is not desirable if server accepts exact
representation and does not requote URL itself.
To disable canonicalization use encoded=True parameter for URL construction::
await session.get(
URL('http://example.com/%30', encoded=True)).. warning::
Passing params overrides encoded=True. Never use both options
if you need to preserve exact query-string bytes.
Build the full URL (including query) instead.
Response Content and Status Code
We can read the content of the server's response and its status
code. Consider the GitHub time-line again::
async with session.get('https://api.github.com/events') as resp:
print(resp.status)
print(await resp.text())prints out something like::
200
'[{"created_at":"2015-06-12T14:06:22Z","public":true,"actor":{...aiohttp automatically decodes the content from the server. You can
specify custom encoding for the :meth:~ClientResponse.text method::
await resp.text(encoding='windows-1251')Binary Response Content
You can also access the response body as bytes, for non-text requests::
print(await resp.read())::
b'[{"created_at":"2015-06-12T14:06:22Z","public":true,"actor":{...The gzip and deflate transfer-encodings are automatically
decoded for you.
You can enable brotli transfer-encodings support,
just install Brotli <https://pypi.org/project/Brotli/>_
or brotlicffi <https://pypi.org/project/brotlicffi/>_.
You can enable zstd transfer-encodings support,
install backports.zstd <https://pypi.org/project/backports.zstd/>_.
If you are using Python >= 3.14, no dependency should be required.
JSON Request
Any of session's request methods like :func:request,
:meth:ClientSession.get, :meth:ClientSession.post etc. acceptjson parameter::
async with aiohttp.ClientSession() as session:
await session.post(url, json={'test': 'object'})
By default session uses python's standard :mod:json module for
serialization. But it is possible to use a differentserializer. :class:ClientSession accepts json_serialize andjson_serialize_bytes parameters::
import orjson
async with aiohttp.ClientSession(
json_serialize_bytes=orjson.dumps) as session:
await session.post(url, json={'test': 'object'})
.. note::
orjson library is faster than standard :mod:json and is actively
maintained. Since orjson.dumps returns :class:bytes, pass it via
the json_serialize_bytes parameter to avoid unnecessary
encoding/decoding overhead.
JSON Response Content
There's also a built-in JSON decoder, in case you're dealing with JSON data::
async with session.get('https://api.github.com/events') as resp:
print(await resp.json())In case that JSON decoding fails, :meth:~ClientResponse.json will
raise an exception. It is possible to specify custom encoding and
decoder functions for the :meth:~ClientResponse.json call.
.. note::
The methods above reads the whole response body into memory. If you are
planning on reading lots of data, consider using the streaming response
method documented below.Streaming Response Content
While methods :meth:~ClientResponse.read,
:meth:~ClientResponse.json and :meth:~ClientResponse.text are very
convenient you should use them carefully. All these methods load the
whole response in memory. For example if you want to download several
gigabyte sized files, these methods will load all the data in
memory. Instead you can use the :attr:~ClientResponse.content
attribute. It is an instance of the :class:aiohttp.StreamReader
class. The gzip and deflate transfer-encodings are
automatically decoded for you::
async with session.get('https://api.github.com/events') as resp:
await resp.content.read(10)In general, however, you should use a pattern like this to save what is being
streamed to a file::
with open(filename, 'wb') as fd:
async for chunk in resp.content.iter_chunked(chunk_size):
fd.write(chunk)It is not possible to use :meth:~ClientResponse.read,
:meth:~ClientResponse.json and :meth:~ClientResponse.text after
explicit reading from :attr:~ClientResponse.content.
More complicated POST requests
Typically, you want to send some form-encoded data -- much like an HTML form.
To do this, simply pass a dictionary to the data argument. Your
dictionary of data will automatically be form-encoded when the request is made::
payload = {'key1': 'value1', 'key2': 'value2'}
async with session.post('http://httpbin.org/post',
data=payload) as resp:
print(await resp.text())::
{
...
"form": {
"key2": "value2",
"key1": "value1"
},
...
}If you want to send data that is not form-encoded you can do it by
passing a :class:bytes instead of a :class:dict. This data will be
posted directly and content-type set to 'application/octet-stream' by
default::
async with session.post(url, data=b'\x00Binary-data\x00') as resp:
...If you want to send JSON data::
async with session.post(url, json={'example': 'test'}) as resp:
...To send text with appropriate content-type just use data argument::
async with session.post(url, data='ะขะตัั') as resp:
...POST a Multipart-Encoded File
To upload Multipart-encoded files::
url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}
await session.post(url, data=files)You can set the filename and content_type explicitly::
url = 'http://httpbin.org/post'
data = aiohttp.FormData()
data.add_field('file',
open('report.xls', 'rb'),
filename='report.xls',
content_type='application/vnd.ms-excel')
await session.post(url, data=data)If you pass a file object as data parameter, aiohttp will stream it to
the server automatically. Check :class:~aiohttp.StreamReader
for supported format information.
.. seealso:: :ref:aiohttp-multipart
Streaming uploads
:mod:aiohttp supports multiple types of streaming uploads, which allows you to
send large files without reading them into memory.
As a simple case, simply provide a file-like object for your body::
with open("massive-body", "rb") as f:
await session.post("https://httpbin.org/post", data=f)Or you can provide an asynchronous generator, for example to generate
data on the fly::
async def data_generator():
for i in range(10):
yield f"line {i}\n".encode()
async with session.post("https://httpbin.org/post",
data=data_generator()) as resp:
print(await resp.text())
.. warning::
Async generators and other non-rewindable data sources
(such as :class:~aiohttp.StreamReader) cannot be replayed if a
redirect occurs (for example, HTTP 307 or 308). If the request body
has already been streamed, :mod:aiohttp raises
:class:~aiohttp.ClientPayloadError.
If your endpoint may redirect, either:
- Pass a seekable file-like object or :class:
bytes. - Disable redirects with
allow_redirects=Falseand handle them manually.
Because the :attr:~aiohttp.ClientResponse.content attribute is a
:class:~aiohttp.StreamReader (provides async iterator protocol), you
can chain get and post requests together::
resp = await session.get('http://python.org')
await session.post('http://httpbin.org/post',
data=resp.content)
.. _aiohttp-client-websockets:
WebSockets
:mod:aiohttp works with client websockets out-of-the-box.
You have to use the :meth:aiohttp.ClientSession.ws_connect coroutine
for client websocket connection. It accepts a url as a first
parameter and returns :class:ClientWebSocketResponse, with that
object you can communicate with websocket server using response's
methods::
async with session.ws_connect('http://example.org/ws') as ws:
async for msg in ws:
if msg.type == aiohttp.WSMsgType.TEXT:
if msg.data == 'close cmd':
await ws.close()
break
else:
await ws.send_str(msg.data + '/answer')
elif msg.type == aiohttp.WSMsgType.ERROR:
break
You must use the only websocket task for both reading (e.g. await ws.receive() or async for msg in ws:) and writing but may have
multiple writer tasks which can only send data asynchronously (byawait ws.send_str('data') for example).
.. _aiohttp-client-timeouts:
Timeouts
Timeout settings are stored in :class:ClientTimeout data structure.
By default aiohttp uses a total 300 seconds (5min) timeout, it means that the
whole operation should finish in 5 minutes. In order to allow time for DNS fallback,
the default sock_connect timeout is 30 seconds.
The value could be overridden by timeout parameter for the session (specified in seconds)::
timeout = aiohttp.ClientTimeout(total=60)
async with aiohttp.ClientSession(timeout=timeout) as session:
...Timeout could be overridden for a request like :meth:ClientSession.get::
async with session.get(url, timeout=timeout) as resp:
...Supported :class:ClientTimeout fields are:
total
The maximal number of seconds for the whole operation including connection
establishment, request sending and response reading. connect
The maximal number of seconds for
connection establishment of a new connection or
for waiting for a free connection from a pool if pool connection
limits are exceeded. sock_connect
The maximal number of seconds for connecting to a peer for a new connection, not
given from a pool. sock_read
The maximal number of seconds allowed for period between reading a new
data portion from a peer.
``ceil_threshold``
The threshold value to trigger ceiling of absolute timeout values.All fields are floats, None or 0 disables a particular timeout check, see the
:class:ClientTimeout reference for defaults and additional details.
Thus the default timeout is::
aiohttp.ClientTimeout(total=5*60, connect=None,
sock_connect=None, sock_read=None, ceil_threshold=5)
.. note::
aiohttp ceils timeout if the value is equal or greater than 5
seconds. The timeout expires at the next integer second greater than
current_time + timeout.
The ceiling is done for the sake of optimization, when many concurrent tasks
are scheduled to wake-up at the almost same but different absolute times. It
leads to very many event loop wakeups, which kills performance.
The optimization shifts absolute wakeup times by scheduling them to exactly
the same time as other neighbors, the loop wakes up once-per-second for
timeout expiration.
Smaller timeouts are not rounded to help testing; in the real life network
timeouts usually greater than tens of seconds. However, the default threshold
value of 5 seconds can be configured using the ceil_threshold parameter.
File: docs/client_reference.rst
.. _aiohttp-client-reference:
Client Reference
.. currentmodule:: aiohttp
Client Session
Client session is the recommended interface for making HTTP requests.
Session encapsulates a connection pool (connector instance) and
supports keepalives by default. Unless you are connecting to a large,
unknown number of different servers over the lifetime of your
application, it is suggested you use a single session for the
lifetime of your application to benefit from connection pooling.
Usage example::
import aiohttp
import asyncio
async def fetch(client):
async with client.get('http://python.org') as resp:
assert resp.status == 200
return await resp.text()
async def main():
async with aiohttp.ClientSession() as client:
html = await fetch(client)
print(html)
asyncio.run(main())The client session supports the context manager protocol for self closing.
.. class:: ClientSession(base_url=None, *,
connector=None, cookies=None,
headers=None, skip_auto_headers=None,
json_serialize=json.dumps,
request_class=ClientRequest,
response_class=ClientResponse,
ws_response_class=ClientWebSocketResponse,
version=aiohttp.HttpVersion11,
cookie_jar=None,
connector_owner=True,
raise_for_status=False,
timeout=sentinel,
auto_decompress=True,
ssl=True,
trust_env=False,
requote_redirect_url=True,
trace_configs=None,
middlewares=(),
read_bufsize=2**18,
max_line_size=8190,
max_field_size=8190,
max_headers=128,
fallback_charset_resolver=lambda r, b: "utf-8",
ssl_shutdown_timeout=0)
:canonical: aiohttp.client.ClientSession
The class for creating client sessions and making requests.
:param base_url: Base part of the URL (optional)
If set, allows to join a base part to relative URLs in request calls.
If the URL has a path it must have a trailing / (as in
https://docs.aiohttp.org/en/stable/).
Note that URL joining follows :rfc:`3986`. This means, in the most
common case the request URLs should have no leading slash, e.g.::
session = ClientSession(base_url="http://example.com/foo/")
await session.request("GET", "bar")
# request for http://example.com/foo/bar
await session.request("GET", "/bar")
# request for http://example.com/bar
.. versionadded:: 3.8
.. versionchanged:: 3.12
Added support for overriding the base URL with an absolute one in client sessions. :param aiohttp.BaseConnector connector: BaseConnector
sub-class instance to support connection pooling.
:param dict cookies: Cookies to send with the request (optional)
:param headers: HTTP Headers to send with every request (optional).
May be either *iterable of key-value pairs* or
:class:`~collections.abc.Mapping`
(e.g. :class:`dict`,
:class:`~multidict.CIMultiDict`). :param skip_auto_headers: set of headers for which autogeneration
should be skipped.
*aiohttp* autogenerates headers like ``User-Agent`` or
``Content-Type`` if these headers are not explicitly
passed. Using ``skip_auto_headers`` parameter allows to skip
that generation. Note that ``Content-Length`` autogeneration can't
be skipped.
Iterable of :class:`str` or :class:`~multidict.istr` (optional):param collections.abc.Callable json_serialize: Json serializer callable.
By default :func:`json.dumps` function.:param aiohttp.ClientRequest request_class: Custom class to use for client requests.
:param ClientResponse response_class: Custom class to use for client responses.
:param ClientWebSocketResponse ws_response_class: Custom class to use for websocket responses.
:param version: supported HTTP version, HTTP 1.1 by default.
:param cookie_jar: Cookie Jar, :class:~aiohttp.abc.AbstractCookieJar instance.
By default every session instance has own private cookie jar for
automatic cookies processing but user may redefine this behavior
by providing own jar implementation.
One example is not processing cookies at all when working in
proxy mode.
If no cookie processing is needed, a
:class:`aiohttp.DummyCookieJar` instance can be
provided.:param bool connector_owner:
Close connector instance on session closing.
Setting the parameter to ``False`` allows to share
connection pool between sessions without sharing session state:
cookies etc.:param bool raise_for_status:
Automatically call :meth:`ClientResponse.raise_for_status` for
each response, ``False`` by default.
This parameter can be overridden when making a request, e.g.::
client_session = aiohttp.ClientSession(raise_for_status=True)
resp = await client_session.get(url, raise_for_status=False)
async with resp:
assert resp.status == 200
Set the parameter to ``True`` if you need ``raise_for_status``
for most of cases but override ``raise_for_status`` for those
requests where you need to handle responses with status 400 or
higher. :param timeout: a :class:ClientTimeout settings structure, 300 seconds (5min)
total timeout, 30 seconds socket connect timeout by default.
.. versionadded:: 3.3
.. versionchanged:: 3.10.9
The default value for the ``sock_connect`` timeout has been changed to 30 seconds. :param bool auto_decompress: Automatically decompress response body (True by default).
.. versionadded:: 2.3 :param ssl: Default SSL validation mode for requests made through this
session. True for default SSL check
(:func:ssl.create_default_context is used),
False for skip SSL certificate validation,
:class:aiohttp.Fingerprint for fingerprint
validation, :class:ssl.SSLContext for custom SSL
certificate validation (True by default).
A per-request ``ssl`` argument overrides this value.
.. versionadded:: 3.15 :param bool trust_env: Trust environment settings for proxy configuration if the parameter
is True (False by default). See :ref:aiohttp-client-proxy-support for
more information.
Get proxy credentials from ``~/.netrc`` file if present.
Get HTTP Basic Auth credentials from :file:`~/.netrc` file if present.
If :envvar:`NETRC` environment variable is set, read from file specified
there rather than from :file:`~/.netrc`.
.. seealso::
``.netrc`` documentation: https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html
.. versionadded:: 2.3
.. versionchanged:: 3.0
Added support for ``~/.netrc`` file.
.. versionchanged:: 3.9
Added support for reading HTTP Basic Auth credentials from :file:`~/.netrc` file. :param bool requote_redirect_url: Apply URL requoting for redirection URLs if
automatic redirection is enabled (True by
default).
.. versionadded:: 3.5 :param trace_configs: A list of :class:TraceConfig instances used for client
tracing. None (default) is used for request tracing
disabling. See :ref:aiohttp-client-tracing-reference for
more information.
:param middlewares: A sequence of middleware instances to apply to all session requests.
Each middleware must match the :type:ClientMiddlewareType signature.
() (empty tuple, default) is used when no middleware is needed.
See :ref:aiohttp-client-middleware for more information.
.. versionadded:: 3.12 :param int read_bufsize: Size of the read buffer (:attr:ClientResponse.content).
256 KiB by default. On a WebSocket connection it
also bounds what is buffered between the handshake
and the reader being installed.
.. versionadded:: 3.7:param int max_line_size: Maximum allowed size of lines in responses.
:param int max_field_size: Maximum allowed size of header name and value combined in responses.
:param int max_headers: Maximum number of headers and trailers combined in responses.
:param Callable[[ClientResponse,bytes],str] fallback_charset_resolver:
A :term:callable that accepts a :class:ClientResponse and the
:class:bytes contents, and returns a :class:str which will be used as
the encoding parameter to :meth:bytes.decode().
This function will be called when the charset is not known (e.g. not specified in the
Content-Type header). The default function simply defaults to ``utf-8``.
.. versionadded:: 3.8.6 :param float ssl_shutdown_timeout: (DEPRECATED) This parameter is deprecated
and will be removed in aiohttp 4.0. Grace period for SSL shutdown handshake on
TLS connections when the connector is closed (0 seconds by default).
By default (0), SSL connections are aborted immediately when the
connector is closed, without performing the shutdown handshake. During
normal operation, SSL connections use Python's default SSL shutdown
behavior. Setting this to a positive value (e.g., 0.1) will perform
a graceful shutdown when closing the connector, notifying the remote
peer which can help prevent "connection reset" errors at the cost of
additional cleanup time. This timeout is passed to the underlying
:class:TCPConnector when one is created automatically.
Note: On Python versions prior to 3.11, only a value of 0 is supported;
other values will trigger a warning.
.. versionadded:: 3.12.5
.. versionchanged:: 3.12.11
Changed default from ``0.1`` to ``0`` to abort SSL connections
immediately when the connector is closed. Added support for
``ssl_shutdown_timeout=0`` on all Python versions. A :exc:`RuntimeWarning`
is issued when non-zero values are passed on Python < 3.11.
.. deprecated:: 3.12.11
This parameter is deprecated and will be removed in aiohttp 4.0... attribute:: closed
``True`` if the session has been closed, ``False`` otherwise.
A read-only property... attribute:: connector
:class:`aiohttp.BaseConnector` derived instance used
for the session.
A read-only property... attribute:: cookie_jar
The session cookies, :class:`~aiohttp.abc.AbstractCookieJar` instance.
Gives access to cookie jar's content and modifiers.
A read-only property... attribute:: requote_redirect_url
aiohttp re quote's redirect urls by default, but some servers
require exact url from location header. To disable *re-quote* system
set :attr:`requote_redirect_url` attribute to ``False``.
.. versionadded:: 2.1
.. note:: This parameter affects all subsequent requests.
.. deprecated:: 3.5
The attribute modification is deprecated... attribute:: loop
A loop instance used for session creation.
A read-only property.
.. deprecated:: 3.5.. attribute:: timeout
Default client timeouts, :class:`ClientTimeout` instance. The value can
be tuned by passing *timeout* parameter to :class:`ClientSession`
constructor.
.. versionadded:: 3.7.. attribute:: headers
HTTP Headers that sent with every request
May be either *iterable of key-value pairs* or
:class:`~collections.abc.Mapping`
(e.g. :class:`dict`,
:class:`~multidict.CIMultiDict`).
.. versionadded:: 3.7.. attribute:: skip_auto_headers
Set of headers for which autogeneration skipped.
:class:`frozenset` of :class:`str` or :class:`~multidict.istr` (optional)
.. versionadded:: 3.7.. attribute:: json_serialize
Json serializer callable.
By default :func:`json.dumps` function.
.. versionadded:: 3.7.. attribute:: connector_owner
Should connector be closed on session closing
:class:`bool` (optional)
.. versionadded:: 3.7.. attribute:: raise_for_status
Should :meth:`ClientResponse.raise_for_status` be called for each response
Either :class:`bool` or :class:`collections.abc.Callable`
.. versionadded:: 3.7.. attribute:: auto_decompress
Should the body response be automatically decompressed
:class:`bool` default is ``True``
.. versionadded:: 3.7.. attribute:: trust_env
Trust environment settings for proxy configuration
or ~/.netrc file if present. See :ref:`aiohttp-client-proxy-support` for
more information.
:class:`bool` default is ``False``
.. versionadded:: 3.7.. attribute:: trace_configs
A list of :class:`TraceConfig` instances used for client
tracing. ``None`` (default) is used for request tracing
disabling. See :ref:`aiohttp-client-tracing-reference` for more information.
.. versionadded:: 3.7 .. method:: request(method, url, *, params=None, data=None, json=None,
cookies=None, headers=None, skip_auto_headers=None,
allow_redirects=True,
max_redirects=10,
compress=None, chunked=None, expect100=False, raise_for_status=None,
read_until_eof=True,
proxy=None,
timeout=sentinel, ssl=True,
server_hostname=None,
proxy_headers=None,
trace_request_ctx=None,
middlewares=None,
read_bufsize=None,
auto_decompress=None,
max_line_size=None,
max_field_size=None,
max_headers=None)
:async:
:noindexentry:
Performs an asynchronous HTTP request. Returns a response object that
should be used as an async context manager.
:param str method: HTTP method
:param url: Request URL, :class:`~yarl.URL` or :class:`str` that will
be encoded with :class:`~yarl.URL` (see :class:`~yarl.URL`
to skip encoding).
:param params: Mapping, iterable of tuple of *key*/*value* pairs or
string to be sent as parameters in the query
string of the new request. Ignored for subsequent
redirected requests (optional)
Allowed values are:
- :class:`collections.abc.Mapping` e.g. :class:`dict`,
:class:`multidict.MultiDict` or
:class:`multidict.MultiDictProxy`
- :class:`collections.abc.Iterable` e.g. :class:`tuple` or
:class:`list`
- :class:`str` with preferably url-encoded content
(**Warning:** content will not be encoded by *aiohttp*)
:param data: The data to send in the body of the request. This can be a
:class:`FormData` object or anything that can be passed into
:class:`FormData`, e.g. a dictionary, bytes, or file-like object.
(optional)
:param json: Any json compatible python object
(optional). *json* and *data* parameters could not
be used at the same time.
:param dict cookies: HTTP Cookies to send with
the request (optional)
Global session cookies and the explicitly set cookies will be merged
when sending the request.
.. versionadded:: 3.5
:param dict headers: HTTP Headers to send with
the request (optional)
:param skip_auto_headers: set of headers for which autogeneration
should be skipped.
*aiohttp* autogenerates headers like ``User-Agent`` or
``Content-Type`` if these headers are not explicitly
passed. Using ``skip_auto_headers`` parameter allows to skip
that generation.
Iterable of :class:`str` or :class:`~multidict.istr`
(optional)
:param bool allow_redirects: Whether to process redirects or not.
When ``True``, redirects are followed (up to ``max_redirects`` times)
and logged into :attr:`ClientResponse.history` and ``trace_configs``.
When ``False``, the original response is returned.
``True`` by default (optional).
:param int max_redirects: Maximum number of redirects to follow.
:exc:`TooManyRedirects` is raised if the number is exceeded.
``0`` means no limit, redirects are followed until the request
times out. Use ``allow_redirects=False`` to not follow redirects at all.
Ignored when ``allow_redirects=False``.
``10`` by default.
:param bool compress: Set to ``True`` if request has to be compressed
with deflate encoding. If `compress` can not be combined
with a *Content-Encoding* and *Content-Length* headers.
``None`` by default (optional).
:param int chunked: Enable chunked transfer encoding.
It is up to the developer
to decide how to chunk data streams. If chunking is enabled, aiohttp
encodes the provided chunks in the "Transfer-encoding: chunked" format.
If *chunked* is set, then the *Transfer-encoding* and *content-length*
headers are disallowed. ``None`` by default (optional).
:param bool expect100: Expect 100-continue response from server.
``False`` by default (optional).
:param bool raise_for_status: Automatically call :meth:`ClientResponse.raise_for_status` for
response if set to ``True``.
If set to ``None`` value from ``ClientSession`` will be used.
``None`` by default (optional).
.. versionadded:: 3.4
:param bool read_until_eof: Read response until EOF if response
does not have Content-Length header.
``True`` by default (optional).
:param proxy: Proxy URL, :class:`str` or :class:`~yarl.URL` (optional)
:param int timeout: override the session's timeout.
.. versionchanged:: 3.3
The parameter is :class:`ClientTimeout` instance,
:class:`float` is still supported for sake of backward
compatibility.
If :class:`float` is passed it is a *total* timeout (in seconds).
:param ssl: SSL validation mode. ``True`` for default SSL check
(:func:`ssl.create_default_context` is used),
``False`` for skip SSL certificate validation,
:class:`aiohttp.Fingerprint` for fingerprint
validation, :class:`ssl.SSLContext` for custom SSL
certificate validation.
Supersedes *verify_ssl*, *ssl_context* and
*fingerprint* parameters.
When not given, the session's ``ssl`` value is used
(``True`` unless set).
.. versionadded:: 3.0
.. versionchanged:: 3.15
Defaults to the session's ``ssl`` value.
:param str server_hostname: Sets or overrides the host name that the
target server's certificate will be matched against.
See :py:meth:`asyncio.loop.create_connection` for more information.
.. versionadded:: 3.9
:param collections.abc.Mapping proxy_headers: HTTP headers to send to the proxy if the
parameter proxy has been provided.
.. versionadded:: 2.3
:param trace_request_ctx: Object used to give as a kw param for each new
:class:`TraceConfig` object instantiated,
used to give information to the
tracers that is only available at request time.
.. versionadded:: 3.0
:param middlewares: A sequence of middleware instances to apply to this request only.
Each middleware must match the :type:`ClientMiddlewareType` signature.
``None`` by default which uses session middlewares.
See :ref:`aiohttp-client-middleware` for more information.
.. versionadded:: 3.12
:param upload_tracker: An :class:`UploadTracker` instance observing
this request's body upload.
``None`` by default (no tracking).
.. versionadded:: 3.14.4
:param int read_bufsize: Size of the read buffer (:attr:`ClientResponse.content`).
``None`` by default,
it means that the session global value is used.
.. versionadded:: 3.7
:param bool auto_decompress: Automatically decompress response body.
Overrides :attr:`ClientSession.auto_decompress`.
May be used to enable/disable auto decompression on a per-request basis.
:param int max_line_size: Maximum allowed size of lines in responses.
:param int max_field_size: Maximum allowed size of header name and value combined in responses.
:param int max_headers: Maximum number of headers and trailers combined in responses.
:return ClientResponse: a :class:`client response <ClientResponse>`
object. .. method:: get(url, *, allow_redirects=True, **kwargs)
:async:
Perform a ``GET`` request. Returns an async context manager.
In order to modify inner
:meth:`request<aiohttp.ClientSession.request>`
parameters, provide `kwargs`.
:param url: Request URL, :class:`str` or :class:`~yarl.URL`
:param bool allow_redirects: Whether to process redirects or not.
When ``True``, redirects are followed and logged into
:attr:`ClientResponse.history`.
When ``False``, the original response is returned.
``True`` by default (optional).
:return ClientResponse: a :class:`client response
<ClientResponse>` object. .. method:: post(url, *, data=None, **kwargs)
:async:
Perform a ``POST`` request. Returns an async context manager.
In order to modify inner
:meth:`request<aiohttp.ClientSession.request>`
parameters, provide `kwargs`.
:param url: Request URL, :class:`str` or :class:`~yarl.URL`
:param data: Data to send in the body of the request; see
:meth:`request<aiohttp.ClientSession.request>`
for details (optional)
:return ClientResponse: a :class:`client response
<ClientResponse>` object. .. method:: put(url, *, data=None, **kwargs)
:async:
Perform a ``PUT`` request. Returns an async context manager.
In order to modify inner
:meth:`request<aiohttp.ClientSession.request>`
parameters, provide `kwargs`.
:param url: Request URL, :class:`str` or :class:`~yarl.URL`
:param data: Data to send in the body of the request; see
:meth:`request<aiohttp.ClientSession.request>`
for details (optional)
:return ClientResponse: a :class:`client response
<ClientResponse>` object. .. method:: delete(url, **kwargs)
:async:
Perform a ``DELETE`` request. Returns an async context manager.
In order to modify inner
:meth:`request<aiohttp.ClientSession.request>`
parameters, provide `kwargs`.
:param url: Request URL, :class:`str` or :class:`~yarl.URL`
:return ClientResponse: a :class:`client response
<ClientResponse>` object. .. method:: head(url, *, allow_redirects=False, **kwargs)
:async:
Perform a ``HEAD`` request. Returns an async context manager.
In order to modify inner
:meth:`request<aiohttp.ClientSession.request>`
parameters, provide `kwargs`.
:param url: Request URL, :class:`str` or :class:`~yarl.URL`
:param bool allow_redirects: Whether to process redirects or not.
When ``True``, redirects are followed and logged into
:attr:`ClientResponse.history`.
When ``False``, the original response is returned.
``False`` by default (optional).
:return ClientResponse: a :class:`client response
<ClientResponse>` object. .. method:: options(url, *, allow_redirects=True, **kwargs)
:async:
Perform an ``OPTIONS`` request. Returns an async context manager.
In order to modify inner
:meth:`request<aiohttp.ClientSession.request>`
parameters, provide `kwargs`.
:param url: Request URL, :class:`str` or :class:`~yarl.URL`
:param bool allow_redirects: Whether to process redirects or not.
When ``True``, redirects are followed and logged into
:attr:`ClientResponse.history`.
When ``False``, the original response is returned.
``True`` by default (optional).
:return ClientResponse: a :class:`client response
<ClientResponse>` object. .. method:: patch(url, *, data=None, **kwargs)
:async:
Perform a ``PATCH`` request. Returns an async context manager.
In order to modify inner
:meth:`request<aiohttp.ClientSession.request>`
parameters, provide `kwargs`.
:param url: Request URL, :class:`str` or :class:`~yarl.URL`
:param data: Data to send in the body of the request; see
:meth:`request<aiohttp.ClientSession.request>`
for details (optional)
:return ClientResponse: a :class:`client response
<ClientResponse>` object. .. method:: ws_connect(url, *, method='GET',
protocols=(),
timeout=sentinel,
autoclose=True,
autoping=True,
heartbeat=None,
origin=None,
params=None,
headers=None,
proxy=None, ssl=True,
verify_ssl=None, fingerprint=None,
ssl_context=None, proxy_headers=None,
compress=0, max_msg_size=4194304,
decode_text=True)
:async:
Create a websocket connection. Returns a
:class:`ClientWebSocketResponse` async context manager object.
:param url: Websocket server url, :class:`~yarl.URL` or :class:`str` that
will be encoded with :class:`~yarl.URL` (see :class:`~yarl.URL`
to skip encoding).
:param tuple protocols: Websocket protocols
:param timeout: a :class:`ClientWSTimeout` timeout for websocket.
By default, the value
`ClientWSTimeout(ws_receive=None, ws_close=10.0)` is used
(``10.0`` seconds for the websocket to close).
``None`` means no timeout will be used.
:param bool autoclose: Automatically close websocket connection on close
message from server. If *autoclose* is False
then close procedure has to be handled manually.
``True`` by default
:param bool autoping: automatically send *pong* on *ping*
message from server. ``True`` by default
:param float heartbeat: Send *ping* message every *heartbeat*
seconds and wait *pong* response, if
*pong* response is not received then
close connection. The timer is reset on any
inbound data reception (coalesced per event loop
iteration). (optional)
:param str origin: Origin header to send to server(optional)
:param params: Mapping, iterable of tuple of *key*/*value* pairs or
string to be sent as parameters in the query
string of the new request. Ignored for subsequent
redirected requests (optional)
Allowed values are:
- :class:`collections.abc.Mapping` e.g. :class:`dict`,
:class:`multidict.MultiDict` or
:class:`multidict.MultiDictProxy`
- :class:`collections.abc.Iterable` e.g. :class:`tuple` or
:class:`list`
- :class:`str` with preferably url-encoded content
(**Warning:** content will not be encoded by *aiohttp*)
:param dict headers: HTTP Headers to send with
the request (optional)
:param str proxy: Proxy URL, :class:`str` or :class:`~yarl.URL` (optional)
:param ssl: SSL validation mode. ``True`` for default SSL check
(:func:`ssl.create_default_context` is used),
``False`` for skip SSL certificate validation,
:class:`aiohttp.Fingerprint` for fingerprint
validation, :class:`ssl.SSLContext` for custom SSL
certificate validation.
Supersedes *verify_ssl*, *ssl_context* and
*fingerprint* parameters.
When not given, the session's ``ssl`` value is used
(``True`` unless set).
.. versionadded:: 3.0
.. versionchanged:: 3.15
Defaults to the session's ``ssl`` value.
:param bool verify_ssl: Perform SSL certificate validation for
*HTTPS* requests (enabled by default). May be disabled to
skip validation for sites with invalid certificates.
.. versionadded:: 2.3
.. deprecated:: 3.0
Use ``ssl=False``
:param bytes fingerprint: Pass the SHA256 digest of the expected
certificate in DER format to verify that the certificate the
server presents matches. Useful for `certificate pinning
<https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning>`_.
Note: use of MD5 or SHA1 digests is insecure and deprecated.
.. versionadded:: 2.3
.. deprecated:: 3.0
Use ``ssl=aiohttp.Fingerprint(digest)``
:param ssl.SSLContext ssl_context: ssl context used for processing
*HTTPS* requests (optional).
*ssl_context* may be used for configuring certification
authority channel, supported SSL options etc.
.. versionadded:: 2.3
.. deprecated:: 3.0
Use ``ssl=ssl_context``
:param dict proxy_headers: HTTP headers to send to the proxy if the
parameter proxy has been provided.
.. versionadded:: 2.3
:param int compress: Enable Per-Message Compress Extension support.
0 for disable, 9 to 15 for window bit support.
Default value is 0.
.. versionadded:: 2.3
:param int max_msg_size: maximum size of read websocket message,
4 MB by default. To disable the size
limit use ``0``.
.. versionadded:: 3.3
:param str method: HTTP method to establish WebSocket connection,
``'GET'`` by default.
.. versionadded:: 3.5
:param bool decode_text: If ``True`` (default), TEXT messages are
decoded to strings. If ``False``, TEXT messages
are returned as raw bytes, which can improve
performance when using JSON parsers like
``orjson`` that accept bytes directly.
.. versionadded:: 3.14 .. method:: close()
:async:
Close underlying connector.
Release all acquired resources... method:: detach()
Detach connector from session without closing the former.
Session is switched to closed state anyway.Basic API
While we encourage :class:ClientSession usage we also provide simple
coroutines for making HTTP requests.
Basic API is good for performing simple HTTP requests without
keepaliving, cookies and complex connection stuff like properly configured SSL
certification chaining.
.. function:: request(method, url, *, params=None, data=None,
json=None,
cookies=None, headers=None, skip_auto_headers=None,
allow_redirects=True, max_redirects=10,
compress=False, chunked=None, expect100=False, raise_for_status=None,
read_until_eof=True,
proxy=None,
timeout=sentinel, ssl=True,
server_hostname=None,
proxy_headers=None,
trace_request_ctx=None,
read_bufsize=None,
auto_decompress=None,
max_line_size=None,
max_field_size=None,
max_headers=None,
version=aiohttp.HttpVersion11,
connector=None)
:canonical: aiohttp.client.request
:async:
Asynchronous context manager for performing an asynchronous HTTP
request. Returns a :class:ClientResponse response object. Use as
an async context manager.
:param str method: HTTP method
:param url: Request URL, :class:~yarl.URL or :class:str that will
be encoded with :class:~yarl.URL (see :class:~yarl.URL
to skip encoding).
:param params: Mapping, iterable of tuple of key/value pairs or
string to be sent as parameters in the query
string of the new request. Ignored for subsequent
redirected requests (optional)
Allowed values are:
- :class:`collections.abc.Mapping` e.g. :class:`dict`,
:class:`multidict.MultiDict` or
:class:`multidict.MultiDictProxy`
- :class:`collections.abc.Iterable` e.g. :class:`tuple` or
:class:`list`
- :class:`str` with preferably url-encoded content
(**Warning:** content will not be encoded by *aiohttp*) :param data: The data to send in the body of the request. This can be a
:class:FormData object or anything that can be passed into
:class:FormData, e.g. a dictionary, bytes, or file-like object.
(optional)
:param json: Any json compatible python object (optional). json and data
parameters could not be used at the same time.
:param dict cookies: HTTP Cookies to send with the request (optional)
:param dict headers: HTTP Headers to send with the request (optional)
:param skip_auto_headers: set of headers for which autogeneration
should be skipped.
*aiohttp* autogenerates headers like ``User-Agent`` or
``Content-Type`` if these headers are not explicitly
passed. Using ``skip_auto_headers`` parameter allows to skip
that generation.
Iterable of :class:`str` or :class:`~multidict.istr`
(optional) :param bool allow_redirects: Whether to process redirects or not.
When True, redirects are followed (up to max_redirects times)
and logged into :attr:ClientResponse.history and trace_configs.
When False, the original response is returned.
True by default (optional).
:param int max_redirects: Maximum number of redirects to follow.
:exc:TooManyRedirects is raised if the number is exceeded.
0 means no limit, redirects are followed until the request
times out. Use allow_redirects=False to not follow redirects at all.
Ignored when allow_redirects=False.
10 by default.
:param compress: Set to True to compress the request body with
deflate encoding, or pass "deflate" or "gzip"
explicitly to choose the content encoding. False by
default.
This parameter cannot be combined with
*Content-Encoding* or *Content-Length* headers. :param int chunked: Enables chunked transfer encoding.
It is up to the developer
to decide how to chunk data streams. If chunking is enabled, aiohttp
encodes the provided chunks in the "Transfer-encoding: chunked" format.
If chunked is set, then the Transfer-encoding and content-length
headers are disallowed. None by default (optional).
:param bool expect100: Expect 100-continue response from server.
False by default (optional).
:param bool raise_for_status: Automatically call
:meth:ClientResponse.raise_for_status
for response if set to True. If
set to None value from
ClientSession will be used.
None by default (optional).
.. versionadded:: 3.4 :param bool read_until_eof: Read response until EOF if response
does not have Content-Length header.
True by default (optional).
:param proxy: Proxy URL, :class:str or :class:~yarl.URL (optional)
:param timeout: a :class:ClientTimeout settings structure, 300 seconds (5min)
total timeout, 30 seconds socket connect timeout by default.
:param ssl: SSL validation mode. True for default SSL check
(:func:ssl.create_default_context is used),
False for skip SSL certificate validation,
:class:aiohttp.Fingerprint for fingerprint
validation, :class:ssl.SSLContext for custom SSL
certificate validation.
Supersedes *verify_ssl*, *ssl_context* and
*fingerprint* parameters. :param str server_hostname: Sets or overrides the host name that the
target server's certificate will be matched against.
See :py:meth:`asyncio.loop.create_connection`
for more information. :param collections.abc.Mapping proxy_headers: HTTP headers to send to the proxy
if the parameter proxy has been provided.
:param trace_request_ctx: Object used to give as a kw param for each new
:class:TraceConfig object instantiated,
used to give information to the
tracers that is only available at request time.
:param int read_bufsize: Size of the read buffer (:attr:ClientResponse.content).
None by default,
it means that the session global value is used.
.. versionadded:: 3.7 :param bool auto_decompress: Automatically decompress response body.
May be used to enable/disable auto decompression on a per-request basis.
:param int max_line_size: Maximum allowed size of lines in responses.
:param int max_field_size: Maximum allowed size of header name and value combined in responses.
:param int max_headers: Maximum number of headers and trailers combined in responses.
:param aiohttp.protocol.HttpVersion version: Request HTTP version,
HTTP 1.1 by default. (optional)
:param aiohttp.BaseConnector connector: BaseConnector sub-class
instance to support connection pooling. (optional)
:return ClientResponse: a :class:client response <ClientResponse> object.
Usage::
import aiohttp
async def fetch():
async with aiohttp.request('GET',
'http://python.org/') as resp:
assert resp.status == 200
print(await resp.text()).. _aiohttp-client-reference-connectors:
Connectors
Connectors are transports for aiohttp client API.
There are standard connectors:
- :class:
TCPConnectorfor regular TCP sockets (both HTTP and
HTTPS schemes supported). - :class:
UnixConnectorfor connecting via UNIX socket (it's used mostly for
testing purposes).
All connector classes should be derived from :class:BaseConnector.
By default all connectors support keep-alive connections (behavior
is controlled by force_close constructor's parameter).
.. class:: BaseConnector(*, keepalive_timeout=15,
force_close=False, limit=100, limit_per_host=0,
enable_cleanup_closed=False, loop=None)
:canonical: aiohttp.connector.BaseConnector
Base class for all connectors.
:param keepalive_timeout: timeout for connection reusing
after releasing (optional). Set to
None to reuse connections
indefinitely, regardless of how long
they've been idle. For disabling
keep-alive feature entirely use
force_close=True flag instead.
:type keepalive_timeout: float | None
:param int limit: total number simultaneous connections. If limit is
0 the connector has no limit (default: 100).
:param int limit_per_host: limit simultaneous connections to the same
endpoint. Endpoints are the same if they are
have equal (host, port, is_ssl) triple.
If limit is 0 the connector has no limit (default: 0).
:param bool force_close: close underlying sockets after
connection releasing (optional).
:param bool enable_cleanup_closed: some SSL servers do not properly complete
SSL shutdown process, in that case asyncio leaks SSL connections.
If this parameter is set to True, aiohttp additionally aborts underlining
transport after 2 seconds. It is off by default.
For Python version 3.12.7+, or 3.13.1 and later,
this parameter is ignored because the asyncio SSL connection
leak is fixed in these versions of Python. :param loop: :ref:event loop<asyncio-event-loop>
used for handling connections.
If param is None, :func:asyncio.get_event_loop
is used for getting default event loop.
.. deprecated:: 2.0.. attribute:: closed
Read-only property, ``True`` if connector is closed... attribute:: force_close
Read-only property, ``True`` if connector should ultimately
close connections on releasing... attribute:: limit
The total number for simultaneous connections.
If limit is 0 the connector has no limit. The default limit size is 100... attribute:: limit_per_host
The limit for simultaneous connections to the same
endpoint.
Endpoints are the same if they are have equal ``(host, port,
is_ssl)`` triple.
If *limit_per_host* is ``0`` the connector has no limit per host.
Read-only property. .. method:: close()
:async:
Close all opened connections. .. method:: connect(request)
:async:
Get a free connection from pool or create new one if connection
is absent in the pool.
The call may be paused if :attr:`limit` is exhausted until used
connections returns to pool.
:param aiohttp.ClientRequest request: request object
which is connection
initiator.
:return: :class:`Connection` object. .. method:: _create_connection(req)
:async:
Abstract method for actual connection establishing, should be
overridden in subclasses... py:class:: AddrInfoType
Refer to :py:data:aiohappyeyeballs.AddrInfoType for more info.
.. warning::
Be sure to use aiohttp.AddrInfoType rather than
aiohappyeyeballs.AddrInfoType to avoid import breakage, as
it is likely to be removed from :mod:aiohappyeyeballs in the
future.
.. py:class:: SocketFactoryType
Refer to :py:data:aiohappyeyeballs.SocketFactoryType for more info.
.. warning::
Be sure to use aiohttp.SocketFactoryType rather than
aiohappyeyeballs.SocketFactoryType to avoid import breakage,
as it is likely to be removed from :mod:aiohappyeyeballs in the
future.
.. class:: TCPConnector(*, ssl=True, verify_ssl=True, fingerprint=None,
use_dns_cache=True, ttl_dns_cache=10,
family=0, ssl_context=None, local_addr=None,
resolver=None, keepalive_timeout=sentinel,
force_close=False, limit=100, limit_per_host=0,
enable_cleanup_closed=False, timeout_ceil_threshold=5,
happy_eyeballs_delay=0.25, interleave=None, loop=None,
socket_factory=None, ssl_shutdown_timeout=0)
:canonical: aiohttp.connector.TCPConnector
Connector for working with HTTP and HTTPS via TCP sockets.
The most common transport. When you don't know what connector type
to use, use a :class:TCPConnector instance.
:class:TCPConnector inherits from :class:BaseConnector.
Constructor accepts all parameters suitable for
:class:BaseConnector plus several TCP-specific ones:
:param ssl: **(DEPRECATED)** SSL validation mode. ``True`` for default
SSL check (:func:`ssl.create_default_context` is used),
``False`` for skip SSL certificate validation,
:class:`aiohttp.Fingerprint` for fingerprint
validation, :class:`ssl.SSLContext` for custom SSL
certificate validation.
Supersedes *verify_ssl*, *ssl_context* and
*fingerprint* parameters.
.. versionadded:: 3.0
.. deprecated:: 4.0
Scheduled for removal in 5.0. Pass *ssl* to
:class:`ClientSession` for a session-wide default, or to
:meth:`ClientSession.get` and others per request. :param bool verify_ssl: perform SSL certificate validation for
HTTPS requests (enabled by default). May be disabled to
skip validation for sites with invalid certificates.
.. deprecated:: 2.3
Pass *verify_ssl* to ``ClientSession.get()`` etc. :param bytes fingerprint: pass the SHA256 digest of the expected
certificate in DER format to verify that the certificate the
server presents matches. Useful for certificate pinning <https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning>_.
Note: use of MD5 or SHA1 digests is insecure and deprecated.
.. deprecated:: 2.3
Pass *verify_ssl* to ``ClientSession.get()`` etc. :param bool use_dns_cache: use internal cache for DNS lookups, True
by default.
Enabling an option *may* speedup connection
establishing a bit but may introduce some
*side effects* also. :param int ttl_dns_cache: expire after some seconds the DNS entries, None
means cached forever. By default 10 seconds (optional).
In some environments the IP addresses related to a specific HOST can
change after a specific time. Use this option to keep the DNS cache
updated refreshing each entry after N seconds. :param int limit: total number simultaneous connections. If limit is
0 the connector has no limit (default: 100).
:param int limit_per_host: limit simultaneous connections to the same
endpoint. Endpoints are the same if they are
have equal (host, port, is_ssl) triple.
If limit is 0 the connector has no limit (default: 0).
:param aiohttp.abc.AbstractResolver resolver: custom resolver
instance to use. aiohttp.DefaultResolver by
default (asynchronous if aiodns>=1.1 is installed).
Custom resolvers allow to resolve hostnames differently than the
way the host is configured.
The resolver is ``aiohttp.ThreadedResolver`` by default,
asynchronous version is pretty robust but might fail in
very rare cases. :param int family: TCP socket family, both IPv4 and IPv6 by default.
For IPv4 only use :data:socket.AF_INET,
for IPv6 only -- :data:socket.AF_INET6.
*family* is ``0`` by default, that means both
IPv4 and IPv6 are accepted. To specify only
concrete version please pass
:data:`socket.AF_INET` or
:data:`socket.AF_INET6` explicitly. :param ssl.SSLContext ssl_context: SSL context used for processing
HTTPS requests (optional).
*ssl_context* may be used for configuring certification
authority channel, supported SSL options etc. :param tuple local_addr: tuple of (local_host, local_port) used to bind
socket locally if specified.
:param bool force_close: close underlying sockets after
connection releasing (optional).
:param bool enable_cleanup_closed: Some ssl servers do not properly complete
SSL shutdown process, in that case asyncio leaks SSL connections.
If this parameter is set to True, aiohttp additionally aborts underlining
transport after 2 seconds. It is off by default.
:param float happy_eyeballs_delay: The amount of time in seconds to wait for a
connection attempt to complete, before starting the next attempt in parallel.
This is the โConnection Attempt Delayโ as defined in RFC 8305. To disable
Happy Eyeballs, set this to None. The default value recommended by the
RFC is 0.25 (250 milliseconds).
.. versionadded:: 3.10 :param int interleave: controls address reordering when a host name resolves
to multiple IP addresses. If 0 or unspecified, no reordering is done, and
addresses are tried in the order returned by the resolver. If a positive
integer is specified, the addresses are interleaved by address family, and
the given integer is interpreted as โFirst Address Family Countโ as defined
in RFC 8305. The default is 0 if happy_eyeballs_delay is not specified, and
1 if it is.
.. versionadded:: 3.10 :param SocketFactoryType socket_factory: This function takes an
:py:data:AddrInfoType and is used in lieu of
:py:func:socket.socket when creating TCP connections.
.. versionadded:: 3.12 :param float ssl_shutdown_timeout: (DEPRECATED) This parameter is deprecated
and will be removed in aiohttp 4.0. Grace period for SSL shutdown on TLS
connections when the connector is closed (0 seconds by default).
By default (0), SSL connections are aborted immediately when the
connector is closed, without performing the shutdown handshake. During
normal operation, SSL connections use Python's default SSL shutdown
behavior. Setting this to a positive value (e.g., 0.1) will perform
a graceful shutdown when closing the connector, notifying the remote
server which can help prevent "connection reset" errors at the cost of
additional cleanup time. Note: On Python versions prior to 3.11, only
a value of 0 is supported; other values will trigger a warning.
.. versionadded:: 3.12.5
.. versionchanged:: 3.12.11
Changed default from ``0.1`` to ``0`` to abort SSL connections
immediately when the connector is closed. Added support for
``ssl_shutdown_timeout=0`` on all Python versions. A :exc:`RuntimeWarning`
is issued when non-zero values are passed on Python < 3.11.
.. deprecated:: 3.12.11
This parameter is deprecated and will be removed in aiohttp 4.0... attribute:: family
*TCP* socket family e.g. :data:`socket.AF_INET` or
:data:`socket.AF_INET6`
Read-only property... attribute:: dns_cache
Use quick lookup in internal *DNS* cache for host names if ``True``.
Read-only :class:`bool` property... attribute:: cached_hosts
The cache of resolved hosts if :attr:`dns_cache` is enabled.
Read-only :class:`types.MappingProxyType` property... method:: clear_dns_cache(self, host=None, port=None)
Clear internal *DNS* cache.
Remove specific entry if both *host* and *port* are specified,
clear all cache otherwise... class:: UnixConnector(path, *, conn_timeout=None,
keepalive_timeout=30, limit=100,
force_close=False, loop=None)
:canonical: aiohttp.connector.UnixConnector
Unix socket connector.
Use :class:UnixConnector for sending HTTP/HTTPS requests
through UNIX Sockets as underlying transport.
UNIX sockets are handy for writing tests and making very fast
connections between processes on the same host.
:class:UnixConnector is inherited from :class:BaseConnector.
Usage::
conn = UnixConnector(path='/path/to/socket')
session = ClientSession(connector=conn)
async with session.get('http://python.org') as resp:
... Constructor accepts all parameters suitable for
:class:BaseConnector plus UNIX-specific one:
:param str path: Unix socket path
.. attribute:: path
Path to *UNIX socket*, read-only :class:`str` property... class:: Connection
:canonical: aiohttp.connector.Connection
Encapsulates single connection in connector object.
End user should never create :class:Connection instances manually
but get it by :meth:BaseConnector.connect coroutine.
.. attribute:: closed
:class:`bool` read-only property, ``True`` if connection was
closed, released or detached... attribute:: loop
Event loop used for connection
.. deprecated:: 3.5.. attribute:: transport
Connection transport.. method:: close()
Close connection with forcibly closing underlying socket... method:: release()
Release connection back to connector.
Underlying socket is not closed, the connection may be reused
later if timeout (30 seconds by default) for connection was not
expired.Response object
.. class:: ClientResponse
:canonical: aiohttp.client_reqrep.ClientResponse
Client response returned by :meth:aiohttp.ClientSession.request and family.
User never creates the instance of ClientResponse class but gets it
from API calls.
:class:ClientResponse supports async context manager protocol, e.g.::
resp = await client_session.get(url)
async with resp:
assert resp.status == 200 After exiting from async with block response object will be
released (see :meth:release method).
.. attribute:: version
Response's version, :class:`~aiohttp.protocol.HttpVersion` instance... attribute:: status
HTTP status code of response (:class:`int`), e.g. ``200``... attribute:: reason
HTTP status reason of response (:class:`str`), e.g. ``"OK"``... attribute:: ok
Boolean representation of HTTP status code (:class:`bool`).
``True`` if ``status`` is less than ``400``; otherwise, ``False``... attribute:: method
Request's method (:class:`str`)... attribute:: url
URL of request (:class:`~yarl.URL`)... attribute:: real_url
Unmodified URL of request with URL fragment unstripped (:class:`~yarl.URL`).
.. versionadded:: 3.2.. attribute:: connection
:class:`Connection` used for handling response... attribute:: content
Payload stream, which contains response's BODY (:class:`StreamReader`).
It supports various reading methods depending on the expected format.
When chunked transfer encoding is used by the server, allows retrieving
the actual http chunks.
Reading from the stream may raise
:exc:`aiohttp.ClientPayloadError` if the response object is
closed before response receives all data or in case if any
transfer encoding related errors like malformed chunked
encoding of broken compression data... attribute:: cookies
HTTP cookies of response (*Set-Cookie* HTTP header,
:class:`~http.cookies.SimpleCookie`).
.. note::
Since :class:`~http.cookies.SimpleCookie` uses cookie name as the
key, cookies with the same name but different domains or paths will
be overwritten. Only the last cookie with a given name will be
accessible via this attribute.
To access all cookies, including duplicates with the same name,
use :meth:`response.headers.getall('Set-Cookie') <multidict.MultiDictProxy.getall>`.
At most 50 valid ``Set-Cookie`` fields are parsed, here and for the
session's cookie jar... attribute:: headers
A case-insensitive multidict proxy with HTTP headers of
response, :class:`~multidict.CIMultiDictProxy`... attribute:: raw_headers
Unmodified HTTP headers of response as unconverted bytes, a sequence of
``(key, value)`` pairs... attribute:: links
Link HTTP header parsed into a :class:`~multidict.MultiDictProxy`.
For each link, key is link param `rel` when it exists, or link url as
:class:`str` otherwise, and value is :class:`~multidict.MultiDictProxy`
of link params and url at key `url` as :class:`~yarl.URL` instance.
.. versionadded:: 3.2.. attribute:: content_type
Read-only property with *content* part of *Content-Type* header.
.. note::
Returns ``'application/octet-stream'`` if no Content-Type header
is present or the value contains invalid syntax according to
:rfc:`9110`. To see the original header check
``resp.headers["Content-Type"]``.
To make sure Content-Type header is not present in
the server reply, use :attr:`headers` or :attr:`raw_headers`, e.g.
``'Content-Type' not in resp.headers``... attribute:: charset
Read-only property that specifies the *encoding* for the request's BODY.
The value is parsed from the *Content-Type* HTTP header.
Returns :class:`str` like ``'utf-8'`` or ``None`` if no *Content-Type*
header present in HTTP headers or it has no charset information... attribute:: content_disposition
Read-only property that specified the *Content-Disposition* HTTP header.
Instance of :class:`ContentDisposition` or ``None`` if no *Content-Disposition*
header present in HTTP headers... attribute:: history
A :class:`~collections.abc.Sequence` of :class:`ClientResponse`
objects of preceding requests (earliest request first) if there were
redirects, an empty sequence otherwise... method:: close()
Close response and underlying connection.
For :term:`keep-alive` support see :meth:`release`. .. method:: read()
:async:
Read the whole response's body as :class:`bytes`.
Close underlying connection if data reading gets an error,
release connection otherwise.
Raise an :exc:`aiohttp.ClientResponseError` if the data can't
be read.
:return bytes: read *BODY*.
.. seealso:: :meth:`close`, :meth:`release`... method:: release()
It is not required to call `release` on the response
object. When the client fully receives the payload, the
underlying connection automatically returns back to pool. If the
payload is not fully read, the connection is closed.. method:: raise_for_status()
Raise an :exc:`aiohttp.ClientResponseError` if the response
status is 400 or higher.
Do nothing for success responses (less than 400). .. method:: text(encoding=None)
:async:
Read response's body and return decoded :class:`str` using
specified *encoding* parameter.
If *encoding* is ``None`` content encoding is determined from the
Content-Type header, or using the ``fallback_charset_resolver`` function.
Close underlying connection if data reading gets an error,
release connection otherwise.
:param str encoding: text encoding used for *BODY* decoding, or
``None`` for encoding autodetection
(default).
:raises: :exc:`UnicodeDecodeError` if decoding fails. See also
:meth:`get_encoding`.
:return str: decoded *BODY* .. method:: json(*, encoding=None, loads=json.loads,
content_type='application/json')
:async:
Read response's body as *JSON*, return :class:`dict` using
specified *encoding* and *loader*. If data is not still available
a ``read`` call will be done.
If response's `content-type` does not match `content_type` parameter
:exc:`aiohttp.ContentTypeError` get raised.
To disable content type check pass ``None`` value.
:param str encoding: text encoding used for *BODY* decoding, or
``None`` for encoding autodetection
(default).
By the standard JSON encoding should be
``UTF-8`` but practice beats purity: some
servers return non-UTF
responses. Autodetection works pretty fine
anyway.
:param collections.abc.Callable loads: :term:`callable` used for loading *JSON*
data, :func:`json.loads` by default.
:param str content_type: specify response's content-type, if content type
does not match raise :exc:`aiohttp.ClientResponseError`.
To disable `content-type` check, pass ``None`` as value.
(default: `application/json`).
:return: *BODY* as *JSON* data parsed by *loads* parameter or
``None`` if *BODY* is empty or contains white-spaces only... attribute:: request_info
A :class:`typing.NamedTuple` with request URL and headers from :class:`~aiohttp.ClientRequest`
object, :class:`aiohttp.RequestInfo` instance... method:: get_encoding()
Retrieve content encoding using ``charset`` info in ``Content-Type`` HTTP header.
If no charset is present or the charset is not understood by Python, the
``fallback_charset_resolver`` function associated with the ``ClientSession`` is called.
.. versionadded:: 3.0ClientWebSocketResponse
To connect to a websocket server :func:aiohttp.ws_connect or
:meth:aiohttp.ClientSession.ws_connect coroutines should be used, do
not create an instance of class :class:ClientWebSocketResponse
manually.
.. class:: ClientWebSocketResponse()
:canonical: aiohttp.client_ws.ClientWebSocketResponse
Class for handling client-side websockets.
.. attribute:: closed
Read-only property, ``True`` if :meth:`close` has been called or
:const:`~aiohttp.WSMsgType.CLOSE` message has been received from peer... attribute:: protocol
Websocket *subprotocol* chosen after :meth:`start` call.
May be ``None`` if server and client protocols are
not overlapping... method:: get_extra_info(name, default=None)
Reads optional extra information from the connection's transport.
If no value associated with ``name`` is found, ``default`` is returned.
See :meth:`asyncio.BaseTransport.get_extra_info`
:param str name: The key to look up in the transport extra information.
:param default: Default value to be used when no value for ``name`` is
found (default is ``None``)... method:: exception()
Returns exception if any occurs or returns None. .. method:: ping(message=b'')
:async:
Send :const:`~aiohttp.WSMsgType.PING` to peer.
:param message: optional payload of *ping* message,
:class:`str` (converted to *UTF-8* encoded bytes)
or :class:`bytes`.
.. versionchanged:: 3.0
The method is converted into :term:`coroutine` .. method:: pong(message=b'')
:async:
Send :const:`~aiohttp.WSMsgType.PONG` to peer.
:param message: optional payload of *pong* message,
:class:`str` (converted to *UTF-8* encoded bytes)
or :class:`bytes`.
.. versionchanged:: 3.0
The method is converted into :term:`coroutine` .. method:: send_str(data, compress=None)
:async:
Send *data* to peer as :const:`~aiohttp.WSMsgType.TEXT` message.
:param str data: data to send.
:param int compress: sets specific level of compression for
single message,
``None`` for not overriding per-socket setting.
:raise TypeError: if data is not :class:`str`
.. versionchanged:: 3.0
The method is converted into :term:`coroutine`,
*compress* parameter added. .. method:: send_bytes(data, compress=None)
:async:
Send *data* to peer as :const:`~aiohttp.WSMsgType.BINARY` message.
:param data: data to send.
:param int compress: sets specific level of compression for
single message,
``None`` for not overriding per-socket setting.
:raise TypeError: if data is not :class:`bytes`,
:class:`bytearray` or :class:`memoryview`.
.. versionchanged:: 3.0
The method is converted into :term:`coroutine`,
*compress* parameter added. .. method:: send_json(data, compress=None, *, dumps=json.dumps)
:async:
Send *data* to peer as JSON string.
:param data: data to send.
:param int compress: sets specific level of compression for
single message,
``None`` for not overriding per-socket setting.
:param collections.abc.Callable dumps: any :term:`callable` that accepts an object and
returns a JSON string
(:func:`json.dumps` by default).
:raise RuntimeError: if connection is not started or closing
:raise ValueError: if data is not serializable object
:raise TypeError: if value returned by ``dumps(data)`` is not
:class:`str`
.. versionchanged:: 3.0
The method is converted into :term:`coroutine`,
*compress* parameter added. .. method:: send_json_bytes(data, compress=None, *, dumps)
:async:
Send *data* to peer as a JSON binary frame using a bytes-returning encoder.
:param data: data to send.
:param int compress: sets specific level of compression for
single message,
``None`` for not overriding per-socket setting.
:param collections.abc.Callable dumps: any :term:`callable` that accepts an object and
returns JSON as :class:`bytes`
(e.g. ``orjson.dumps``).
:raise RuntimeError: if connection is not started or closing
:raise ValueError: if data is not serializable object
:raise TypeError: if value returned by ``dumps(data)`` is not
:class:`bytes` .. method:: send_frame(message, opcode, compress=None)
:async:
Send a :const:`~aiohttp.WSMsgType` message *message* to peer.
This method is low-level and should be used with caution as it
only accepts bytes which must conform to the correct message type
for *message*.
It is recommended to use the :meth:`send_str`, :meth:`send_bytes`
or :meth:`send_json` methods instead of this method.
The primary use case for this method is to send bytes that are
have already been encoded without having to decode and
re-encode them.
:param bytes message: message to send.
:param ~aiohttp.WSMsgType opcode: opcode of the message.
:param int compress: sets specific level of compression for
single message,
``None`` for not overriding per-socket setting.
.. versionadded:: 3.11 .. method:: close(*, code=WSCloseCode.OK, message=b'')
:async:
A :ref:`coroutine<coroutine>` that initiates closing handshake by sending
:const:`~aiohttp.WSMsgType.CLOSE` message. It waits for
close response from server. To add a timeout to `close()` call
just wrap the call with `asyncio.wait()` or `asyncio.wait_for()`.
:param int code: closing code. See also :class:`~aiohttp.WSCloseCode`.
:param message: optional payload of *close* message,
:class:`str` (converted to *UTF-8* encoded bytes) or :class:`bytes`. .. method:: receive()
:async:
A :ref:`coroutine<coroutine>` that waits upcoming *data*
message from peer and returns it.
The coroutine implicitly handles
:const:`~aiohttp.WSMsgType.PING`,
:const:`~aiohttp.WSMsgType.PONG` and
:const:`~aiohttp.WSMsgType.CLOSE` without returning the
message.
It process *ping-pong game* and performs *closing handshake* internally.
:return: :class:`~aiohttp.WSMessage` .. method:: receive_str()
:async:
A :ref:`coroutine<coroutine>` that calls :meth:`receive` but
also asserts the message type is
:const:`~aiohttp.WSMsgType.TEXT`.
:return str: peer's message content.
:raise aiohttp.WSMessageTypeError: if message is not :const:`~aiohttp.WSMsgType.TEXT`. .. method:: receive_bytes()
:async:
A :ref:`coroutine<coroutine>` that calls :meth:`receive` but
also asserts the message type is
:const:`~aiohttp.WSMsgType.BINARY`.
:return bytes: peer's message content.
:raise aiohttp.WSMessageTypeError: if message is not :const:`~aiohttp.WSMsgType.BINARY`. .. method:: receive_json(*, loads=json.loads)
:async:
A :ref:`coroutine<coroutine>` that calls :meth:`receive_str` and loads
the JSON string to a Python dict.
:param collections.abc.Callable loads: any :term:`callable` that accepts
:class:`str` and returns :class:`dict`
with parsed JSON (:func:`json.loads` by
default).
:return dict: loaded JSON content
:raise TypeError: if message is :const:`~aiohttp.WSMsgType.BINARY`.
:raise ValueError: if message is not valid JSON.ClientRequest
.. class:: ClientRequest
:canonical: aiohttp.client_reqrep.ClientRequest
Represents an HTTP request to be sent by the client.
This object encapsulates all the details of an HTTP request before it is sent.
It is primarily used within client middleware to inspect or modify requests.
.. note::
You typically don't create ``ClientRequest`` instances directly. They are
created internally by :class:`ClientSession` methods and passed to middleware. For more information about using middleware, see :ref:aiohttp-client-middleware.
.. attribute:: body
:type: Payload | Literal[b""]
The request body payload (defaults to ``b""`` if no body passed).
.. danger::
**DO NOT set this attribute directly!** Direct assignment will cause resource
leaks. Always use :meth:`update_body` instead:
.. code-block:: python
# WRONG - This will leak resources!
request.body = b"new data"
# CORRECT - Use update_body
await request.update_body(b"new data")
Setting body directly bypasses cleanup of the previous payload, which can
leave file handles open, streams unclosed, and buffers unreleased.
Additionally, setting body directly must be done from within an event loop
and is not thread-safe. Setting body outside of an event loop may raise
RuntimeError when closing file-based payloads. .. attribute:: chunked
:type: bool | None
Whether to use chunked transfer encoding:
- ``True``: Use chunked encoding
- ``False``: Don't use chunked encoding
- ``None``: Automatically determine based on body .. attribute:: compress
:type: str | None
The compression encoding for the request body. Common values include
``'gzip'`` and ``'deflate'``, but any string value is technically allowed.
``None`` means no compression. .. attribute:: headers
:type: multidict.CIMultiDict
The HTTP headers that will be sent with the request. This is a case-insensitive
multidict that can be modified by middleware.
.. code-block:: python
# Add or modify headers
request.headers['X-Custom-Header'] = 'value'
request.headers['User-Agent'] = 'MyApp/1.0' .. attribute:: is_ssl
:type: bool
``True`` if the request uses a secure scheme (e.g., HTTPS, WSS), ``False`` otherwise. .. attribute:: method
:type: str
The HTTP method of the request (e.g., ``'GET'``, ``'POST'``, ``'PUT'``, etc.). .. attribute:: original_url
:type: yarl.URL
The original URL passed to the request method, including any fragment.
This preserves the exact URL as provided by the user. .. attribute:: proxy
:type: yarl.URL | None
The proxy URL if the request will be sent through a proxy, ``None`` otherwise. .. attribute:: proxy_headers
:type: multidict.CIMultiDict | None
Headers to be sent to the proxy server (e.g., ``Proxy-Authorization``).
Only set when :attr:`proxy` is not ``None``. .. attribute:: response_class
:type: type[ClientResponse]
The class to use for creating the response object. Defaults to
:class:`ClientResponse` but can be customized for special handling. .. attribute:: server_hostname
:type: str | None
Override the hostname for SSL certificate verification. Useful when
connecting through proxies or to IP addresses. .. attribute:: session
:type: ClientSession
The client session that created this request. Useful for accessing
session-level configuration or making additional requests within middleware.
.. warning::
Be careful when making requests with the same session inside middleware
to avoid infinite recursion. Use ``middlewares=()`` parameter when needed. .. attribute:: ssl
:type: ssl.SSLContext | bool | Fingerprint
SSL validation configuration for this request:
- ``True``: Use default SSL verification
- ``False``: Skip SSL verification
- :class:`ssl.SSLContext`: Custom SSL context
- :class:`Fingerprint`: Verify specific certificate fingerprint .. attribute:: timeout
:type: ClientTimeout
The timeout configuration this request runs under (read-only): the
per-request timeout when one was passed to the request method, the
session's default otherwise. Useful in middleware to bound waits or
retries by the caller's time budget.
.. versionadded:: 3.15 .. attribute:: url
:type: yarl.URL
The target URL of the request with the fragment (``#...``) part stripped.
This is the actual URL that will be used for the connection.
.. note::
To access the original URL with fragment, use :attr:`original_url`. .. attribute:: version
:type: HttpVersion
The HTTP version to use for the request (e.g., ``HttpVersion(1, 1)`` for HTTP/1.1)... method:: update_body(body)
Update the request body and close any existing payload to prevent resource leaks.
**This is the ONLY correct way to modify a request body.** Never set the
:attr:`body` attribute directly.
This method is particularly useful in middleware when you need to modify the
request body after the request has been created but before it's sent.
:param body: The new body content. Can be:
- ``bytes``/``bytearray``: Raw binary data
- ``str``: Text data (encoded using charset from Content-Type)
- :class:`FormData`: Form data encoded as multipart/form-data
- :class:`Payload`: A pre-configured payload object
- ``AsyncIterable[bytes]``: Async iterable of bytes chunks
- File-like object: Will be read and sent as binary data
- ``None``: Clears the body
.. code-block:: python
async def middleware(request, handler):
# Modify request body in middleware
if request.method == 'POST':
# CORRECT: Always use update_body
await request.update_body(b'{"modified": true}')
# WRONG: Never set body directly!
# request.body = b'{"modified": true}' # This leaks resources!
# Or add authentication data to form
if isinstance(request.body, FormData):
form = FormData()
# Copy existing fields and add auth token
form.add_field('auth_token', 'secret123')
await request.update_body(form)
return await handler(request)
.. note::
This method is async because it may need to close file handles or
other resources associated with the previous payload. Always await
this method to ensure proper cleanup.
.. danger::
**Never set :attr:`ClientRequest.body` directly!** Direct assignment will cause resource
leaks. Always use this method instead. Setting the body attribute directly:
- Bypasses cleanup of the previous payload
- Leaves file handles and streams open
- Can cause memory leaks
- May result in unexpected behavior with async iterables
.. warning::
When updating the body, ensure that the Content-Type header is
appropriate for the new body content. The Content-Length header
will be updated automatically. When using :class:`FormData` or
:class:`Payload` objects, headers are updated automatically,
but you may need to set Content-Type manually for raw bytes or text.
It is not recommended to change the payload type in middleware. If the
body was already set (e.g., as bytes), it's best to keep the same type
rather than converting it (e.g., to str) as this may result in unexpected
behavior.
.. versionadded:: 3.12Utilities
.. class:: ClientTimeout(, total=560, connect=None,
sock_connect=None, sock_read=None)
:canonical: aiohttp.client.ClientTimeout
A data class for client timeout settings.
See :ref:aiohttp-client-timeouts for usage examples.
.. attribute:: total
Total number of seconds for the whole request.
:class:`float`, 300 seconds (5 min) by default... attribute:: connect
Maximal number of seconds for acquiring a connection from pool. The time
consists connection establishment for a new connection or
waiting for a free connection from a pool if pool connection
limits are exceeded.
For pure socket connection establishment time use
:attr:`sock_connect`.
:class:`float`, ``None`` by default... attribute:: sock_connect
Maximal number of seconds for connecting to a peer for a new connection, not
given from a pool. See also :attr:`connect`.
:class:`float`, ``None`` by default... attribute:: sock_read
Maximal number of seconds for reading a portion of data from a peer.
:class:`float`, ``None`` by default... class:: ClientWSTimeout(*, ws_receive=None, ws_close=None)
:canonical: aiohttp.client_ws.ClientWSTimeout
A data class for websocket client timeout settings.
.. attribute:: ws_receive
A timeout for websocket to receive a complete message.
:class:`float`, ``None`` by default... attribute:: ws_close
A timeout for the websocket to close.
:class:`float`, ``10.0`` by default... note::
Timeouts of 5 seconds or more are rounded for scheduling on the next
second boundary (an absolute time where microseconds part is zero) for the
sake of performance.
E.g., assume a timeout is ``10``, absolute time when timeout should expire
is ``loop.time() + 5``, and it points to ``12345.67 + 10`` which is equal
to ``12355.67``.
The absolute time for the timeout cancellation is ``12356``.
It leads to grouping all close scheduled timeout expirations to exactly
the same time to reduce amount of loop wakeups.
.. versionchanged:: 3.7
Rounding to the next seconds boundary is disabled for timeouts smaller
than 5 seconds for the sake of easy debugging.
In turn, tiny timeouts can lead to significant performance degradation
on production environment... class:: ETag(name, is_weak=False)
:canonical: aiohttp.helpers.ETag
Represents ETag identifier.
.. attribute:: value
Value of corresponding etag without quotes... attribute:: is_weak
Flag indicates that etag is weak (has `W/` prefix)... versionadded:: 3.8
.. class:: ContentDisposition
:canonical: aiohttp.client_reqrep.ContentDisposition
A data class to represent the Content-Disposition header,
available as :attr:`ClientResponse.content_disposition` attribute.
.. attribute:: type
A :class:`str` instance. Value of Content-Disposition header
itself, e.g. ``attachment``.
.. attribute:: filename
A :class:`str` instance. Content filename extracted from
parameters. May be ``None``.
.. attribute:: parameters
Read-only mapping contains all parameters... class:: RequestInfo()
:canonical: aiohttp.client_reqrep.RequestInfo
A :class:typing.NamedTuple with request URL and headers from :class:~aiohttp.ClientRequest
object, available as :attr:ClientResponse.request_info attribute.
.. attribute:: url
Requested *url*, :class:`yarl.URL` instance... attribute:: method
Request HTTP method like ``'GET'`` or ``'POST'``, :class:`str`... attribute:: headers
HTTP headers for request, :class:`multidict.CIMultiDict` instance... attribute:: real_url
Requested *url* with URL fragment unstripped, :class:`yarl.URL` instance.
.. versionadded:: 3.2.. function:: encode_basic_auth(login, password='', encoding='utf-8')
Encode HTTP Basic Authentication credentials as a value suitable for the
Authorization (or Proxy-Authorization) header::
headers = {"Authorization": encode_basic_auth("user", "pass")} :param str login: login
:param str password: password ('' by default)
:param str encoding: encoding ('utf-8' by default)
:return: a string of the form "Basic "
:rtype: str
.. versionadded:: 3.14
.. class:: UploadTracker()
:canonical: aiohttp.client_reqrep.UploadTracker
Tracks upload progress of a single client request.
Create a tracker inside a running event loop and pass it to a request
via the upload_tracker argument; read its attributes while the
request runs, e.g. from a progress-reporting task::
tracker = aiohttp.UploadTracker()
async def report_progress() -> None:
while not tracker.upload_complete.done():
print(f"uploaded {tracker.bytes_written} bytes")
await asyncio.sleep(0.5)
progress = asyncio.create_task(report_progress())
async with session.post(url, data=data, upload_tracker=tracker) as resp:
...
await progress
# Raises if the upload failed, even when the request itself
# succeeded because the server answered early.
await tracker.upload_complete A tracker observes exactly one request: passing it to a second request
raises :exc:RuntimeError. Two requests uploading the same payload
each get their own tracker.
.. attribute:: bytes_written
Body bytes of the current upload attempt that have been sent to
the kernel. Counted before transport-level transformations such as compression
or chunked framing; within a partially sent chunk the value is a
linear estimate. Resets to ``0`` when the request moves on to a new
attempt, and equal to the full body size once the attempt has
written everything.
.. note::
Because this only tracks the data sent to the kernel, which then buffers data
itself, this feature is effectively useless on small payloads.
Typically, payloads less than ~10 MiB will result in the progress
appearing to be 100% immediately, even if not a single byte has left
the machine yet. A payload ~20 MiB might see the progress jump to 40-50%
immediately, etc. The larger the payload, the less noticeable this skew will be... attribute:: attempts
Number of upload attempts dispatched: ``1`` for a plain request,
incremented each time the request is resent, e.g. following a
redirect or a middleware retry. A redirect that drops the body
(such as a *303 See Other*) still counts a zero-byte attempt... attribute:: upload_complete
An :class:`asyncio.Future` settled once no more of the body will
be sent: with ``None`` when the final attempt wrote the body fully
(even if the server responded first, the future settles when
writing finishes); with the upload error when the final attempt
failed (the request raises the same error unless the server
already responded successfully); or with :exc:`UploadAbortedError`
when the body was never fully sent, e.g. the request failed before
writing started, was cancelled, or a middleware answered without
sending the request.
When the server answers before reading the whole body, the request
succeeds without raising; await the future (or check its
:meth:`~asyncio.Future.exception`) to observe such upload failures... versionadded:: 3.14.4
.. class:: DigestAuthMiddleware(login, password, *, preemptive=True)
:canonical: aiohttp.client_middleware_digest_auth.DigestAuthMiddleware
HTTP digest authentication client middleware.
:param str login: login
:param str password: password
:param bool preemptive: Enable preemptive authentication (default: True)
This middleware supports HTTP digest authentication with both auth and
auth-int quality of protection (qop) modes, and a variety of hashing algorithms.
It automatically handles the digest authentication handshake by:
- Parsing 401 Unauthorized responses with
WWW-Authenticate: Digestheaders - Generating appropriate
Authorization: Digestheaders on retry - Maintaining nonce counts and challenge data per request
- When
preemptive=True, reusing authentication credentials for subsequent
requests to the same protection space (following RFC 7616 Section 3.6)
Preemptive Authentication
By default (preemptive=True), the middleware remembers successful authentication
challenges and automatically includes the Authorization header in subsequent requests
to the same protection space. This behavior:
- Improves server efficiency by avoiding extra round trips
- Matches how modern web browsers handle digest authentication
- Follows the recommendation in RFC 7616 Section 3.6
The server may still respond with a 401 status and stale=true if the nonce
has expired, in which case the middleware will automatically retry with the new nonce.
Origin scoping
The credentials are scoped to the origin of the first request the middleware
handles. A request to a different origin is passed through untouched, so it
never receives a digest response computed from those credentials, unless that
origin falls within a protection space the anchor origin advertised through
the RFC 7616 domain directive. Make the first request through the
middleware against the intended origin, as the anchor is pinned to it and not
reset for the life of the instance.
To disable preemptive authentication and require a 401 challenge for every request,
set preemptive=False::
# Default behavior - preemptive auth enabled
digest_auth_middleware = DigestAuthMiddleware(login="user", password="pass")
# Disable preemptive auth - always wait for 401 challenge
digest_auth_middleware = DigestAuthMiddleware(login="user", password="pass",
preemptive=False)Usage::
digest_auth_middleware = DigestAuthMiddleware(login="user", password="pass")
async with ClientSession(middlewares=(digest_auth_middleware,)) as session:
async with session.get("http://protected.example.com") as resp:
# The middleware automatically handles the digest auth handshake
assert resp.status == 200
# Subsequent requests include auth header preemptively
async with session.get("http://protected.example.com/other") as resp:
assert resp.status == 200 # No 401 round trip needed .. versionadded:: 3.12
.. versionchanged:: 3.12.8
Added preemptive parameter to enable/disable preemptive authentication.
.. versionchanged:: 3.14.1
Credentials are scoped to the origin of the first request the middleware
handles; other origins are passed through untouched unless covered by an
RFC 7616 domain directive from the anchor origin.
.. class:: CookieJar(*, unsafe=False, quote_cookie=True, treat_as_secure_origin = [])
:canonical: aiohttp.cookiejar.CookieJar
The cookie jar instance is available as :attr:ClientSession.cookie_jar.
The jar contains :class:~http.cookies.Morsel items for storing
internal cookie data.
API provides a count of saved cookies::
len(session.cookie_jar)These cookies may be iterated over::
for cookie in session.cookie_jar:
print(cookie.key)
print(cookie["domain"]) The class implements :class:collections.abc.Iterable,
:class:collections.abc.Sized and
:class:aiohttp.abc.AbstractCookieJar interfaces.
Implements cookie storage adhering to RFC 6265.
Cookies parsed from responses are limited to 50 valid Set-Cookie
fields per response, 4,096 octets for a cookie's name and value, 32
attributes per field and 1,024 octets per attribute value; anything beyond
that is ignored. Flags such as Secure ignore their value, so a value
over the limit still sets them.
The jar stores at most 180 cookies per domain and 3,300 in total, and
sends at most 150 cookies and 8,190 octets, including Cookie:, per
request header. Eviction follows Firefox: adding a cookie to a full domain
evicts expired, then non-secure, cookies, least recently used first, down
to 150 or until none are left. If the domain is full of live Secure
cookies, they are evicted for a new Secure cookie and a new non-secure
cookie is dropped. A full jar evicts expired, then least recently used,
cookies from any domain down to 3,000.
The limits do not apply to an explicit Cookie header or to the
per-request cookies argument.
:param bool unsafe: (optional) Whether to accept cookies from IPs.
:param bool quote_cookie: (optional) Whether to quote cookies according to
:rfc:2109. Some backend systems
(not compatible with RFC mentioned above)
does not support quoted cookies.
.. versionadded:: 3.7 :param treat_as_secure_origin: (optional) Mark origins as secure
for cookies marked as Secured.
Possible types are:
- :class:`tuple` or :class:`list` of
:class:`str` or :class:`yarl.URL`
- :class:`str`
- :class:`yarl.URL`
.. versionadded:: 3.8.. method:: update_cookies(cookies, response_url=None)
Update cookies returned by server in ``Set-Cookie`` header.
:param cookies: a :class:`collections.abc.Mapping`
(e.g. :class:`dict`, :class:`~http.cookies.SimpleCookie`) or
*iterable* of *pairs* with cookies returned by server's
response.
:param ~yarl.URL response_url: URL of response, ``None`` for *shared
cookies*. Regular cookies are coupled with server's URL and
are sent only to this server, shared ones are sent in every
client request (except that shared cookies marked ``Secure``
are only sent over encrypted connections or to origins listed
in *treat_as_secure_origin*)... method:: filter_cookies(request_url)
Return jar's cookies acceptable for URL and available in
``Cookie`` header for sending client requests for given URL.
:param ~yarl.URL response_url: request's URL for which cookies are asked.
:return: :class:`http.cookies.SimpleCookie` with filtered
cookies for given URL... method:: save(file_path)
Write a JSON representation of cookies into the file
at provided path.
:param file_path: Path to file where cookies will be serialized,
:class:`str` or :class:`pathlib.Path` instance... method:: load(file_path)
Load cookies from a JSON file at the provided path.
The jar's storage limits apply to the loaded cookies. If the file is
malformed, an exception is raised and the jar is left unchanged.
:param file_path: Path to file from where cookies will be
imported, :class:`str` or :class:`pathlib.Path` instance... method:: clear(predicate=None)
Removes all cookies from the jar if the predicate is ``None``. Otherwise remove only those :class:`~http.cookies.Morsel` that ``predicate(morsel)`` returns ``True``.
:param predicate: callable that gets :class:`~http.cookies.Morsel` as a parameter and returns ``True`` if this :class:`~http.cookies.Morsel` must be deleted from the jar.
.. versionadded:: 4.0.. method:: clear_domain(domain)
Remove all cookies from the jar that belongs to the specified domain or its subdomains.
:param str domain: domain for which cookies must be deleted from the jar.
.. versionadded:: 4.0.. attribute:: cookies
A read-only view of the jar's cookies as a
:class:`~types.MappingProxyType` mapping ``(domain, path)`` tuples
to :class:`~http.cookies.SimpleCookie` instances.
.. versionadded:: 3.14.. attribute:: host_only_cookies
A :class:`frozenset` of ``(domain, path, name)`` tuples indicating
which cookies are host-only (not sent to subdomains).
.. versionadded:: 3.14
.. versionchanged:: 3.14.4
The tuples gained the *path* element; host-only state is tracked
per ``(domain, path, name)`` cookie identity so that same-named
cookies on other paths cannot affect it... attribute:: treat_as_secure_origin
A :class:`frozenset` of :class:`~yarl.URL` origins that are
treated as secure even when the connection is not encrypted, as
configured by the *treat_as_secure_origin* parameter.
.. versionadded:: 3.14.4.. class:: DummyCookieJar(*, loop=None)
:canonical: aiohttp.cookiejar.DummyCookieJar
Dummy cookie jar which does not store cookies but ignores them.
Could be useful e.g. for web crawlers to iterate over Internet
without blowing up with saved cookies information.
To install dummy cookie jar pass it into session instance::
jar = aiohttp.DummyCookieJar()
session = aiohttp.ClientSession(cookie_jar=DummyCookieJar()).. class:: Fingerprint(digest)
:canonical: aiohttp.client_reqrep.Fingerprint
Fingerprint helper for checking SSL certificates by SHA256 digest.
:param bytes digest: SHA256 digest for certificate in DER-encoded
binary form (see
:meth:ssl.SSLSocket.getpeercert).
To check fingerprint pass the object into :meth:ClientSession.get
call, e.g.::
import hashlib
with open(path_to_cert, 'rb') as f:
digest = hashlib.sha256(f.read()).digest()
await session.get(url, ssl=aiohttp.Fingerprint(digest)).. versionadded:: 3.0
.. function:: set_zlib_backend(lib)
:canonical: aiohttp.compression_utils.set_zlib_backend
Sets the compression backend for zlib-based operations.
This function allows you to override the default zlib backend
used internally by passing a module that implements the standard
compression interface.
The module should implement at minimum the exact interface offered by the
latest version of zlib.
:param types.ModuleType lib: A module that implements the zlib-compatible compression API.
Example usage::
import zlib_ng.zlib_ng as zng
import aiohttp
aiohttp.set_zlib_backend(zng) .. note:: aiohttp has been tested internally with :mod:zlib, :mod:zlib_ng.zlib_ng, and :mod:isal.isal_zlib.
.. versionadded:: 3.12
FormData
^^^^^^^^
A :class:FormData object contains the form data and also handles
encoding it into a body that is either multipart/form-data orapplication/x-www-form-urlencoded. multipart/form-data is
used if at least one field is an :class:io.IOBase object or was
added with at least one optional argument to :meth:add_field<aiohttp.FormData.add_field>
(content_type, filename, or content_transfer_encoding).
Otherwise, application/x-www-form-urlencoded is used.
:class:FormData instances are callable and return a :class:aiohttp.payload.Payload
on being called.
.. class:: FormData(fields, quote_fields=True, charset=None)
:canonical: aiohttp.formdata.FormData
Helper class for multipart/form-data and application/x-www-form-urlencoded body generation.
:param fields: A container for the key/value pairs of this form.
Possible types are:
- :class:`dict`
- :class:`tuple` or :class:`list`
- :class:`io.IOBase`, e.g. a file-like object
- :class:`multidict.MultiDict` or :class:`multidict.MultiDictProxy`
If it is a :class:`tuple` or :class:`list`, it must be a valid argument
for :meth:`add_fields<aiohttp.FormData.add_fields>`.
For :class:`dict`, :class:`multidict.MultiDict`, and :class:`multidict.MultiDictProxy`,
the keys and values must be valid `name` and `value` arguments to
:meth:`add_field<aiohttp.FormData.add_field>`, respectively. .. method:: add_field(name, value, content_type=None, filename=None,
content_transfer_encoding=None)
Add a field to the form.
:param str name: Name of the field
:param value: Value of the field
Possible types are:
- :class:`str`
- :class:`bytes`, :class:`bytearray`, or :class:`memoryview`
- :class:`io.IOBase`, e.g. a file-like object
:param str content_type: The field's content-type header (optional)
:param str filename: The field's filename (optional)
If this is not set and ``value`` is a :class:`bytes`, :class:`bytearray`,
or :class:`memoryview` object, the `name` argument is used as the filename
unless ``content_transfer_encoding`` is specified.
If ``filename`` is not set and ``value`` is an :class:`io.IOBase`
object, the filename is extracted from the object if possible.
:param str content_transfer_encoding: The field's content-transfer-encoding
header (optional).. method:: add_fields(fields)
Add one or more fields to the form.
:param fields: An iterable containing:
- :class:`io.IOBase`, e.g. a file-like object
- :class:`multidict.MultiDict` or :class:`multidict.MultiDictProxy`
- :class:`tuple` or :class:`list` of length two, containing a name-value pairClient exceptions
Exception hierarchy has been significantly modified in version
2.0. aiohttp defines only exceptions that covers connection handling
and server response misbehaviors. For developer specific mistakes,
aiohttp uses python standard exceptions like :exc:ValueError or
:exc:TypeError.
Reading a response content may raise a :exc:ClientPayloadError
exception. This exception indicates errors specific to the payload
encoding. Such as invalid compressed data, malformed chunked-encoded
chunks or not enough data that satisfy the content-length header.
All exceptions are available as members of aiohttp module.
.. exception:: ClientError
:canonical: aiohttp.client_exceptions.ClientError
Base class for all client specific exceptions.
Derived from :exc:Exception
.. class:: ClientPayloadError
:canonical: aiohttp.client_exceptions.ClientPayloadError
This exception can only be raised while reading the response
payload if one of these errors occurs:
- invalid compression
- malformed chunked encoding
- not enough data that satisfy
Content-LengthHTTP header.
Derived from :exc:ClientError
.. class:: UploadAbortedError
:canonical: aiohttp.client_exceptions.UploadAbortedError
Set on :attr:UploadTracker.upload_complete when the request body
was never fully sent.
Derived from :exc:ClientError
.. versionadded:: 3.14.4
.. exception:: InvalidURL
:canonical: aiohttp.client_exceptions.InvalidURL
URL used for fetching is malformed, e.g. it does not contain host
part.
Derived from :exc:ClientError and :exc:ValueError
.. attribute:: url
Invalid URL, :class:`yarl.URL` instance.
.. attribute:: description
Invalid URL description, :class:`str` instance or :data:`None`... exception:: InvalidUrlClientError
:canonical: aiohttp.client_exceptions.InvalidUrlClientError
Base class for all errors related to client url.
Derived from :exc:InvalidURL
.. exception:: RedirectClientError
:canonical: aiohttp.client_exceptions.RedirectClientError
Base class for all errors related to client redirects.
Derived from :exc:ClientError
.. exception:: NonHttpUrlClientError
:canonical: aiohttp.client_exceptions.NonHttpUrlClientError
Base class for all errors related to non http client urls.
Derived from :exc:ClientError
.. exception:: InvalidUrlRedirectClientError
:canonical: aiohttp.client_exceptions.InvalidUrlRedirectClientError
Redirect URL is malformed, e.g. it does not contain host part.
Derived from :exc:InvalidUrlClientError and :exc:RedirectClientError
.. exception:: NonHttpUrlRedirectClientError
:canonical: aiohttp.client_exceptions.NonHttpUrlRedirectClientError
Redirect URL does not contain http schema.
Derived from :exc:RedirectClientError and :exc:NonHttpUrlClientError
Response errors
^^^^^^^^^^^^^^^
.. exception:: ClientResponseError
:canonical: aiohttp.client_exceptions.ClientResponseError
These exceptions could happen after we get response from server.
Derived from :exc:ClientError
.. attribute:: request_info
Instance of :class:`RequestInfo` object, contains information
about request... attribute:: status
HTTP status code of response (:class:`int`), e.g. ``400``... attribute:: message
Message of response (:class:`str`), e.g. ``"OK"``... attribute:: headers
Headers in response, a list of pairs... attribute:: history
History from failed response, if available, else empty tuple.
A :class:`tuple` of :class:`ClientResponse` objects used for
handle redirection responses... attribute:: code
HTTP status code of response (:class:`int`), e.g. ``400``.
.. deprecated:: 3.1.. class:: ContentTypeError
:canonical: aiohttp.client_exceptions.ContentTypeError
Invalid content type.
Derived from :exc:ClientResponseError
.. versionadded:: 2.3
.. class:: TooManyRedirects
:canonical: aiohttp.client_exceptions.TooManyRedirects
Client was redirected too many times.
Maximum number of redirects can be configured by using
parameter max_redirects in :meth:request<aiohttp.ClientSession.request>.
Derived from :exc:ClientResponseError
.. versionadded:: 3.2
.. class:: WSServerHandshakeError
:canonical: aiohttp.client_exceptions.WSServerHandshakeError
Web socket server response error.
Derived from :exc:ClientResponseError
.. exception:: WSMessageTypeError
:canonical: aiohttp.client_exceptions.WSMessageTypeError
Received WebSocket message of unexpected type
Derived from :exc:TypeError
Connection errors
^^^^^^^^^^^^^^^^^
.. class:: ClientConnectionError
:canonical: aiohttp.client_exceptions.ClientConnectionError
These exceptions related to low-level connection problems.
Derived from :exc:ClientError
.. class:: ClientConnectionResetError
:canonical: aiohttp.client_exceptions.ClientConnectionResetError
Derived from :exc:ClientConnectionError and :exc:ConnectionResetError
.. class:: ClientOSError
:canonical: aiohttp.client_exceptions.ClientOSError
Subset of connection errors that are initiated by an :exc:OSError
exception.
Derived from :exc:ClientConnectionError and :exc:OSError
.. class:: ClientConnectorError
:canonical: aiohttp.client_exceptions.ClientConnectorError
Connector related exceptions.
Derived from :exc:ClientOSError
.. attribute:: ssl
The value passed as the ``ssl`` parameter of the request: an
:class:`ssl.SSLContext`, a :class:`bool`, or a
:class:`~aiohttp.Fingerprint`... class:: ClientConnectorDNSError
:canonical: aiohttp.client_exceptions.ClientConnectorDNSError
DNS resolution error.
Derived from :exc:ClientConnectorError
.. class:: ClientProxyConnectionError
:canonical: aiohttp.client_exceptions.ClientProxyConnectionError
Derived from :exc:ClientConnectorError
.. class:: ClientSSLError
:canonical: aiohttp.client_exceptions.ClientSSLError
Derived from :exc:ClientConnectorError
.. class:: ClientConnectorSSLError
:canonical: aiohttp.client_exceptions.ClientConnectorSSLError
Response ssl error.
Derived from :exc:ClientSSLError and :exc:ssl.SSLError
.. class:: ClientConnectorCertificateError
:canonical: aiohttp.client_exceptions.ClientConnectorCertificateError
Response certificate error.
Derived from :exc:ClientSSLError and :exc:ssl.CertificateError
.. class:: UnixClientConnectorError
:canonical: aiohttp.client_exceptions.UnixClientConnectorError
Derived from :exc:ClientConnectorError
.. class:: ServerConnectionError
:canonical: aiohttp.client_exceptions.ServerConnectionError
Derived from :exc:ClientConnectionError
.. class:: ServerDisconnectedError
:canonical: aiohttp.client_exceptions.ServerDisconnectedError
Server disconnected.
Derived from :exc:~aiohttp.ServerConnectionError
.. attribute:: message
Partially parsed HTTP message (optional)... class:: ServerFingerprintMismatch
:canonical: aiohttp.client_exceptions.ServerFingerprintMismatch
Server fingerprint mismatch.
Derived from :exc:ServerConnectionError
.. class:: ServerTimeoutError
:canonical: aiohttp.client_exceptions.ServerTimeoutError
Server operation timeout: read timeout, etc.
To catch all timeouts, including the total timeout, use
:exc:asyncio.TimeoutError.
Derived from :exc:ServerConnectionError and :exc:asyncio.TimeoutError
.. class:: ConnectionTimeoutError
:canonical: aiohttp.client_exceptions.ConnectionTimeoutError
Connection timeout on connect and sock_connect timeouts.
Derived from :exc:ServerTimeoutError
.. class:: SocketTimeoutError
:canonical: aiohttp.client_exceptions.SocketTimeoutError
Reading from socket timeout on sock_read timeout.
Derived from :exc:ServerTimeoutError
Hierarchy of exceptions
^^^^^^^^^^^^^^^^^^^^^^^
:exc:
ClientError:exc:
ClientConnectionError:exc:
ClientConnectionResetError:exc:
ClientOSError:exc:
ClientConnectorError:exc:
ClientProxyConnectionError:exc:
ClientConnectorDNSError:exc:
ClientSSLError:exc:
ClientConnectorCertificateError:exc:
ClientConnectorSSLError
:exc:
UnixClientConnectorError
:exc:
ServerConnectionError:exc:
ServerDisconnectedError:exc:
ServerFingerprintMismatch:exc:
ServerTimeoutError:exc:
ConnectionTimeoutError:exc:
SocketTimeoutError
:exc:
ClientPayloadError:exc:
UploadAbortedError:exc:
ClientResponseError:exc:
~aiohttp.ClientHttpProxyError:exc:
ContentTypeError:exc:
TooManyRedirects:exc:
WSServerHandshakeError
:exc:
InvalidURL:exc:
InvalidUrlClientError- :exc:
InvalidUrlRedirectClientError
- :exc:
:exc:
NonHttpUrlClientError- :exc:
NonHttpUrlRedirectClientError
- :exc:
:exc:
RedirectClientError:exc:
InvalidUrlRedirectClientError:exc:
NonHttpUrlRedirectClientError
Client Types
.. type:: ClientMiddlewareType
Type alias for client middleware functions. Middleware functions must have this signature::
Callable[
[ClientRequest, ClientHandlerType],
Awaitable[ClientResponse]
].. type:: ClientHandlerType
Type alias for client request handler functions::
Callable[[ClientRequest], Awaitable[ClientResponse]]File: docs/contributing.rst
.. _aiohttp-contributing:
Contributing
(:doc:contributing-admins)
Instructions for contributors
In order to make a clone of the GitHub_ repo: open the link and press the "Fork" button on the upper-right menu of the web page.
I hope everybody knows how to work with git and github nowadays :)
Workflow is pretty straightforward:
Make sure you are reading the latest version of this document.
It can be found in the GitHub_ repo in thedocssubdirectory.Clone the GitHub_ repo using the
--recurse-submodulesargumentSetup your machine with the required development environment
Make a change
Make sure all tests passed
Add a file into the
CHANGESfolder (seeChangelog update_ for how).Commit changes to your own aiohttp clone
Make a pull request from the github page of your clone against the master branch
Optionally make backport Pull Request(s) for landing a bug fix into released aiohttp versions.
.. note::
The project uses Squash-and-Merge strategy for GitHub Merge button.
Basically it means that there is no need to rebase a Pull Request against
master branch. Just git merge master into your working copy (a fork) if
needed. The Pull Request is automatically squashed into the single commit
once the PR is accepted.
.. note::
GitHub issue and pull request threads are automatically locked when there has
not been any recent activity for one year. Please open a new issue <https://github.com/aio-libs/aiohttp/issues/new>_ for related bugs.
If you feel like there are important points in the locked discussions,
please include those excerpts into that new issue.
Preconditions for running aiohttp test suite
We expect you to use a python virtual environment to run our tests.
There are several ways to make a virtual environment.
If you like to use virtualenv please run:
.. code-block:: shell
$ cd aiohttp
$ virtualenv --python=which python3 venv
$ . venv/bin/activate
For standard python venv:
.. code-block:: shell
$ cd aiohttp
$ python3 -m venv venv
$ . venv/bin/activate
For virtualenvwrapper:
.. code-block:: shell
$ cd aiohttp
$ mkvirtualenv --python=which python3 aiohttp
There are other tools like pyvenv but you know the rule of thumb now: create a python3 virtual environment and activate it.
After that please install libraries required for development:
.. code-block:: shell
$ make install-dev
.. note::
For now, the development tooling depends on make and assumes an Unix OS If you wish to contribute to aiohttp from a Windows machine, the easiest way is probably to configure the WSL <https://docs.microsoft.com/en-us/windows/wsl/install-win10>_ so you can use the same instructions. If it's not possible for you or if it doesn't work, please contact us so we can find a solution together.
Install pre-commit hooks:
.. code-block:: shell
$ pre-commit install
.. warning::
If you plan to use temporary print(), pdb or ipdb within the test suite, execute it with -s
and without the parallel pytest-xdist workers that are enabled by default:
.. code-block:: shell
$ pytest tests -s --numprocesses=0in order to run the tests without output capturing.
Congratulations, you are ready to run the test suite!
.. include:: ../vendor/README.rst
Run autoformatter
The project uses black_ + isort_ formatters to keep the source code style.
Please run make fmt after every change before starting tests.
.. code-block:: shell
$ make fmtRun aiohttp test suite
After all the preconditions are met you can run tests typing the next
command:
.. code-block:: shell
$ make test
The command at first will run the linters (sorry, we don't accept
pull requests with pyflakes, black, isort, or mypy errors).
On lint success the tests will be run.
Please take a look on the produced output.
Any extra texts (print statements and so on) should be removed.
Code coverage
We use codecov.io as an indispensable tool for analyzing our coverage
results. Visit https://codecov.io/gh/aio-libs/aiohttp to see coverage
reports for the master branch, history, pull requests etc.
We'll use an example from a real PR to demonstrate how we use this.
Once the tests run in a PR, you'll see a comment posted by codecov.
The most important thing to check here is whether there are any new
missed or partial lines in the report:
.. image:: _static/img/contributing-cov-comment.svg
Here, the PR has introduced 1 miss and 2 partials. Now we
click the link in the comment header to open the full report:
.. image:: _static/img/contributing-cov-header.svg
:alt: Codecov report
Now, if we look through the diff under 'Files changed' we find one of
our partials:
.. image:: _static/img/contributing-cov-partial.svg
:alt: A while loop with partial coverage.
In this case, the while loop is never skipped in our tests. This is
probably not worth writing a test for (and may be a situation that is
impossible to trigger anyway), so we leave this alone.
We're still missing a partial and a miss, so we switch to the
'Indirect changes' tab and take a look through the diff there. This
time we find the remaining 2 lines:
.. image:: _static/img/contributing-cov-miss.svg
:alt: An if statement that isn't covered anymore.
After reviewing the PR, we find that this code is no longer needed as
the changes mean that this method will never be called under those
conditions. Thanks to this report, we were able to remove some
redundant code from a performance-critical part of our codebase (this
check would have been run, probably multiple times, for every single
incoming request).
.. tip::
Sometimes the diff on codecov.io doesn't make sense. This is usually
caused by the branch being out of sync with master. Try merging
master into the branch and it will likely fix the issue. Failing
that, try checking coverage locally as described in the next section.
Other tools
The browser extension https://docs.codecov.io/docs/browser-extension
is also a useful tool for analyzing the coverage directly from Files
Changed tab on the GitHub Pull Request review page.
You can also produce coverage reports locally with make cov-dev
or just adding --cov-report=html to pytest.
This will run the test suite and collect coverage information. Once
finished, coverage results can be view by opening:
$ python -m webbrowser -n file://"$(pwd)"/htmlcov/index.htmlDocumentation
We encourage documentation improvements.
Please before making a Pull Request about documentation changes run:
.. code-block:: shell
$ make doc
Once it finishes it will output the index html pageopen file:///.../aiohttp/docs/_build/html/index.html.
Go to the link and make sure your doc changes looks good.
Spell checking
We use pyenchant and sphinxcontrib-spelling for running spell
checker for documentation:
.. code-block:: shell
$ make doc-spelling
Unfortunately there are problems with running spell checker on MacOS X.
To run spell checker on Linux box you should install it first:
.. code-block:: shell
$ sudo apt-get install enchant
$ pip install sphinxcontrib-spelling
Preparing a pull request
When making a pull request, please include a short summary of the changes
and a reference to any issue tickets that the PR is intended to solve.
All PRs with code changes should include tests. All changes should
include a changelog entry.
Changelog update
.. include:: ../CHANGES/README.rst
Making a pull request
After finishing all steps make a GitHub_ Pull Request with master base branch.
Backporting
All Pull Requests are created against master git branch.
If the Pull Request is not a new functionality but bug fixing
backport to maintenance branch would be desirable.
aiohttp project committer may ask for making a backport of the PR
into maintained branch(es), in this case he or she adds a github label
like needs backport to 3.1.
Backporting is performed after main PR merging into master.
Please do the following steps:
Find Pull Request's commit for cherry-picking.
aiohttp does squashing PRs on merging, so open your PR page on
github and scroll down to message likeasvetlov merged commit f7b8921 into master 9 days ago.f7b8921is the required commit number.Run
cherry_picker <https://github.com/python/core-workflow/tree/master/cherry_picker>_
tool for making backport PR (the tool is already pre-installed from./requirements/dev.txt), e.g.cherry_picker f7b8921 3.1.In case of conflicts fix them and continue cherry-picking by
cherry_picker --continue.cherry_picker --abortstops the process.cherry_picker --statusshows current cherry-picking status
(likegit status)After all conflicts are done the tool opens a New Pull Request page
in a browser with pre-filed information. Create a backport Pull
Request and wait for review/merging.aiohttp committer should remove backport Git label after
merging the backport.
How to become an aiohttp committer
Contribute!
The easiest way is providing Pull Requests for issues in our bug
tracker. But if you have a great idea for the library improvement
-- please make an issue and Pull Request.
The rules for committers are simple:
- No wild commits! Everything should go through PRs.
- Take a part in reviews. It's very important part of maintainer's activity.
- Pickup issues created by others, especially if they are simple.
- Keep test suite comprehensive. In practice it means leveling up
coverage. 97% is not bad but we wish to have 100% someday. Well, 99%
is good target too. - Don't hesitate to improve our docs. Documentation is a very important
thing, it's the key for project success. The documentation should
not only cover our public API but help newbies to start using the
project and shed a light on non-obvious gotchas.
After positive answer aiohttp committer creates an issue on github
with the proposal for nomination. If the proposal will collect only
positive votes and no strong objection -- you'll be a new member in
our team.
.. _GitHub: https://github.com/aio-libs/aiohttp
.. _ipdb: https://pypi.python.org/pypi/ipdb
.. _black: https://pypi.python.org/pypi/black
.. _isort: https://pypi.python.org/pypi/isort
File: docs/contributing-admins.rst
:orphan:
Instructions for aiohttp admins
This page is intended to document certain processes for admins of the aiohttp repository.
For regular contributors, return to :doc:contributing.
.. contents::
:local:
:depth: 1
.. highlight:: none
Running reproducer code
.. warning::
When evaluating a bug report or vulnerability report, treat reproducer code as
untrusted. If you don't understand what it does or are unfamiliar with a library
it imports do not run it (and ask the reporter to provide a simpler reproducer).
We also recommend that any reproducers you do run are executed in a container.
Creating a new release
.. note:: The example commands assume that origin refers to the aio-libs repository.
To create a new release:
#. Start on the branch for the release you are planning (e.g. 3.8 for v3.8.6): git checkout 3.8 && git pull
#. Update the version number in __init__.py.
#. Run towncrier.
#. Check and cleanup the changes in CHANGES.rst.
#. Checkout a new branch: e.g. git checkout -b release/v3.8.6
#. Commit and create a PR. Verify the changelog and release notes look good on Read the Docs. Once PR is merged, continue.
#. Go back to the release branch: e.g. git checkout 3.8 && git pull
#. Add a tag: e.g. git tag -a v3.8.6 -m 'Release 3.8.6' -s
#. Push the tag: e.g. git push origin v3.8.6
#. Monitor CI to ensure release process completes without errors.
Once released, we need to complete some cleanup steps (no further steps are needed for
non-stable releases though). If doing a patch release, we need to do the below steps twice,
first merge into the newer release branch (e.g. 3.8 into 3.9) and then to master
(e.g. 3.9 into master). If a new minor release, then just merge to master.
#. Switch to target branch: e.g. git checkout 3.9 && git pull
#. Start a merge: e.g. git merge 3.8 --no-commit --no-ff --gpg-sign
#. Carefully review the changes and revert anything that should not be included (most
things outside the changelog). Use git checkout 3.9 path/to/file to revert files
without aborting the merge.
#. To ensure change fragments are cleaned up properly, run: python tools/cleanup_changes.py
#. Complete the merge: git merge --continue.
#. Push the branch directly to Github (because a PR would get squashed). When pushing,
you may get a rejected message. Follow these steps to resolve:
#. Checkout to a new branch and push: e.g. git checkout -b do-not-merge && git push
#. Open a draft PR with a title of 'DO NOT MERGE'.
#. Once the CI has completed on that branch, you should be able to switch back and push
the target branch (as tests have passed on the merge commit now).
#. This should automatically consider the PR merged and delete the temporary branch.
Back on the original release branch, bump the version number and append .dev0 in __init__.py.
Post the release announcement to social media:
- BlueSky: https://bsky.app/profile/aiohttp.org and re-post to https://bsky.app/profile/aio-libs.org
- Mastodon: https://fosstodon.org/@aiohttp and re-post to https://fosstodon.org/@aio_libs
If doing a minor release:
#. Create a new release branch for future features to go to: e.g. git checkout -b 3.10 3.9 && git push
#. Update both target-branch backports for Dependabot to reference the new branch name in .github/dependabot.yml.
#. Delete the older backport label (e.g. backport-3.8): https://github.com/aio-libs/aiohttp/labels
#. Add a new backport label (e.g. backport-3.10).
Incident response
This section covers responding to a reported security vulnerability and to
three classes of compromise -- of the supply chain, of a maintainer account,
and of the project infrastructure. It picks up after a report or a problem
is in hand.
.. note::
Vulnerability reports arrive through the organization's SECURITY.md
-- GitHub private vulnerability reporting, or email to the security coordinators.
Never triage a suspected vulnerability in a public issue or pull request.
The security coordinator who first triages a report is its incident lead,
and may explicitly hand off to another coordinator. The lead owns the GitHub
Security Advisory (GHSA) draft, fix coordination, the release, and notification.
Severity tiers
aiohttp is volunteer-maintained, so there is no response-time commitment. The
tier guides prioritization, the release decision, and how widely the fix is
announced. All security fixes -- regardless of tier -- land on ``master`` and
are backported to the currently supported ``x.y`` branch (and the next
``x.y`` branch, if one is in development).
High
A concrete remote impact an attacker can actually achieve against a
default deployment. Examples: a single request that stops the server from
handling further requests (a server-wide denial of service), reading files
on the server outside the project root, remote code execution,
authentication bypass. Cut a dedicated security release once the fix lands.
Medium
Bounded impact, or impact that needs a non-default option, an unusual
configuration, or a local position. Examples: request smuggling demonstrated
to cause a real issue against a common proxy, or a DoS that use significant server
resources with a low effort sustained attack.
Cut a dedicated security release.
Low
Limited or hard-to-exploit impact, or impact confined to debug or
non-default paths. Examples: minor version or error-message disclosure,
parser leniency with no demonstrated security impact, or request smuggling
that has not been demonstrated to cause a real issue against a common
proxy. May ride the next routine release rather than cutting a dedicated
security release.
Severity is rated by demonstrated attacker impact. A denial of service that
disables further request handling for the whole server from a single request
leans High; one that requires sustained low-effort traffic to consume
significant server resources leans Medium. Request smuggling and parser bugs
are rated by what an attacker can actually achieve against a common proxy or
in a realistic deployment, not by the shape of the bug.
Responding to a reported vulnerability#. Acknowledge and confirm. Reply to the reporter in the GitHub private
report or the email thread. Reproduce the issue
(but don't run untrusted code <Running reproducer code_>_) against
master and the maintained x.y branches. If it is not reproducible
or is out of scope, record the decision and close the report.
#. Open the GHSA draft. For an email report, if the reporter can't use Github
for some reason, then open a new advisory to track the issue.
#. Develop the fix privately in the GHSA's temporary private fork ("Start a
temporary private fork" in the draft) -- never on a public branch or in a
public pull request. Include a regression test unless it would provide too
much information for an attacker to replicate.
#. Title the advisory with the vulnerability class and affected component.
#. Write the description using the GHSA description template::
### Summary
<one or two sentences describing the vulnerability>
### Impact
<who is affected, prerequisites, and what an attacker achieves>
### Workaround
---
Patch: <link to commit fixing the issue on the stable x.y branch> An important detail that Github will use to decide the CVE severity is exploit
maturity. Try to clarify the likelihood of a vulnerability being attacked
(e.g. if exploit code is available, or active attacks in-the-wild already exist).
#. Set the affected and fixed versions.
#. Assign a severity tier (see Severity tiers).
#. Credit the reporter (if report came by email) in the GHSA Credits field.
#. Credit the developer using "Remediation developer" if different from Reporter.
#. Request a CVE by clicking the button in the advisory.
#. Get the fix reviewed in the private fork by at least one other maintainer.
#. Consider early notify for high severity issues
(see Notifying about a disclosed vulnerability).
#. Coordinate a release.
#. Agree the timing. For an embargoed high-severity incident, set the
release date to align with the lift of any private-list embargo.
#. Merge all the private forks and create and merge the backports for
each.
#. Create the release. Follow Creating a new release.
#. Update patch link in GHSA description.
#. Publish the GHSA usually around 1 day after release.
#. Notify according to the severity tier
(see Notifying about a disclosed vulnerability).
#. Run the post-incident steps (see Post-incident_).
Notifying about a disclosed vulnerability
Notification is cumulative -- each tier adds to the ones below it. Mind the
timing: the ``linux-distros`` pre-notification happens under embargo, *before*
the release, while everything else happens at or after the release.
Baseline (all severities)
The published GHSA (which feeds the CVE and the GitHub Advisory Database).
Higher (Medium-High)
For most high severity issues, additionally post to the public ``oss-security``
mailing list once the advisory is public.
Highest (High-Critical)
For the most serious issues, additionally *before* the public release, send
an embargoed pre-notification to the private distribution-security lists -- primarily
``linux-distros`` -- and attempt to notify affected downstreams. Use the
`vuln_search.py dependents-enumeration script
<https://github.com/aio-libs/.github/blob/master/tools/vuln_search.py>`_
to search aiohttp's GitHub dependents; it needs a GitHub token and may need to be
run over a few days, so start it early.
Keep the embargo as short as practical. Typically an embargo of 1 or 2 days is expected.
Template for the embargoed ``linux-distros`` pre-notification::
To: [email protected]
Subject: aiohttp: <one-line summary of the vulnerability>
We are coordinating disclosure of a security vulnerability in aiohttp
(https://github.com/aio-libs/aiohttp), the asyncio HTTP client/server
library.
Summary
<2-3 sentences: the flaw and its impact>
Affected versions
<e.g. aiohttp < 3.12.15 (all 3.11.x and 3.12.x)>
CVE
<CVE-XXXX-XXXXX, or "requested via GitHub Security Advisory, ID pending">
Fix
<link to the patch, or attach the diff>
Proposed public disclosure date
<YYYY-MM-DD> -- as short as practical. On that date we will publish the
GitHub Security Advisory, ship a patched PyPI release, and post to
oss-security.
This issue is not yet public; please observe the embargo until that date.
Contact:
Template for the public ``oss-security`` disclosure::
To: [email protected]
Subject: CVE-XXXX-XXXXX: aiohttp <one-line summary>
A security vulnerability has been fixed in aiohttp, the asyncio HTTP
client/server library (https://github.com/aio-libs/aiohttp).
CVE: CVE-XXXX-XXXXX
Advisory: <GHSA URL>
Affected versions: <...>
Fixed versions: <...>
Description
<what the flaw is>
Impact
<what an attacker can achieve, and any prerequisites>
Mitigation
<workaround, or "upgrade to <version>">
Post-incident
~~~~~~~~~~~~~
#. **Update** ``THREAT_MODEL.md``. Have an AI coding agent fetch the new advisories
and update the document. Review the changes.
#. **File follow-up hardening** as ordinary public issues or pull requests.
Supply-chain or release compromise
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A malicious or tampered release on PyPI, or a compromised publish pipeline.
#. **Pull the bad artifact.** On PyPI, *yank* the affected release -- this
hides it from new resolves while keeping existing pins working. *Delete* it
only if it is actively malicious and removal is the safer choice. This needs
a PyPI project owner or maintainer account.
#. **Verify the legitimate artifacts with Sigstore.** Every genuine release is
signed by the release pipeline, with the ``.sigstore`` bundles attached to
the GitHub Release. Verify the ``sdist`` and wheels; a divergence from what is on
PyPI localizes the tampering.
#. **Lock the publish path.** Publishing uses a PyPI OIDC trusted publisher, so
there is no long-lived token to rotate. Instead, on PyPI temporarily remove
the trusted-publisher binding, and on GitHub restrict or pause the ``pypi``
deployment environment used by the release job.
#. **Audit the release inputs.** Review recent changes to the release workflow,
its tag trigger, and the third-party action versions it uses.
#. **Audit the committed Cython sources.** The generated ``.c`` files ship in
the ``sdist`` and are not checked against their ``.pyx`` sources in CI (see
``THREAT_MODEL.md`` section 5.19). Regenerate them with ``make cythonize``
and ``git diff`` against the released revision. Re-verify the
``vendor/llhttp`` pin and ``package-lock.json``.
#. **Reissue a clean release** via `Creating a new release`_ once the cause is
fixed. Never re-publish over a yanked version number.
#. **Notify** per severity -- a malicious published release is High.
Maintainer account compromise
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A GitHub or PyPI account takeover, or leaked publishing or signing material.
#. **Suspend the account.** Another GitHub organization owner can suspend it,
revoke its repository access, and start the audit-log review. If the
compromised account is the sole organization owner, or no other owner is
reachable, contact GitHub Support at https://support.github.com/contact
for emergency account lock down and organization recovery.
#. **Kill sessions and credentials** on the affected account. On GitHub: change
the password, sign out all sessions, revoke every personal access token,
OAuth app, and SSH or GPG key, then re-enroll two-factor authentication.
On PyPI: change the password, re-enroll two-factor authentication,
and revoke API tokens.
#. **Audit PyPI project ownership.** OIDC publishing means there is usually no
long-lived PyPI token to leak, but a compromised project owner can add a
trusted publisher or upload directly. Review the project collaborators and
trusted-publisher bindings, and remove anything unrecognized.
#. **Audit what the account could have done** from the GitHub audit log:
pushes, tag creation, branch-protection or settings changes, new secrets or
deploy keys, new collaborators, and workflow edits.
#. **Revert and re-verify.** Force-revert any unauthorized commits or tags, and
re-verify recent releases against their ``Sigstore`` bundles. If a malicious
release shipped, escalate to `Supply-chain or release compromise`_.
#. **Handle signing material.** ``Sigstore`` signing is key-less, so there is no
static signing key to rotate. Any separate GPG key used for signed tags must
be treated as compromised, then revoked and rotated.
CI or infrastructure compromise
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A compromise of GitHub Actions, repository settings, or branch protections.
#. **Freeze the release path.** Pause the ``pypi`` deployment environment and
stop tag-triggered deploys until the compromise is scoped.
#. **Review branch protection and required reviews** on ``master`` and the
``x.y`` branches. These are enforced on GitHub and are not visible in the
repository; confirm nothing was relaxed and restore the known-good
configuration.
#. **Audit Actions secrets and environments** -- the repository and
organization secrets, the ``pypi`` environment's protection rules and
reviewers, and any new deploy keys. Confirm the workflow keeps empty
top-level permissions and that ``id-token: write`` is scoped to the deploy
job only.
#. **Diff recently changed workflows** with ``git log -- .github/workflows/``,
especially the release workflow, the auto-merge workflow (which runs in the
privileged ``pull_request_target`` context), and the CodeQL workflow. Look
for added steps, changed action references, or new triggers.
#. **Check the committed Cython sources** as in `Supply-chain or release
compromise`_ -- regenerate them and ``git diff``.
#. **Re-pin and rebuild.** If a third-party action was compromised, pin the
affected actions by full commit hash, re-run CI from a clean known-good
revision, and re-verify with ``Sigstore`` any release made during the suspected
window.
#. **Escalate** to `Supply-chain or release compromise`_ if a release shipped
through the compromised pipeline.
## 2. Official Technical Reference & Guides (aio-libs/aio-libs.github.io)
## File: content/pages/projects/aiohttp.md
Title: Aiohttp
Links: Documentation=https://docs.aiohttp.org/en/stable/
Github=https://github.com/aio-libs/aiohttp/
Sponsorship=https://opencollective.com/aio-libs/projects/aiohttp
An asynchronous HTTP Client/Server for Python's [asyncio](https://docs.python.org/3/library/asyncio.html), built on the [llhttp](https://llhttp.org/) C parser with Cython-accelerated hot paths.
Sharing client and server in a single, well-tested dependency โ with [WebSockets](https://docs.aiohttp.org/en/stable/client_quickstart.html#websockets) and [middlewares](https://docs.aiohttp.org/en/stable/web_advanced.html#middlewares) on both sides โ keeps things simple when you're building services that both consume and serve HTTP.
aiohttp powers [Home Assistant](https://www.home-assistant.io/), [Pulp](https://pulpproject.org/), [aiogram](https://aiogram.dev/), the [Molotov](https://molotov.readthedocs.io/) load tester, and [many others](https://docs.aiohttp.org/en/stable/built_with.html).
As a [client](https://docs.aiohttp.org/en/stable/client.html), aiohttp provides:
- Connection pooling and a shared cookie jar across requests.
- Streaming uploads and downloads.
- [WebSocket](https://docs.aiohttp.org/en/stable/client_quickstart.html#websockets) support.
- [Middlewares](https://docs.aiohttp.org/en/stable/client_advanced.html#client-middleware) to customise request/response processing.
- [Tracing hooks](https://docs.aiohttp.org/en/stable/tracing_reference.html) for observability.
As a [web server/framework](https://docs.aiohttp.org/en/stable/web.html), aiohttp provides:
- [WebSocket](https://docs.aiohttp.org/en/stable/web_quickstart.html#websockets) support.
- [Middlewares](https://docs.aiohttp.org/en/stable/web_advanced.html#middlewares) to customise
request/response processing.
- Optional [handler cancellation](https://docs.aiohttp.org/en/stable/web_advanced.html#web-handler-cancellation) when a client disconnects.
- First-party [testing utilities](https://docs.aiohttp.org/en/stable/testing.html), including a [pytest-aiohttp](https://github.com/aio-libs/pytest-aiohttp) plugin.
- An extensive collection of [first and third party libraries](https://docs.aiohttp.org/en/stable/third_party.html) extending the core functionality.
---
## File: content/pages/index.md
Title: About us
Status: hidden
save_as: index.html
We are a co-operative of developers who maintain open-source libraries for use with Python's [asyncio](https://docs.python.org/3/library/asyncio.html), including the popular [[aiohttp]] library.
## Sponsors
Aio-libs would not be possible without our amazing sponsors. Please consider [joining them](/sponsor_us/) to help fund our work.
{% sponsors gold %}
{% sponsors silver %}
## Aio-libs
This website exists to showcase the work that we do across aio-libs.
Under projects you can view the various libraries we maintain (more to be added soon).
Under news you can read the latest posts from us where we talk about some of the things we've been working on and give you some behind-the-scenes views of the work we've been doing.
If you want to follow along, there is an Atom feed for all news, as well as a feed for each category if you're only interested in particular areas of our work.
---
## File: content/pages/projects.md
Title: Projects
Template: projects
Status: hidden
The various libraries we maintain.
---
## File: content/pages/sponsorship.md
Title: Sponsor us
Aio-libs would not be possible without our amazing sponsors. Please consider joining them to help fund our work.
Our sponsorships are managed by [Open Collective](https://opencollective.com/aio-libs).
{% sponsors gold %}
{% sponsors silver %}
{% sponsors bronze %}
---
## File: content/news/aiohttp/2026-05-18_introducing-aiohttp.md
Title: Introducing aiohttp
Tags: aio-libs, aiohttp
Most of you reading this already know [[aiohttp]] as the longest-running asynchronous HTTP client for Python's [asyncio](https://docs.python.org/3/library/asyncio.html).
What is less widely known is that the same package also ships a full-featured web server and framework, available under `aiohttp.web`.
As a [client](https://docs.aiohttp.org/en/stable/client.html), aiohttp offers an ergonomic API for concurrent HTTP and WebSocket traffic, with [middlewares](https://docs.aiohttp.org/en/stable/client_advanced.html#client-middleware) to customise request and response processing and [tracing hooks](https://docs.aiohttp.org/en/stable/tracing_reference.html) for observability.
As a [web server and framework](https://docs.aiohttp.org/en/stable/web.html), `aiohttp.web` covers what you'd expect from a modern framework - WebSockets, middlewares, and an extensive ecosystem of [first and third party libraries](https://docs.aiohttp.org/en/stable/third_party.html) extending the core functionality.
Rarer is its optional [handler cancellation](https://docs.aiohttp.org/en/stable/web_advanced.html#web-handler-cancellation) when a client disconnects, sparing long-running handlers from finishing work no one is waiting for.
It has been quietly powering production services for years and is the backbone of Home Assistant.
Sharing client and server in a single, well-tested dependency keeps things simple when you're building services that both consume and serve HTTP, and aiohttp's focus on performance means you rarely have to reach for something else as traffic grows.
We'll be posting more about aiohttp here over time - new releases, deep dives, and behind-the-scenes notes from the maintainers.
If you'd like to follow along, subscribe to the [aiohttp tag feed](https://aio-libs.org/feeds/aiohttp.atom.xml).
---
## File: content/news/aio-libs/2026-02-18_new-site.md
Title: Welcome to the aio-libs site
We've just launched the new home page for aio-libs.
This is where we'll share updates and behind-the-scene looks at the work we've been doing across our projects.
You can subscribe to the [Atom feed](https://aio-libs.org/feeds/atom.xml) to get the latest updates as we post them.
The [aio-libs](https://aio-libs.org/feeds/aio-libs.atom.xml) tag will be used to discuss general updates around the
group and introduce new projects. More tags will be added later to cover other areas.
---
## File: content/news/aio-libs/2026-08-17_security-at-aio-libs.md
Title: How we handle security at aio-libs
Tags: aio-libs, aiohttp
[[aiohttp]] and the wider aio-libs family sit underneath a big slice of the Python ecosystem, which means our bugs become everyone else's bugs.
Security has always been part of the job, but the last year has seen a run of dedicated work on it - two external audits, a funded security program, and a lot of new processes.
## The day-to-day process
Everything starts with the reporting pipeline described in our organisation-wide [security policy](https://github.com/aio-libs/.github/blob/master/SECURITY.md).
We typically receive several reports per month and try to act on them promptly.
You can read how we handle these reports in our [incident response plan](https://docs.aiohttp.org/en/stable/contributing-admins.html#incident-response).
We typically issue CVEs for anything that could plausibly affect users, which means we may allocate more CVEs than some similar projects.
Additionally, aiohttp is a complex project and we must consider security relating to networking, HTTP parsing, general web framework and client code.
Most similar projects only deal with one of these areas.
On the supply-chain side, releases are published with PyPI trusted publishing (so there are no long-lived tokens to steal) and signed with [Sigstore](https://www.sigstore.dev/), CodeQL and Dependabot run on the repositories, and aiohttp's parsers have been fuzzed continuously by [OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/aiohttp) since 2022.
## A security audit, via NLnet
In 2025, [NLnet](https://nlnet.nl/) funded development work on aiohttp - [improving the type annotations](https://nlnet.nl/project/Aiohttp-typecheck/) - through the NGI Zero Commons Fund, backed by the European Commission's Next Generation Internet programme.
NGI Zero grants come with more than money though: projects also get access to [support services](https://nlnet.nl/NGI0/services/), including a professional security audit.
Ours was performed by [Radically Open Security](https://www.radicallyopensecurity.com/) - particular thanks to Thomas Rinsma - and its findings resulted in five CVEs: denial-of-service vectors like resource exhaustion via large payloads and an infinite loop when Python runs with assertions disabled, a brute-forceable path disclosure in static file handling, and parsing discrepancies around Unicode digits.
The fixes shipped in [aiohttp 3.13.3](https://github.com/aio-libs/aiohttp/releases/tag/v3.13.3) in January, [disclosed in a coordinated batch of eight advisories](https://www.openwall.com/lists/oss-security/2026/01/05/14) together with three issues from independent reporters.
Our thanks to NLnet for funding both the audit and the development time spent fixing the findings.
One of those reports is worth calling out explicitly: a high-severity decompression bomb ([CVE-2025-69223](https://github.com/aio-libs/aiohttp/security/advisories/GHSA-6mq8-rvhq-8wgg)), where a tiny compressed message inflates into a huge one when aiohttp decompresses it automatically.
It also wasn't ours to fix alone - the [brotli](https://github.com/google/brotli) library had no way to cap how much data a decompression call could produce - so the issue was disclosed to Google and we waited for them to provide a fix in brotli 1.2 before we could resolve it.
Due to architectural difficulties, the initial fix capped decompressed output at 32 MiB per call, which also blocked some legitimate highly-compressed payloads, so [aiohttp 3.14.0](https://github.com/aio-libs/aiohttp/releases/tag/v3.14.0) followed up with an overhaul of the decompression code that processes payloads incrementally in bounded chunks, safely handling any valid payload.
The final fix also reduced the amount of data in memory from 32 MiB to 256 KiB, matching most memory assumptions in the rest of the aiohttp code.
Coordinated disclosure sometimes has to run up the dependency chain as well as down it.
## The GitHub Secure Open Source Fund
In April we joined Session 4 of the [GitHub Secure Open Source Fund](https://github.com/open-source/github-secure-open-source-fund), alongside 49 other projects (including friends from the Python ecosystem).
The program pairs $10,000 of funding through GitHub Sponsors with a three-week security sprint - threat modeling, secure coding, vulnerability management and AI security, with a curriculum from GitHub Security Lab - and check-ins over the following year.
The funding is welcome, but the bigger value for us was momentum: a structured push, with security experts on hand, to clear a backlog of security process work.
While we found that we were already doing most of the recommendations covered in the program, we still found plenty of things to take our security to the next level.
So far, we have fixed up license files, written an incident response plan and a detailed threat model, plugged a gap in aiohttp's SBOM, and ran an AI-assisted audit over all our codebases.
The [threat model](https://docs.aiohttp.org/en/stable/threat_model.html) is the biggest piece: a STRIDE analysis of aiohttp covering nineteen subsystems, from the HTTP/1 parser through cookies and DNS resolution to the build and release supply chain.
For each one it records what we trust, what can go wrong, and which mitigations exist or are still wanted - including the mitigations that are the responsibility of applications built on aiohttp, which are explicitly marked as such.
We're still reviewing and publishing the remaining chapters, but expect to complete this over the next few months.
It's a living document: our incident-response process now ends with feeding each new advisory back into it.
This is really important in the age of AI-generated security reports; this is a tool that AI agents can use to verify if their report is actually valid and in scope, reducing the number of false positives getting reported to us.
The [incident response plan](https://docs.aiohttp.org/en/stable/contributing-admins.html#incident-response) writes down what used to be tribal knowledge: severity tiers, the advisory-to-release runbook, the disclosure and notification procedures, and - hopefully never needed - playbooks for a compromised release pipeline, maintainer account or CI.
The SBOM work fixes a blind spot: aiohttp vendors the [llhttp](https://github.com/nodejs/llhttp) parser as a git submodule, which GitHub's dependency graph can't see.
A [workflow](https://github.com/aio-libs/aiohttp/blob/master/.github/workflows/dependency-submission.yml) now registers the vendored llhttp version with the dependency graph on every push, so it appears in the exported SBOM and gets Dependabot alerts like any other dependency.
And the AI-assisted audit, run with GitHub Security Lab's [taskflow agent](https://github.com/GitHubSecurityLab/seclab-taskflows), found one more minor vulnerability in aiohttp - and, more usefully, several issues across other aio-libs projects that haven't seen the same level of scrutiny yet.
There's still more planned from the program: achieving [OpenSSF Baseline](https://baseline.openssf.org/) level 3, reviewing several new tools and configuration of existing ones, bringing the OSS-Fuzz integration into our repo, and generating runtime SBOMs to ship in the wheels.
## Patch the Planet
In June, aiohttp was one of the first projects taken through [Patch the Planet](https://openai.com/index/patch-the-planet/), an OpenAI initiative built with [Trail of Bits](https://blog.trailofbits.com/2026/06/22/introducing-patch-the-planet/) that points AI-assisted vulnerability research - validated by human security engineers - at critical open source projects, at no cost to the maintainers.
Trail of Bits privately reported a cluster of 10 issues (resulting in 8 CVEs) across our client and server code, including cookies that could regain a broader scope after a save and reload, digest credentials that would answer a challenge from the wrong origin, and resource limits that ran only after attacker-controlled buffering.
All fixes were written, reviewed and merged a couple of days later and shipped in [aiohttp 3.14.1](https://github.com/aio-libs/aiohttp/releases/tag/v3.14.1).
## Keeping it going
None of this makes aiohttp bug-free - every audit above found something, which is exactly why we keep inviting them.
Each round of fresh eyes turns into fixes, regression tests and threat model updates, and each program leaves the process a little stronger than it found it.
Our thanks to NLnet, Radically Open Security, GitHub, OpenAI, Trail of Bits, and every reporter credited in our advisories.
If you believe you've found a vulnerability in any aio-libs project, please report it privately by following our [security policy](https://github.com/aio-libs/.github/blob/master/SECURITY.md).
And if your business relies on this work, consider [sponsoring aio-libs](/sponsorship/) - almost everything above was done by volunteers.