## 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 like
``await 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.8

Abstract 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 framework
* `salted <https://github.com/RuedigerVoigt/salted>`_ fast link check library (for HTML, Markdown, LaTeX, ...) with CLI
* `Unofficial 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 <client_quickstart>
   Advanced Usage <client_advanced>
   Client Middleware Cookbook <client_middleware_cookbook>
   Reference <client_reference>
   Tracing Reference 
   The aiohttp Request Lifecycle <http_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 keyword
``json``::

    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://user@example.com`` redirects to
``http://other_user@example.com``, 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:

1. The first middleware in the list is called first and executes its code before calling the handler
2. The handler is the next middleware in the chain (or the request handler if there are no more middlewares)
3. When the handler returns a response, execution continues from the last middleware right after the handler call
4. This creates a nested "onion-like" pattern for execution

For example, with ``middlewares=(middleware1, middleware2)``, the execution order would be:

1. Enter ``middleware1`` (pre-request code)
2. Enter ``middleware2`` (pre-request code)
3. Execute the actual request handler
4. Exit ``middleware2`` (post-response code)
5. 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 with
``surrogateescape`` 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 the
``Content-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)
            pass

Disabling content type validation for JSON responses
----------------------------------------------------

The standard explicitly restricts JSON ``Content-Type`` HTTP header to
``application/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:

1. Pass the expected type explicitly (in this case checking will be strict, without the extended form support,
   so ``custom/xxx+type`` won't be accepted):

   ``await resp.json(content_type='custom/type')``.
2. 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 called
``trace_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 optional
``socket_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 like
`ssl.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:pass@some.proxy.com")

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 passing
``trust_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 asyncio

Now, let's try to get a web-page. For example let's query
``http://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 the
``params`` keyword argument. As an example, if you wanted to pass
``key1=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) == expect

You 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) == expect

You 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. accept
`json` 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 different
``serializer``. :class:`ClientSession` accepts ``json_serialize`` and
``json_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=False`` and 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 (by
``await 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:

1. :class:`TCPConnector` for regular *TCP sockets* (both *HTTP* and
   *HTTPS* schemes supported).
2. :class:`UnixConnector` for 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.0


ClientWebSocketResponse
-----------------------

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.12



Utilities
---------


.. class:: ClientTimeout(*, total=5*60, 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: Digest` headers
   - Generating appropriate `Authorization: Digest` headers 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`` or
``application/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 pair

Client 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:

   1. invalid compression
   2. malformed chunked encoding
   3. not enough data that satisfy ``Content-Length`` HTTP 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:`NonHttpUrlClientError`

    * :exc:`NonHttpUrlRedirectClientError`

  * :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:

  0. Make sure you are reading the latest version of this document.
     It can be found in the GitHub_ repo in the ``docs`` subdirectory.

  1. Clone the GitHub_ repo using the ``--recurse-submodules`` argument

  2. Setup your machine with the required development environment

  3. Make a change

  4. Make sure all tests passed

  5. Add a file into the ``CHANGES`` folder (see `Changelog update`_ for how).

  6. Commit changes to your own aiohttp clone

  7. Make a pull request from the github page of your clone against the master branch

  8. 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=0

  in 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 fmt


Run 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:
```console
$ python -m webbrowser -n file://"$(pwd)"/htmlcov/index.html
```

Documentation
-------------

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 page
``open 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:

1. 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 like ``asvetlov merged commit
   f7b8921 into master 9 days ago``.  ``f7b8921`` is the required commit number.

2. 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``.

3. In case of conflicts fix them and continue cherry-picking by
   ``cherry_picker --continue``.

   ``cherry_picker --abort`` stops the process.

   ``cherry_picker --status`` shows current cherry-picking status
   (like ``git status``)

4. 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.

5. *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:

1. No wild commits! Everything should go through PRs.
2. Take a part in reviews. It's very important part of maintainer's activity.
3. Pickup issues created by others, especially if they are simple.
4. 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.
5. 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: linux-distros@vs.openwall.org
    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: oss-security@lists.openwall.com
    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.