Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion sentry_sdk/integrations/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ def aiohttp_processor(
if request is None:
return event

client_options = sentry_sdk.get_client().options
with capture_internal_exceptions():
request_info = event.setdefault("request", {})

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

return event

Expand Down
102 changes: 102 additions & 0 deletions tests/integrations/aiohttp/test_aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import sentry_sdk
from sentry_sdk import capture_message, start_transaction
from sentry_sdk._types import OVER_SIZE_LIMIT_SUBSTITUTE
from sentry_sdk.consts import SPANDATA
from sentry_sdk.integrations.aiohttp import (
AioHttpIntegration,
Expand Down Expand Up @@ -131,6 +132,107 @@ async def hello(request):
assert request["data"] == json.dumps(body)


@pytest.mark.parametrize(
"data_collection, expect_body",
[
pytest.param({}, True, id="data_collection_http_bodies_default"),
pytest.param(
{"http_bodies": ["incoming_request"]},
True,
id="data_collection_http_bodies_incoming_request",
),
pytest.param(
{"http_bodies": []}, False, id="data_collection_http_bodies_empty"
),
],
)
@pytest.mark.asyncio
async def test_aiohttp_request_body_data_collection(
sentry_init, aiohttp_client, capture_events, data_collection, expect_body
):
sentry_init(
integrations=[AioHttpIntegration()],
_experiments={"data_collection": data_collection},
)

body = {"some": "value"}

async def hello(request):
await request.json()
1 / 0

app = web.Application()
app.router.add_post("/", hello)

events = capture_events()

client = await aiohttp_client(app)
resp = await client.post("/", json=body)
assert resp.status == 500

(event,) = events
request = event["request"]

if expect_body:
assert request["data"] == json.dumps(body)
else:
assert "data" not in request


@pytest.mark.parametrize(
"data_collection, expect_annotated",
[
pytest.param(
{"http_bodies": ["incoming_request"]},
True,
id="data_collection_http_bodies_incoming_request",
),
pytest.param(
{"http_bodies": []}, False, id="data_collection_http_bodies_empty"
),
],
)
@pytest.mark.asyncio
async def test_aiohttp_oversized_request_body_data_collection(
sentry_init, aiohttp_client, capture_events, data_collection, expect_annotated
):
"""
The gating happens before the size check. When bodies are collected, an
oversized body is still reported as removed because of the size limit; when
they are not, it is dropped outright with no annotation.
"""
sentry_init(
integrations=[AioHttpIntegration()],
max_request_body_size="small",
_experiments={"data_collection": data_collection},
)

body = "a" * 2000

async def hello(request):
await request.text()
1 / 0

app = web.Application()
app.router.add_post("/", hello)

events = capture_events()

client = await aiohttp_client(app)
resp = await client.post("/", data=body)
assert resp.status == 500

(event,) = events
request_meta = event.get("_meta", {}).get("request", {})

if expect_annotated:
assert event["request"]["data"] == OVER_SIZE_LIMIT_SUBSTITUTE
assert request_meta["data"] == {"": {"rem": [["!config", "s"]]}}
else:
assert "data" not in event["request"]
assert "data" not in request_meta


@pytest.mark.asyncio
async def test_403_not_captured(sentry_init, aiohttp_client, capture_events):
sentry_init(integrations=[AioHttpIntegration()])
Expand Down
Loading