Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES/12395.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Fixed a crash (:external+python:exc:`~http.cookies.CookieError`) in the cookie parser when receiving cookies
containing ASCII control characters on CPython builds with the :cve:`2026-3644`
patch. The parser now gracefully skips cookies whose value contains control
characters instead of letting the exception propagate -- by :user:`rodrigobnogueira`.
2 changes: 2 additions & 0 deletions CHANGES/12425.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Replaced uses of the ``get_event_loop()`` function with ``get_running_loop()``
-- by :user:`agronholm`.
2 changes: 2 additions & 0 deletions CHANGES/9891.contrib.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Skipped IPv6-only connector and test utility tests when the runtime does not support
IPv6 -- by :user:`nightcityblade`.
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Alec Hanefeld
Alejandro Gómez
Aleksandr Danshyn
Aleksey Kutepov
Alex Grönholm
Alex Hayes
Alex Key
Alex Khomchenko
Expand Down
62 changes: 42 additions & 20 deletions aiohttp/_cookie_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import re
from collections.abc import Sequence
from http.cookies import Morsel
from http.cookies import CookieError, Morsel
from typing import cast

from .log import internal_logger
Expand Down Expand Up @@ -106,9 +106,16 @@ def preserve_morsel_with_coded_value(cookie: Morsel[str]) -> Morsel[str]:
# bypass validation and set already validated state. This is more stable than
# setting protected attributes directly and unlikely to change since it would
# break pickling.
mrsl_val.__setstate__( # type: ignore[attr-defined]
{"key": cookie.key, "value": cookie.value, "coded_value": cookie.coded_value}
)
try:
mrsl_val.__setstate__( # type: ignore[attr-defined]
{
"key": cookie.key,
"value": cookie.value,
"coded_value": cookie.coded_value,
}
)
except CookieError:
return cookie
return mrsl_val


Expand Down Expand Up @@ -206,10 +213,18 @@ def parse_cookie_header(header: str) -> list[tuple[str, Morsel[str]]]:
invalid_names.append(key)
else:
morsel = Morsel()
morsel.__setstate__( # type: ignore[attr-defined]
{"key": key, "value": _unquote(value), "coded_value": value}
)
cookies.append((key, morsel))
try:
morsel.__setstate__( # type: ignore[attr-defined]
{
"key": key,
"value": _unquote(value),
"coded_value": value,
}
)
except CookieError:
pass
else:
cookies.append((key, morsel))

# Move to next cookie or end
i = next_semi + 1 if next_semi != -1 else n
Expand All @@ -231,9 +246,12 @@ def parse_cookie_header(header: str) -> list[tuple[str, Morsel[str]]]:
# bypass validation and set already validated state. This is more stable than
# setting protected attributes directly and unlikely to change since it would
# break pickling.
morsel.__setstate__( # type: ignore[attr-defined]
{"key": key, "value": _unquote(value), "coded_value": value}
)
try:
morsel.__setstate__( # type: ignore[attr-defined]
{"key": key, "value": _unquote(value), "coded_value": value}
)
except CookieError:
continue

cookies.append((key, morsel))

Expand Down Expand Up @@ -323,15 +341,19 @@ def parse_set_cookie_headers(headers: Sequence[str]) -> list[tuple[str, Morsel[s
# Create new morsel
current_morsel = Morsel()
# Preserve the original value as coded_value (with quotes if present)
# We use __setstate__ instead of the public set() API because it allows us to
# bypass validation and set already validated state. This is more stable than
# setting protected attributes directly and unlikely to change since it would
# break pickling.
current_morsel.__setstate__( # type: ignore[attr-defined]
{"key": key, "value": _unquote(value), "coded_value": value}
)
parsed_cookies.append((key, current_morsel))
morsel_seen = True
try:
current_morsel.__setstate__( # type: ignore[attr-defined]
{
"key": key,
"value": _unquote(value),
"coded_value": value,
}
)
except CookieError:
current_morsel = None
else:
parsed_cookies.append((key, current_morsel))
morsel_seen = True
else:
# Invalid cookie string - no value for non-attribute
break
Expand Down
2 changes: 1 addition & 1 deletion aiohttp/web_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ def debug(self) -> bool:
DeprecationWarning,
stacklevel=2,
)
return asyncio.get_event_loop().get_debug()
return asyncio.get_running_loop().get_debug()

def _reg_subapp_signals(self, subapp: "Application") -> None:
def reg_handler(signame: str) -> None:
Expand Down
2 changes: 1 addition & 1 deletion aiohttp/web_fileresponse.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ async def _sendfile_fallback(
# controlled by the constructor's chunk_size argument.

chunk_size = self._chunk_size
loop = asyncio.get_event_loop()
loop = asyncio.get_running_loop()
chunk = await loop.run_in_executor(
None, self._seek_and_read, fobj, offset, min(chunk_size, count)
)
Expand Down
12 changes: 6 additions & 6 deletions aiohttp/web_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def name(self) -> str:

async def start(self) -> None:
await super().start()
loop = asyncio.get_event_loop()
loop = asyncio.get_running_loop()
server = self._runner.server
assert server is not None
self._server = await loop.create_server(
Expand Down Expand Up @@ -170,7 +170,7 @@ def name(self) -> str:

async def start(self) -> None:
await super().start()
loop = asyncio.get_event_loop()
loop = asyncio.get_running_loop()
server = self._runner.server
assert server is not None
self._server = await loop.create_unix_server(
Expand All @@ -185,7 +185,7 @@ class NamedPipeSite(BaseSite):
__slots__ = ("_path",)

def __init__(self, runner: "BaseRunner[Any]", path: str) -> None:
loop = asyncio.get_event_loop()
loop = asyncio.get_running_loop()
if not isinstance(
loop, asyncio.ProactorEventLoop # type: ignore[attr-defined]
):
Expand All @@ -201,7 +201,7 @@ def name(self) -> str:

async def start(self) -> None:
await super().start()
loop = asyncio.get_event_loop()
loop = asyncio.get_running_loop()
server = self._runner.server
assert server is not None
_server = await loop.start_serving_pipe( # type: ignore[attr-defined]
Expand Down Expand Up @@ -241,7 +241,7 @@ def name(self) -> str:

async def start(self) -> None:
await super().start()
loop = asyncio.get_event_loop()
loop = asyncio.get_running_loop()
server = self._runner.server
assert server is not None
self._server = await loop.create_server(
Expand Down Expand Up @@ -286,7 +286,7 @@ def sites(self) -> set[BaseSite]:
return set(self._sites)

async def setup(self) -> None:
loop = asyncio.get_event_loop()
loop = asyncio.get_running_loop()

if self._handle_signals:
try:
Expand Down
3 changes: 0 additions & 3 deletions aiohttp/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,6 @@ class GunicornUVLoopWebWorker(GunicornWebWorker):
def init_process(self) -> None:
import uvloop

# Setup uvloop policy, so that every
# asyncio.get_event_loop() will create an instance
# of uvloop event loop.
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

super().init_process()
2 changes: 1 addition & 1 deletion requirements/base-ft.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ frozenlist==1.8.0
# aiosignal
gunicorn==26.0.0
# via -r requirements/base-ft.in
idna==3.11
idna==3.15
# via yarl
multidict==6.7.1
# via
Expand Down
2 changes: 1 addition & 1 deletion requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ frozenlist==1.8.0
# aiosignal
gunicorn==26.0.0
# via -r requirements/base.in
idna==3.11
idna==3.15
# via yarl
multidict==6.7.1
# via
Expand Down
2 changes: 1 addition & 1 deletion requirements/constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ gunicorn==26.0.0
# via -r requirements/base.in
identify==2.6.19
# via pre-commit
idna==3.11
idna==3.15
# via
# requests
# trustme
Expand Down
2 changes: 1 addition & 1 deletion requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ gunicorn==26.0.0
# via -r requirements/base.in
identify==2.6.19
# via pre-commit
idna==3.11
idna==3.15
# via
# requests
# trustme
Expand Down
2 changes: 1 addition & 1 deletion requirements/doc-spelling.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ click==8.3.3
# via towncrier
docutils==0.21.2
# via sphinx
idna==3.11
idna==3.15
# via requests
imagesize==2.0.0
# via sphinx
Expand Down
2 changes: 1 addition & 1 deletion requirements/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ click==8.3.3
# via towncrier
docutils==0.21.2
# via sphinx
idna==3.11
idna==3.15
# via requests
imagesize==2.0.0
# via sphinx
Expand Down
2 changes: 1 addition & 1 deletion requirements/lint.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ frozenlist==1.8.0
# aiosignal
identify==2.6.19
# via pre-commit
idna==3.11
idna==3.15
# via
# trustme
# yarl
Expand Down
2 changes: 1 addition & 1 deletion requirements/runtime-deps.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ frozenlist==1.8.0
# via
# -r requirements/runtime-deps.in
# aiosignal
idna==3.11
idna==3.15
# via yarl
multidict==6.7.1
# via
Expand Down
2 changes: 1 addition & 1 deletion requirements/test-common.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ frozenlist==1.8.0
# via
# aiohttp
# aiosignal
idna==3.11
idna==3.15
# via
# trustme
# yarl
Expand Down
2 changes: 1 addition & 1 deletion requirements/test-ft.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ frozenlist==1.8.0
# aiosignal
gunicorn==26.0.0
# via -r requirements/base-ft.in
idna==3.11
idna==3.15
# via
# trustme
# yarl
Expand Down
2 changes: 1 addition & 1 deletion requirements/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ frozenlist==1.8.0
# aiosignal
gunicorn==26.0.0
# via -r requirements/base.in
idna==3.11
idna==3.15
# via
# trustme
# yarl
Expand Down
Loading
Loading