Skip to content

Commit

Permalink
Merge branch '3.11' into patchback/backports/3.11/b6ffb1d1a3b710c600f…
Browse files Browse the repository at this point in the history
…06c9d21cf62f75d324767/pr-10304
  • Loading branch information
bdraco authored Jan 20, 2025
2 parents 780bd92 + 68e426c commit b55c8d5
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 40 deletions.
4 changes: 4 additions & 0 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
---
version: 2

sphinx:
# Path to your Sphinx configuration file.
configuration: docs/conf.py

submodules:
include: all
exclude: []
Expand Down
1 change: 1 addition & 0 deletions CHANGES/10332.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improved logging of HTTP protocol errors to include the remote address -- by :user:`bdraco`.
8 changes: 6 additions & 2 deletions aiohttp/web_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,9 +694,13 @@ def handle_error(
# or encrypted traffic to an HTTP port. This is expected
# to happen when connected to the public internet so we log
# it at the debug level as to not fill logs with noise.
self.logger.debug("Error handling request", exc_info=exc)
self.logger.debug(
"Error handling request from %s", request.remote, exc_info=exc
)
else:
self.log_exception("Error handling request", exc_info=exc)
self.log_exception(
"Error handling request from %s", request.remote, exc_info=exc
)

# some data already got sent, connection is broken
if request.writer.output_size > 0:
Expand Down
125 changes: 97 additions & 28 deletions docs/client_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ The client session supports the context manager protocol for self closing.
.. versionadded:: 3.0

:param str server_hostname: Sets or overrides the host name that the
target servers certificate will be matched against.
target server's certificate will be matched against.

See :py:meth:`asyncio.loop.create_connection` for more information.

Expand Down Expand Up @@ -850,14 +850,21 @@ certification chaining.

.. function:: request(method, url, *, params=None, data=None, \
json=None,\
headers=None, cookies=None, auth=None, \
cookies=None, headers=None, skip_auto_headers=None, auth=None, \
allow_redirects=True, max_redirects=10, \
encoding='utf-8', \
version=HttpVersion(major=1, minor=1), \
compress=None, chunked=None, expect100=False, raise_for_status=False, \
compress=False, chunked=None, expect100=False, raise_for_status=None, \
read_until_eof=True, \
proxy=None, proxy_auth=None, \
timeout=sentinel, ssl=True, \
server_hostname=None, \
proxy_headers=None, \
trace_request_ctx=None, \
read_bufsize=None, \
connector=None, loop=None,\
read_until_eof=True, timeout=sentinel)
auto_decompress=None, \
max_line_size=None, \
max_field_size=None, \
version=aiohttp.HttpVersion11, \
connector=None)
:async:

Asynchronous context manager for performing an asynchronous HTTP
Expand All @@ -870,8 +877,20 @@ certification chaining.
be encoded with :class:`~yarl.URL` (see :class:`~yarl.URL`
to skip encoding).

:param dict params: Parameters to be sent in the query
string of the new request (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 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
Expand All @@ -881,28 +900,46 @@ certification chaining.
: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 dict cookies: Cookies 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 aiohttp.BasicAuth auth: an object that represents HTTP Basic
Authorization (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).
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 aiohttp.protocol.HttpVersion version: Request HTTP version (optional)
:param int max_redirects: Maximum number of redirects to follow.
:exc:`TooManyRedirects` is raised if the number is exceeded.
Ignored when ``allow_redirects=False``.
``10`` by default.

:param bool compress: Set to ``True`` if request has to be compressed
with deflate encoding.
``False`` instructs aiohttp to not compress data.
with deflate encoding. If `compress` can not be combined
with a *Content-Encoding* and *Content-Length* headers.
``None`` by default (optional).

:param int chunked: Enables chunked transfer encoding.
``None`` by default (optional).
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).
Expand All @@ -916,28 +953,60 @@ certification chaining.

.. versionadded:: 3.4

:param aiohttp.BaseConnector connector: BaseConnector sub-class
instance to support connection pooling.

: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 aiohttp.BasicAuth proxy_auth: an object that represents proxy HTTP
Basic Authorization (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 timeout: a :class:`ClientTimeout` settings structure, 300 seconds (5min)
total timeout, 30 seconds socket connect timeout by default.
:param bool auto_decompress: Automatically decompress response body.
May be used to enable/disable auto decompression on a per-request basis.

:param loop: :ref:`event loop<asyncio-event-loop>`
used for processing HTTP requests.
If param is ``None``, :func:`asyncio.get_event_loop`
is used for getting default event loop.
:param int max_line_size: Maximum allowed size of lines in responses.

.. deprecated:: 2.0
:param int max_field_size: Maximum allowed size of header fields 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.

Expand Down
2 changes: 1 addition & 1 deletion tests/test_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def test_web___all__(pytester: pytest.Pytester) -> None:
# and even slower under pytest-xdist, especially in CI
_XDIST_WORKER_COUNT * 100 * (1 if _IS_CI_ENV else 1.53)
if _IS_XDIST_RUN
else 265
else 295
),
}
_TARGET_TIMINGS_BY_PYTHON_VERSION["3.13"] = _TARGET_TIMINGS_BY_PYTHON_VERSION["3.12"]
Expand Down
36 changes: 27 additions & 9 deletions tests/test_web_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ async def handler(request):
assert txt.startswith("500 Internal Server Error")
assert "Traceback" not in txt

logger.exception.assert_called_with("Error handling request", exc_info=exc)
logger.exception.assert_called_with(
"Error handling request from %s", cli.host, exc_info=exc
)


async def test_raw_server_logs_invalid_method_with_loop_debug(
Expand Down Expand Up @@ -85,7 +87,9 @@ async def handler(request: web.BaseRequest) -> NoReturn:
# on the first request since the client may
# be probing for TLS/SSL support which is
# expected to fail
logger.debug.assert_called_with("Error handling request", exc_info=exc)
logger.debug.assert_called_with(
"Error handling request from %s", cli.host, exc_info=exc
)
logger.debug.reset_mock()

# Now make another connection to the server
Expand All @@ -99,7 +103,9 @@ async def handler(request: web.BaseRequest) -> NoReturn:
# on the first request since the client may
# be probing for TLS/SSL support which is
# expected to fail
logger.debug.assert_called_with("Error handling request", exc_info=exc)
logger.debug.assert_called_with(
"Error handling request from %s", cli.host, exc_info=exc
)


async def test_raw_server_logs_invalid_method_without_loop_debug(
Expand Down Expand Up @@ -128,7 +134,9 @@ async def handler(request: web.BaseRequest) -> NoReturn:
# on the first request since the client may
# be probing for TLS/SSL support which is
# expected to fail
logger.debug.assert_called_with("Error handling request", exc_info=exc)
logger.debug.assert_called_with(
"Error handling request from %s", cli.host, exc_info=exc
)


async def test_raw_server_logs_invalid_method_second_request(
Expand Down Expand Up @@ -159,7 +167,9 @@ async def handler(request: web.BaseRequest) -> web.Response:
# BadHttpMethod should be logged as an exception
# if its not the first request since we know
# that the client already was speaking HTTP
logger.exception.assert_called_with("Error handling request", exc_info=exc)
logger.exception.assert_called_with(
"Error handling request from %s", cli.host, exc_info=exc
)


async def test_raw_server_logs_bad_status_line_as_exception(
Expand All @@ -184,7 +194,9 @@ async def handler(request: web.BaseRequest) -> NoReturn:
txt = await resp.text()
assert "Traceback (most recent call last):\n" not in txt

logger.exception.assert_called_with("Error handling request", exc_info=exc)
logger.exception.assert_called_with(
"Error handling request from %s", cli.host, exc_info=exc
)


async def test_raw_server_handler_timeout(
Expand Down Expand Up @@ -254,7 +266,9 @@ async def handler(request):
txt = await resp.text()
assert "Traceback (most recent call last):\n" in txt

logger.exception.assert_called_with("Error handling request", exc_info=exc)
logger.exception.assert_called_with(
"Error handling request from %s", cli.host, exc_info=exc
)


async def test_raw_server_html_exception(aiohttp_raw_server, aiohttp_client):
Expand All @@ -278,7 +292,9 @@ async def handler(request):
"</body></html>\n"
)

logger.exception.assert_called_with("Error handling request", exc_info=exc)
logger.exception.assert_called_with(
"Error handling request from %s", cli.host, exc_info=exc
)


async def test_raw_server_html_exception_debug(aiohttp_raw_server, aiohttp_client):
Expand All @@ -302,7 +318,9 @@ async def handler(request):
"<pre>Traceback (most recent call last):\n"
)

logger.exception.assert_called_with("Error handling request", exc_info=exc)
logger.exception.assert_called_with(
"Error handling request from %s", cli.host, exc_info=exc
)


async def test_handler_cancellation(unused_port_socket: socket.socket) -> None:
Expand Down

0 comments on commit b55c8d5

Please sign in to comment.