diff --git a/starlette/responses.py b/starlette/responses.py index 419816b7b..9d259a075 100644 --- a/starlette/responses.py +++ b/starlette/responses.py @@ -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 diff --git a/tests/test_responses.py b/tests/test_responses.py index 6bccd23f2..625a12956 100644 --- a/tests/test_responses.py +++ b/tests/test_responses.py @@ -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"" * 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)