diff --git a/starlette/responses.py b/starlette/responses.py index b951e5125..790aa7ebc 100644 --- a/starlette/responses.py +++ b/starlette/responses.py @@ -11,7 +11,7 @@ from email.utils import format_datetime, formatdate from functools import partial from mimetypes import guess_type -from random import choices as random_choices +from secrets import token_hex from urllib.parse import quote import anyio @@ -401,7 +401,8 @@ async def _handle_multiple_ranges( file_size: int, send_header_only: bool, ) -> None: - boundary = "".join(random_choices("abcdefghijklmnopqrstuvwxyz0123456789", k=13)) + # In firefox and chrome, they use boundary with 95-96 bits entropy (that's roughly 13 bytes). + boundary = token_hex(13) content_length, header_generator = self.generate_multipart( ranges, boundary, file_size, self.headers["content-type"] ) diff --git a/tests/test_responses.py b/tests/test_responses.py index 645d26a68..1fb8c6be0 100644 --- a/tests/test_responses.py +++ b/tests/test_responses.py @@ -598,13 +598,13 @@ def test_file_response_range_multi(file_response_client: TestClient) -> None: response = file_response_client.get("/", headers={"Range": "bytes=0-100, 200-300"}) assert response.status_code == 206 assert response.headers["content-range"].startswith("multipart/byteranges; boundary=") - assert response.headers["content-length"] == "400" + assert response.headers["content-length"] == "439" def test_file_response_range_multi_head(file_response_client: TestClient) -> None: response = file_response_client.head("/", headers={"Range": "bytes=0-100, 200-300"}) assert response.status_code == 206 - assert response.headers["content-length"] == "400" + assert response.headers["content-length"] == "439" assert response.content == b"" response = file_response_client.head(