Skip to content
Open
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: 3 additions & 1 deletion docs/responses.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ Signature: `Response.set_cookie(key, value, max_age=None, expires=None, path="/"

Conversely, Starlette also provides a `delete_cookie` method to manually expire a set cookie.

Signature: `Response.delete_cookie(key, path='/', domain=None)`
Signature: `Response.delete_cookie(key, path='/', domain=None, secure=False, httponly=False, samesite="lax", partitioned=False)`
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.

* `partitioned` - A bool that indicates to user agents that these cross-site cookies should only be available in the same top-level context that the cookie was first set in. Only available for Python 3.14+, otherwise an error will be raised. `Optional`


### HTMLResponse
Expand Down
2 changes: 2 additions & 0 deletions starlette/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ def delete_cookie(
secure: bool = False,
httponly: bool = False,
samesite: Literal["lax", "strict", "none"] | None = "lax",
partitioned: bool = False,
) -> None:
self.set_cookie(
key,
Expand All @@ -149,6 +150,7 @@ def delete_cookie(
secure=secure,
httponly=httponly,
samesite=samesite,
partitioned=partitioned,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: delete_cookie("key", partitioned=True) uses the default secure=False, so browsers reject the Partitioned expiry header and the cookie remains. Forward secure=secure or partitioned (or reject that invalid combination) when partitioned is requested.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At starlette/responses.py, line 153:

<comment>`delete_cookie("key", partitioned=True)` uses the default `secure=False`, so browsers reject the `Partitioned` expiry header and the cookie remains. Forward `secure=secure or partitioned` (or reject that invalid combination) when `partitioned` is requested.</comment>

<file context>
@@ -149,6 +150,7 @@ def delete_cookie(
             secure=secure,
             httponly=httponly,
             samesite=samesite,
+            partitioned=partitioned,
         )
 
</file context>

)

def _wrap_websocket_denial_send(self, send: Send) -> Send:
Expand Down
16 changes: 16 additions & 0 deletions tests/test_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,22 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
assert not response.cookies.get("mycookie")


def test_delete_cookie_partitioned(test_client_factory: TestClientFactory) -> None:
async def app(scope: Scope, receive: Receive, send: Send) -> None:
response = Response("Hello, world!", media_type="text/plain")
response.delete_cookie(
"mycookie",
partitioned=True if sys.version_info >= (3, 14) else False,
)
await response(scope, receive, send)

partitioned_text = "Partitioned" if sys.version_info >= (3, 14) else ""

client = test_client_factory(app)
response = client.get("/")
assert partitioned_text in response.headers["set-cookie"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The branchless refactoring loses negative coverage for Python < 3.14. When partitioned_text is "", assert "" in response.headers["set-cookie"] is always true, so the test never actually verifies that "Partitioned" is absent from the header. Compare with the set_cookie test where a full == equality makes the branchless pattern safe — here the in operator and empty string make it vacuous. Consider restoring the explicit assert "Partitioned" not in response.headers["set-cookie"] path for Python < 3.14, or switching to a full equality check similar to the set_cookie test.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/test_responses.py, line 528:

<comment>The branchless refactoring loses negative coverage for Python < 3.14. When `partitioned_text` is `""`, `assert "" in response.headers["set-cookie"]` is always true, so the test never actually verifies that "Partitioned" is absent from the header. Compare with the `set_cookie` test where a full `==` equality makes the branchless pattern safe — here the `in` operator and empty string make it vacuous. Consider restoring the explicit `assert "Partitioned" not in response.headers["set-cookie"]` path for Python < 3.14, or switching to a full equality check similar to the set_cookie test.</comment>

<file context>
@@ -521,13 +521,11 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
-        assert "Partitioned" in set_cookie
-    else:
-        assert "Partitioned" not in set_cookie
+    assert partitioned_text in response.headers["set-cookie"]
 
 
</file context>



def test_populate_headers(test_client_factory: TestClientFactory) -> None:
app = Response(content="hi", headers={}, media_type="text/html")
client = test_client_factory(app)
Expand Down