Skip to content
This repository was archived by the owner on Sep 2, 2022. It is now read-only.

Commit 413c1e8

Browse files
committed
Don't send 0 as the response size for streaming responses
Send nothing instead.
1 parent 3540ce8 commit 413c1e8

7 files changed

Lines changed: 23 additions & 14 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
12+
- Don't send 0 as the response size for streaming responses, send nothing instead.
13+
1014
## [1.2.0] - 2022-01-31
1115

1216
### Added

apilytics/django.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ def __call__(self, request: django.http.HttpRequest) -> django.http.HttpResponse
5252
integrated_library=f"django/{django.__version__}",
5353
) as sender:
5454
response = self.get_response(request)
55+
content = getattr(response, "content", None)
5556
sender.set_response_info(
5657
status_code=response.status_code,
57-
response_size=len(getattr(response, "content", ())),
58+
response_size=len(content) if content is not None else None,
5859
)
5960
return response

apilytics/fastapi.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@ async def dispatch(
6060
integrated_library=f"fastapi/{fastapi.__version__}",
6161
) as sender:
6262
response = await call_next(request)
63+
size = response.headers.get("content-length")
6364
sender.set_response_info(
6465
status_code=response.status_code,
65-
response_size=int(response.headers.get("content-length", 0)),
66+
response_size=int(size) if size is not None else None,
6667
)
6768
return response

tests/django/app/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def streaming_view(
1515
request: django.http.HttpRequest,
1616
) -> django.http.StreamingHttpResponse:
1717
return django.http.StreamingHttpResponse(
18-
status=200, streaming_content=(b"first", b"second")
18+
status=200, streaming_content=(b"first", b" ", b"second")
1919
)
2020

2121

tests/django/test_django.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def test_middleware_should_send_query_params(
7171
assert isinstance(data["timeMillis"], int)
7272

7373

74-
def test_middleware_should_send_zero_request_and_response_sizes(
74+
def test_middleware_should_handle_zero_request_and_response_sizes(
7575
mocked_urlopen: unittest.mock.MagicMock,
7676
) -> None:
7777
client.handler.load_middleware()
@@ -85,7 +85,7 @@ def test_middleware_should_send_zero_request_and_response_sizes(
8585
assert data["responseSize"] == 0
8686

8787

88-
def test_middleware_should_send_non_zero_request_and_response_sizes(
88+
def test_middleware_should_handle_non_zero_request_and_response_sizes(
8989
mocked_urlopen: unittest.mock.MagicMock,
9090
) -> None:
9191
client.handler.load_middleware()
@@ -107,6 +107,9 @@ def test_middleware_should_work_with_streaming_response(
107107
client.handler.load_middleware()
108108
response = client.get("/streaming")
109109
assert response.status_code == 200
110+
# Ignore: The attribute *does* exist on StreamingHTTPResponse.
111+
content = b"".join(response.streaming_content) # type: ignore[attr-defined]
112+
assert content == b"first second"
110113

111114
assert mocked_urlopen.call_count == 1
112115
__, call_kwargs = mocked_urlopen.call_args
@@ -116,14 +119,12 @@ def test_middleware_should_work_with_streaming_response(
116119
"method",
117120
"statusCode",
118121
"requestSize",
119-
"responseSize",
120122
"timeMillis",
121123
}
122124
assert data["path"] == "/streaming"
123125
assert data["method"] == "GET"
124126
assert data["statusCode"] == 200
125127
assert data["requestSize"] == 0
126-
assert data["responseSize"] == 0 # Can't get body size from a streaming response.
127128
assert isinstance(data["timeMillis"], int)
128129

129130

tests/fastapi/app.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ async def streaming_route(
2626
request: fastapi.Request,
2727
) -> starlette.responses.StreamingResponse:
2828
return starlette.responses.StreamingResponse(
29-
status_code=fastapi.status.HTTP_200_OK, content=(b"first", b"second")
29+
status_code=fastapi.status.HTTP_200_OK,
30+
content=iter([b"first", b" ", b"second"]),
31+
media_type="application/octet-stream",
3032
)
3133

3234

tests/fastapi/test_fastapi.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def test_middleware_should_send_query_params(
7070
assert isinstance(data["timeMillis"], int)
7171

7272

73-
def test_middleware_should_send_zero_request_and_response_sizes(
73+
def test_middleware_should_handle_zero_request_and_response_sizes(
7474
mocked_urlopen: unittest.mock.MagicMock,
7575
) -> None:
7676
response = client.post("/empty")
@@ -80,10 +80,10 @@ def test_middleware_should_send_zero_request_and_response_sizes(
8080
__, call_kwargs = mocked_urlopen.call_args
8181
data = tests.conftest.decode_request_data(call_kwargs["data"])
8282
assert data["requestSize"] == 0
83-
assert data["responseSize"] == 0
83+
assert "responseSize" not in data # In FastAPI 0 content-length is not set.
8484

8585

86-
def test_middleware_should_send_non_zero_request_and_response_sizes(
86+
def test_middleware_should_handle_non_zero_request_and_response_sizes(
8787
mocked_urlopen: unittest.mock.MagicMock,
8888
) -> None:
8989
response = client.post("/dummy?some=query", json={"hello": "world"})
@@ -99,8 +99,10 @@ def test_middleware_should_send_non_zero_request_and_response_sizes(
9999
def test_middleware_should_work_with_streaming_response(
100100
mocked_urlopen: unittest.mock.MagicMock,
101101
) -> None:
102-
response = client.get("/streaming")
102+
response = client.get("/streaming", stream=True)
103103
assert response.status_code == 200
104+
content = b"".join(response.iter_content())
105+
assert content == b"first second"
104106

105107
assert mocked_urlopen.call_count == 1
106108
__, call_kwargs = mocked_urlopen.call_args
@@ -110,14 +112,12 @@ def test_middleware_should_work_with_streaming_response(
110112
"method",
111113
"statusCode",
112114
"requestSize",
113-
"responseSize",
114115
"timeMillis",
115116
}
116117
assert data["path"] == "/streaming"
117118
assert data["method"] == "GET"
118119
assert data["statusCode"] == 200
119120
assert data["requestSize"] == 0
120-
assert data["responseSize"] == 0 # Can't get body size from a streaming response.
121121
assert isinstance(data["timeMillis"], int)
122122

123123

0 commit comments

Comments
 (0)