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
23 changes: 23 additions & 0 deletions sentry_sdk/integrations/aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
AnnotatedValue,
_get_aws_sigv4_signed_headers_from_authorization_header,
_get_aws_sigv4_signed_headers_from_url_query_string,
_is_localhost,
_register_control_flow_exception,
capture_internal_exceptions,
ensure_integration_enabled,
Expand Down Expand Up @@ -146,6 +147,17 @@ async def sentry_app_handle(
scope.clear_breadcrumbs()
scope.add_event_processor(_make_request_processor(weak_request))

scope.set_attribute(
SPANDATA.SENTRY_IS_LOCALHOST,
_is_localhost(
client_ip=_get_client_ip(request),
host_header=request.headers.get("Host"),
forwarded_host_header=request.headers.get(
"X-Forwarded-Host"
),
),
)

Comment thread
sentrivana marked this conversation as resolved.
Resolved
headers = dict(request.headers)

span_ctx: "ContextManager[Union[Span, StreamedSpan]]"
Expand Down Expand Up @@ -643,6 +655,17 @@ def aiohttp_processor(
return aiohttp_processor


def _get_client_ip(request: "Request") -> "Optional[str]":
x_forwarded_for = request.headers.get("X-Forwarded-For", "").split(",")[0].strip()
if x_forwarded_for:
return x_forwarded_for

if request.headers.get("X-Real-IP"):
return request.headers["X-Real-IP"]

return request.remote


def _capture_exception() -> "ExcInfo":
exc_info = sys.exc_info()
event, hint = event_from_exception(
Expand Down
56 changes: 56 additions & 0 deletions tests/integrations/aiohttp/test_aiohttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2416,6 +2416,62 @@ async def hello(request):
assert event["request"]["query_string"] == expected_query


@pytest.mark.asyncio
@pytest.mark.parametrize(
"forwarded_for, host_header, is_localhost",
[
pytest.param(None, None, True, id="loopback-ip"),
pytest.param(
"93.184.216.34", "localhost:8080", True, id="localhost-host-header"
),
pytest.param("93.184.216.34", "example.com", False, id="non-local"),
],
)
async def test_is_localhost_attribute(
sentry_init,
aiohttp_client,
capture_items,
forwarded_for,
host_header,
is_localhost,
):
sentry_init(
integrations=[AioHttpIntegration()],
traces_sample_rate=1.0,
trace_lifecycle="stream",
)

async def hello(request):
with sentry_sdk.traces.start_span(name="child"):
pass
return web.Response(text="hello")

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

items = capture_items("span")

client = await aiohttp_client(app)
headers = {}
if host_header:
headers["Host"] = host_header
if forwarded_for:
headers["X-Forwarded-For"] = forwarded_for
resp = await client.get("/", headers=headers)
assert resp.status == 200

sentry_sdk.flush()

child_spans = [item.payload for item in items if not item.payload.get("is_segment")]
server_spans = [item.payload for item in items if item.payload.get("is_segment")]

assert len(server_spans) == 1
assert len(child_spans) == 1

assert server_spans[0]["attributes"][SPANDATA.SENTRY_IS_LOCALHOST] == is_localhost
assert child_spans[0]["attributes"][SPANDATA.SENTRY_IS_LOCALHOST] == is_localhost


@pytest.mark.asyncio
@pytest.mark.parametrize(
"init_kwargs, expect_remote_addr", DATA_COLLECTION_REMOTE_ADDR_CASES
Expand Down
Loading