Skip to content

Commit 016da7e

Browse files
committed
Merge remote-tracking branch 'origin/master' into wip/sessiontracking
2 parents 73c116b + 1aa3383 commit 016da7e

File tree

10 files changed

+175
-183
lines changed

10 files changed

+175
-183
lines changed

sentry_sdk/integrations/_wsgi_common.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@
1111
from typing import Union
1212

1313

14+
SENSITIVE_ENV_KEYS = (
15+
"REMOTE_ADDR",
16+
"HTTP_X_FORWARDED_FOR",
17+
"HTTP_SET_COOKIE",
18+
"HTTP_COOKIE",
19+
"HTTP_AUTHORIZATION",
20+
"HTTP_X_FORWARDED_FOR",
21+
"HTTP_X_REAL_IP",
22+
)
23+
24+
SENSITIVE_HEADERS = tuple(
25+
x[len("HTTP_") :] for x in SENSITIVE_ENV_KEYS if x.startswith("HTTP_")
26+
)
27+
28+
1429
class RequestExtractor(object):
1530
def __init__(self, request):
1631
# type: (Any) -> None
@@ -129,7 +144,10 @@ def _filter_headers(headers):
129144
return headers
130145

131146
return {
132-
k: v
147+
k: (
148+
v
149+
if k.upper().replace("-", "_") not in SENSITIVE_HEADERS
150+
else AnnotatedValue("", {"rem": [["!config", "x", 0, len(v)]]})
151+
)
133152
for k, v in iteritems(headers)
134-
if k.lower().replace("_", "-") not in ("set-cookie", "cookie", "authorization")
135153
}

sentry_sdk/integrations/django/__init__.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,25 @@ def sentry_patched_get_response(self, request):
134134

135135
BaseHandler.get_response = sentry_patched_get_response
136136

137+
try:
138+
from rest_framework.views import APIView # type: ignore
139+
except ImportError:
140+
pass
141+
else:
142+
# DRF's request type (which wraps the Django request and proxies
143+
# all attrs) has some attributes such as `data` which buffer
144+
# request data. We want to use those in the RequestExtractor to
145+
# get body data more reliably.
146+
old_drf_initial = APIView.initial
147+
148+
def sentry_patched_drf_initial(self, request, *args, **kwargs):
149+
with capture_internal_exceptions():
150+
request._request._sentry_drf_request_backref = weakref.ref(request)
151+
pass
152+
return old_drf_initial(self, request, *args, **kwargs)
153+
154+
APIView.initial = sentry_patched_drf_initial
155+
137156
signals.got_request_exception.connect(_got_request_exception)
138157

139158
@add_global_event_processor
@@ -207,6 +226,13 @@ def event_processor(event, hint):
207226
if request is None:
208227
return event
209228

229+
try:
230+
drf_request = request._sentry_drf_request_backref()
231+
if drf_request is not None:
232+
request = drf_request
233+
except AttributeError:
234+
pass
235+
210236
with capture_internal_exceptions():
211237
DjangoRequestExtractor(request).extract_into_event(event)
212238

sentry_sdk/integrations/gnu_backtrace.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
(?P<package>{MODULE_RE})\(
2121
(?P<retval>{TYPE_RE}\ )?
2222
((?P<function>{TYPE_RE})
23-
(?P<args>\([^)]*\))?
23+
(?P<args>\(.*\))?
2424
)?
2525
((?P<constoffset>\ const)?\+0x(?P<offset>{HEXVAL_RE}))?
2626
\)\s
@@ -89,13 +89,8 @@ def _process_gnu_backtrace(event, hint):
8989
},
9090
)
9191
)
92-
elif additional_frames and line.strip():
93-
# If we already started parsing a stacktrace, it must be at the
94-
# end of the message and must not contain random garbage lines
95-
# between the frames
96-
del additional_frames[:]
97-
break
9892
else:
93+
# Put garbage lines back into message, not sure what to do with them.
9994
new_msg.append(line)
10095

10196
if additional_frames:

sentry_sdk/integrations/wsgi.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,9 @@ def _get_environ(environ):
100100
"""
101101
keys = ["SERVER_NAME", "SERVER_PORT"]
102102
if _should_send_default_pii():
103-
# Add all three headers here to make debugging of proxy setup easier.
104-
keys += ["REMOTE_ADDR", "HTTP_X_FORWARDED_FOR", "HTTP_X_REAL_IP"]
103+
# make debugging of proxy setup easier. Proxy headers are
104+
# in headers.
105+
keys += ["REMOTE_ADDR"]
105106

106107
for key in keys:
107108
if key in environ:

tests/integrations/django/myapp/urls.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@
4242
urlpatterns.append(
4343
path("rest-framework-exc", views.rest_framework_exc, name="rest_framework_exc")
4444
)
45+
urlpatterns.append(
46+
path(
47+
"rest-framework-read-body-and-exc",
48+
views.rest_framework_read_body_and_exc,
49+
name="rest_framework_read_body_and_exc",
50+
)
51+
)
4552
except AttributeError:
4653
pass
4754

tests/integrations/django/myapp/views.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
def rest_framework_exc(request):
1212
1 / 0
1313

14+
@api_view(["POST"])
15+
def rest_framework_read_body_and_exc(request):
16+
request.data
17+
1 / 0
18+
1419

1520
except ImportError:
1621
pass

tests/integrations/django/test_basic.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ def test_read_request(sentry_init, client, capture_events):
374374

375375
event, = events
376376

377-
assert event["request"]["data"] == {"hey": 42}
377+
assert "data" not in event["request"]
378378

379379

380380
def test_template_exception(sentry_init, client, capture_events):
@@ -413,12 +413,15 @@ def test_template_exception(sentry_init, client, capture_events):
413413
]
414414

415415

416+
@pytest.mark.parametrize(
417+
"route", ["rest_framework_exc", "rest_framework_read_body_and_exc"]
418+
)
416419
@pytest.mark.parametrize(
417420
"type,event_request",
418421
[
419422
[
420423
"json",
421-
{
424+
lambda route: {
422425
"cookies": {},
423426
"data": {"foo": "bar"},
424427
"env": {"SERVER_NAME": "localhost", "SERVER_PORT": "80"},
@@ -429,12 +432,12 @@ def test_template_exception(sentry_init, client, capture_events):
429432
},
430433
"method": "POST",
431434
"query_string": "",
432-
"url": "http://localhost/rest-framework-exc",
435+
"url": "http://localhost/{}".format(route.replace("_", "-")),
433436
},
434437
],
435438
[
436439
"formdata",
437-
{
440+
lambda route: {
438441
"cookies": {},
439442
"data": {"foo": "bar"},
440443
"env": {"SERVER_NAME": "localhost", "SERVER_PORT": "80"},
@@ -445,13 +448,13 @@ def test_template_exception(sentry_init, client, capture_events):
445448
},
446449
"method": "POST",
447450
"query_string": "",
448-
"url": "http://localhost/rest-framework-exc",
451+
"url": "http://localhost/{}".format(route.replace("_", "-")),
449452
},
450453
],
451454
],
452455
)
453456
def test_rest_framework_basic(
454-
sentry_init, client, capture_events, capture_exceptions, type, event_request
457+
sentry_init, client, capture_events, capture_exceptions, type, event_request, route
455458
):
456459
pytest.importorskip("rest_framework")
457460
sentry_init(integrations=[DjangoIntegration()], send_default_pii=True)
@@ -460,12 +463,12 @@ def test_rest_framework_basic(
460463

461464
if type == "json":
462465
client.post(
463-
reverse("rest_framework_exc"),
466+
reverse(route),
464467
data=json.dumps({"foo": "bar"}),
465468
content_type="application/json",
466469
)
467470
elif type == "formdata":
468-
client.post(reverse("rest_framework_exc"), data={"foo": "bar"})
471+
client.post(reverse(route), data={"foo": "bar"})
469472
else:
470473
assert False
471474

@@ -475,4 +478,4 @@ def test_rest_framework_basic(
475478
event, = events
476479
assert event["exception"]["values"][0]["mechanism"]["type"] == "django"
477480

478-
assert event["request"] == event_request
481+
assert event["request"] == event_request(route)

tests/integrations/pyramid/test_pyramid.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,35 @@ def authenticated_userid(self, request):
327327
client.get("/message")
328328

329329
assert len(events) == 1
330+
331+
332+
def tween_factory(handler, registry):
333+
def tween(request):
334+
try:
335+
response = handler(request)
336+
except Exception:
337+
mroute = request.matched_route
338+
if mroute and mroute.name in ("index",):
339+
return Response("bad request", status_code=400)
340+
return response
341+
342+
return tween
343+
344+
345+
def test_tween_ok(sentry_init, pyramid_config, capture_exceptions, route, get_client):
346+
sentry_init(integrations=[PyramidIntegration()])
347+
errors = capture_exceptions()
348+
349+
@route("/")
350+
def index(request):
351+
raise Exception()
352+
353+
pyramid_config.add_tween(
354+
"tests.integrations.pyramid.test_pyramid.tween_factory",
355+
under=pyramid.tweens.INGRESS,
356+
)
357+
358+
client = get_client()
359+
client.get("/")
360+
361+
assert not errors

0 commit comments

Comments
 (0)