Skip to content

Commit

Permalink
Merge branch 'master' into add-staticresources
Browse files Browse the repository at this point in the history
  • Loading branch information
abersheeran authored Nov 6, 2023
2 parents 6b0c615 + 4370ed6 commit b5f5bd4
Show file tree
Hide file tree
Showing 15 changed files with 70 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
name: deploy

steps:
- uses: "actions/checkout@v3"
- uses: "actions/checkout@v4"
- uses: "actions/setup-python@v4"
with:
python-version: "3.11"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-suite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- uses: "actions/checkout@v3"
- uses: "actions/checkout@v4"
- uses: "actions/setup-python@v4"
with:
python-version: "${{ matrix.python-version }}"
Expand Down
3 changes: 0 additions & 3 deletions docs/js/chat.js

This file was deleted.

6 changes: 0 additions & 6 deletions docs/js/sidecar-1.5.0.js

This file was deleted.

2 changes: 2 additions & 0 deletions docs/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ The following arguments are supported:
* `max_age` - Session expiry time in seconds. Defaults to 2 weeks. If set to `None` then the cookie will last as long as the browser session.
* `same_site` - SameSite flag prevents the browser from sending session cookie along with cross-site requests. Defaults to `'lax'`.
* `https_only` - Indicate that Secure flag should be set (can be used with HTTPS only). Defaults to `False`.
* `domain` - Domain of the cookie used to share cookie between subdomains or cross-domains. The browser defaults the domain to the same host that set the cookie, excluding subdomains [refrence](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#domain_attribute).


## HTTPSRedirectMiddleware

Expand Down
12 changes: 12 additions & 0 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## 0.32.0

### Added

* Send `reason` on `WebSocketDisconnect` [#2309](https://github.com/encode/starlette/pull/2309).
* Add `domain` parameter to `SessionMiddleware` [#2280](https://github.com/encode/starlette/pull/2280).

### Changed

* Inherit from `HTMLResponse` instead of `Response` on `_TemplateResponse` [#2274](https://github.com/encode/starlette/pull/2274).
* Restore the `Response.render` type annotation to its pre-0.31.0 state [#2264](https://github.com/encode/starlette/pull/2264).

## 0.31.1

August 26, 2023
Expand Down
7 changes: 7 additions & 0 deletions docs/third-party-packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ Here are some of those third party packages:

## Plugins

### Apitally

<a href="https://github.com/apitally/python-client" target="_blank">GitHub</a> |
<a href="https://docs.apitally.io/frameworks/starlette" target="_blank">Documentation</a>

Simple traffic, error and response time monitoring plus API key and permission management for Starlette (and other frameworks).

### Authlib

<a href="https://github.com/lepture/Authlib" target="_blank">GitHub</a> |
Expand Down
4 changes: 0 additions & 4 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,3 @@ markdown_extensions:
- pymdownx.superfences
- pymdownx.tabbed:
alternate_style: true

extra_javascript:
- 'js/chat.js'
- 'js/sidecar-1.5.0.js'
16 changes: 8 additions & 8 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@
-e .[full]

# Testing
black==23.7.0
coverage==7.3.0
black==23.10.1
coverage==7.3.1
importlib-metadata==6.8.0
mypy==1.5.1
ruff==0.0.285
typing_extensions==4.7.1
types-contextvars==2.4.7.2
types-PyYAML==6.0.12.11
ruff==0.1.3
typing_extensions==4.8.0
types-contextvars==2.4.7.3
types-PyYAML==6.0.12.12
types-dataclasses==0.6.6
pytest==7.4.0
trio==0.22.2
anyio==4.0.0

# Documentation
mkdocs==1.5.2
mkdocs==1.5.3
mkdocs-material==9.1.17
mkautodoc==0.2.0

# Packaging
build==0.10.0
build==1.0.3
twine==4.0.2
2 changes: 1 addition & 1 deletion starlette/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.31.1"
__version__ = "0.32.0"
3 changes: 3 additions & 0 deletions starlette/middleware/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def __init__(
path: str = "/",
same_site: typing.Literal["lax", "strict", "none"] = "lax",
https_only: bool = False,
domain: typing.Optional[str] = None,
) -> None:
self.app = app
self.signer = itsdangerous.TimestampSigner(str(secret_key))
Expand All @@ -29,6 +30,8 @@ def __init__(
self.security_flags = "httponly; samesite=" + same_site
if https_only: # Secure flag can be used with HTTPS only
self.security_flags += "; secure"
if domain is not None:
self.security_flags += f"; domain={domain}"

async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
if scope["type"] not in ("http", "websocket"): # pragma: no cover
Expand Down
4 changes: 2 additions & 2 deletions starlette/testclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ def send_json(self, data: typing.Any, mode: str = "text") -> None:
else:
self.send({"type": "websocket.receive", "bytes": text.encode("utf-8")})

def close(self, code: int = 1000) -> None:
self.send({"type": "websocket.disconnect", "code": code})
def close(self, code: int = 1000, reason: typing.Union[str, None] = None) -> None:
self.send({"type": "websocket.disconnect", "code": code, "reason": reason})

def receive(self) -> Message:
message = self._send_queue.get()
Expand Down
2 changes: 1 addition & 1 deletion starlette/websockets.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ async def accept(

def _raise_on_disconnect(self, message: Message) -> None:
if message["type"] == "websocket.disconnect":
raise WebSocketDisconnect(message["code"])
raise WebSocketDisconnect(message["code"], message.get("reason"))

async def receive_text(self) -> str:
if self.application_state != WebSocketState.CONNECTED:
Expand Down
24 changes: 24 additions & 0 deletions tests/middleware/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,27 @@ def test_session_cookie(test_client_factory):
client.cookies.delete("session")
response = client.get("/view_session")
assert response.json() == {"session": {}}


def test_domain_cookie(test_client_factory):
app = Starlette(
routes=[
Route("/view_session", endpoint=view_session),
Route("/update_session", endpoint=update_session, methods=["POST"]),
],
middleware=[
Middleware(SessionMiddleware, secret_key="example", domain=".example.com")
],
)
client: TestClient = test_client_factory(app)

response = client.post("/update_session", json={"some": "data"})
assert response.json() == {"session": {"some": "data"}}

# check cookie max-age
set_cookie = response.headers["set-cookie"]
assert "domain=.example.com" in set_cookie

client.cookies.delete("session")
response = client.get("/view_session")
assert response.json() == {"session": {}}
12 changes: 8 additions & 4 deletions tests/test_websockets.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import sys
from typing import Any, MutableMapping
from typing import Any, Callable, MutableMapping

import anyio
import pytest
from anyio.abc import ObjectReceiveStream, ObjectSendStream

from starlette import status
from starlette.testclient import TestClient
from starlette.types import Receive, Scope, Send
from starlette.websockets import WebSocket, WebSocketDisconnect, WebSocketState

Expand Down Expand Up @@ -209,22 +210,25 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
assert data == {"hello": "world"}


def test_client_close(test_client_factory):
def test_client_close(test_client_factory: Callable[..., TestClient]):
close_code = None
close_reason = None

async def app(scope: Scope, receive: Receive, send: Send) -> None:
nonlocal close_code
nonlocal close_code, close_reason
websocket = WebSocket(scope, receive=receive, send=send)
await websocket.accept()
try:
await websocket.receive_text()
except WebSocketDisconnect as exc:
close_code = exc.code
close_reason = exc.reason

client = test_client_factory(app)
with client.websocket_connect("/") as websocket:
websocket.close(code=status.WS_1001_GOING_AWAY)
websocket.close(code=status.WS_1001_GOING_AWAY, reason="Going Away")
assert close_code == status.WS_1001_GOING_AWAY
assert close_reason == "Going Away"


def test_application_close(test_client_factory):
Expand Down

0 comments on commit b5f5bd4

Please sign in to comment.