Skip to content

Commit 9820bf9

Browse files
authored
fix(aiohttp): Gate request body collection on data_collection experiment (#7249)
Only attach the raw request body when data collection is disabled or "incoming_request" is included in the http_bodies experiment option. Previously the body was always attached regardless of this setting. Refs PY-2419 Refs #6283
1 parent 15f4bda commit 9820bf9

2 files changed

Lines changed: 113 additions & 1 deletion

File tree

sentry_sdk/integrations/aiohttp.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@ def aiohttp_processor(
554554
if request is None:
555555
return event
556556

557+
client_options = sentry_sdk.get_client().options
557558
with capture_internal_exceptions():
558559
request_info = event.setdefault("request", {})
559560

@@ -571,7 +572,16 @@ def aiohttp_processor(
571572
# Just attach raw data here if it is within bounds, if available.
572573
# Unfortunately there's no way to get structured data from aiohttp
573574
# without awaiting on some coroutine.
574-
request_info["data"] = get_aiohttp_request_data(request)
575+
if has_data_collection_enabled(client_options):
576+
if (
577+
"incoming_request"
578+
in client_options["data_collection"]["http_bodies"]
579+
):
580+
request_info["data"] = get_aiohttp_request_data(request)
581+
else:
582+
# We never gated this prior to data collection, so it should be attached
583+
# when data collection is not enabled.
584+
request_info["data"] = get_aiohttp_request_data(request)
575585

576586
return event
577587

tests/integrations/aiohttp/test_aiohttp.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import sentry_sdk
2121
from sentry_sdk import capture_message, start_transaction
22+
from sentry_sdk._types import OVER_SIZE_LIMIT_SUBSTITUTE
2223
from sentry_sdk.consts import SPANDATA
2324
from sentry_sdk.integrations.aiohttp import (
2425
AioHttpIntegration,
@@ -131,6 +132,107 @@ async def hello(request):
131132
assert request["data"] == json.dumps(body)
132133

133134

135+
@pytest.mark.parametrize(
136+
"data_collection, expect_body",
137+
[
138+
pytest.param({}, True, id="data_collection_http_bodies_default"),
139+
pytest.param(
140+
{"http_bodies": ["incoming_request"]},
141+
True,
142+
id="data_collection_http_bodies_incoming_request",
143+
),
144+
pytest.param(
145+
{"http_bodies": []}, False, id="data_collection_http_bodies_empty"
146+
),
147+
],
148+
)
149+
@pytest.mark.asyncio
150+
async def test_aiohttp_request_body_data_collection(
151+
sentry_init, aiohttp_client, capture_events, data_collection, expect_body
152+
):
153+
sentry_init(
154+
integrations=[AioHttpIntegration()],
155+
_experiments={"data_collection": data_collection},
156+
)
157+
158+
body = {"some": "value"}
159+
160+
async def hello(request):
161+
await request.json()
162+
1 / 0
163+
164+
app = web.Application()
165+
app.router.add_post("/", hello)
166+
167+
events = capture_events()
168+
169+
client = await aiohttp_client(app)
170+
resp = await client.post("/", json=body)
171+
assert resp.status == 500
172+
173+
(event,) = events
174+
request = event["request"]
175+
176+
if expect_body:
177+
assert request["data"] == json.dumps(body)
178+
else:
179+
assert "data" not in request
180+
181+
182+
@pytest.mark.parametrize(
183+
"data_collection, expect_annotated",
184+
[
185+
pytest.param(
186+
{"http_bodies": ["incoming_request"]},
187+
True,
188+
id="data_collection_http_bodies_incoming_request",
189+
),
190+
pytest.param(
191+
{"http_bodies": []}, False, id="data_collection_http_bodies_empty"
192+
),
193+
],
194+
)
195+
@pytest.mark.asyncio
196+
async def test_aiohttp_oversized_request_body_data_collection(
197+
sentry_init, aiohttp_client, capture_events, data_collection, expect_annotated
198+
):
199+
"""
200+
The gating happens before the size check. When bodies are collected, an
201+
oversized body is still reported as removed because of the size limit; when
202+
they are not, it is dropped outright with no annotation.
203+
"""
204+
sentry_init(
205+
integrations=[AioHttpIntegration()],
206+
max_request_body_size="small",
207+
_experiments={"data_collection": data_collection},
208+
)
209+
210+
body = "a" * 2000
211+
212+
async def hello(request):
213+
await request.text()
214+
1 / 0
215+
216+
app = web.Application()
217+
app.router.add_post("/", hello)
218+
219+
events = capture_events()
220+
221+
client = await aiohttp_client(app)
222+
resp = await client.post("/", data=body)
223+
assert resp.status == 500
224+
225+
(event,) = events
226+
request_meta = event.get("_meta", {}).get("request", {})
227+
228+
if expect_annotated:
229+
assert event["request"]["data"] == OVER_SIZE_LIMIT_SUBSTITUTE
230+
assert request_meta["data"] == {"": {"rem": [["!config", "s"]]}}
231+
else:
232+
assert "data" not in event["request"]
233+
assert "data" not in request_meta
234+
235+
134236
@pytest.mark.asyncio
135237
async def test_403_not_captured(sentry_init, aiohttp_client, capture_events):
136238
sentry_init(integrations=[AioHttpIntegration()])

0 commit comments

Comments
 (0)