Skip to content

Commit

Permalink
Add support for ASGI pathsend extension (#2435)
Browse files Browse the repository at this point in the history
* add support for ASGI `pathsend` extension

* add test for ASGI `pathsend`
  • Loading branch information
gi0baro committed Jan 22, 2024
1 parent 6bfe9fe commit 7936e86
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 0 deletions.
2 changes: 2 additions & 0 deletions starlette/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,8 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
)
if scope["method"].upper() == "HEAD":
await send({"type": "http.response.body", "body": b"", "more_body": False})
elif "http.response.pathsend" in scope["extensions"]:
await send({"type": "http.response.pathsend", "path": str(self.path)})
else:
async with await anyio.open_file(self.path, mode="rb") as file:
more_body = True
Expand Down
32 changes: 32 additions & 0 deletions tests/test_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,38 @@ def test_file_response_with_method_warns(tmpdir, test_client_factory):
FileResponse(path=tmpdir, filename="example.png", method="GET")


@pytest.mark.anyio
async def test_file_response_with_pathsend(tmpdir: Path):
path = os.path.join(tmpdir, "xyz")
content = b"<file content>" * 1000
with open(path, "wb") as file:
file.write(content)

app = FileResponse(path=path, filename="example.png")

async def receive() -> Message: # type: ignore[empty-body]
... # pragma: no cover

async def send(message: Message) -> None:
if message["type"] == "http.response.start":
assert message["status"] == status.HTTP_200_OK
headers = Headers(raw=message["headers"])
assert headers["content-type"] == "image/png"
assert "content-length" in headers
assert "content-disposition" in headers
assert "last-modified" in headers
assert "etag" in headers
elif message["type"] == "http.response.pathsend":
assert message["path"] == str(path)

# Since the TestClient doesn't support `pathsend`, we need to test this directly.
await app(
{"type": "http", "method": "get", "extensions": {"http.response.pathsend": {}}},
receive,
send,
)


def test_set_cookie(test_client_factory, monkeypatch):
# Mock time used as a reference for `Expires` by stdlib `SimpleCookie`.
mocked_now = dt.datetime(2037, 1, 22, 12, 0, 0, tzinfo=dt.timezone.utc)
Expand Down

0 comments on commit 7936e86

Please sign in to comment.