4242 from flask .signals import (
4343 before_render_template ,
4444 got_request_exception ,
45+ request_finished ,
4546 request_started ,
4647 )
4748 from markupsafe import Markup
@@ -94,6 +95,7 @@ def setup_once() -> None:
9495
9596 before_render_template .connect (_add_sentry_trace )
9697 request_started .connect (_request_started )
98+ request_finished .connect (_request_finished )
9799 got_request_exception .connect (_capture_exception )
98100
99101 old_app = Flask .__call__
@@ -164,8 +166,15 @@ def _request_started(app: "Flask", **kwargs: "Any") -> None:
164166 evt_processor = _make_request_event_processor (app , request , integration )
165167 scope .add_event_processor (evt_processor )
166168
169+
170+ def _request_finished (sender : "Flask" , response : "Any" , ** kwargs : "Any" ) -> None :
171+ integration = sentry_sdk .get_client ().get_integration (FlaskIntegration )
172+ if integration is None :
173+ return
174+
167175 client = sentry_sdk .get_client ()
168176 if has_span_streaming_enabled (client .options ):
177+ request = flask_request ._get_current_object ()
169178 _set_request_body_data_on_streaming_segment (request , client )
170179
171180
@@ -178,18 +187,26 @@ def _set_request_body_data_on_streaming_segment(
178187
179188 with capture_internal_exceptions ():
180189 content_length = int (request .content_length or 0 )
181- extractor = FlaskRequestExtractor (request )
182190
183191 if not request_body_within_bounds (client , content_length ):
184192 data = AnnotatedValue .substituted_because_over_size_limit ()
185193 else :
186- raw_data = None
187- try :
188- raw_data = extractor .raw_data ()
189- except _RAW_DATA_EXCEPTIONS :
190- pass
194+ # Only use data that Werkzeug has already cached — never consume
195+ # wsgi.input ourselves, as that would break user code that reads
196+ # the stream directly.
197+ # You can find where this gets set here:
198+ # https://github.com/pallets/werkzeug/blob/1b00618e787f40dfb21eba29caf8f8be7c8e1d93/src/werkzeug/wrappers/request.py#L444
199+ raw_data = getattr (request , "_cached_data" , None )
200+
201+ parsed_body = None
202+ if "form" in request .__dict__ :
203+ extractor = FlaskRequestExtractor (request )
204+ parsed_body = extractor .parsed_body ()
205+ elif raw_data is not None :
206+ extractor = FlaskRequestExtractor (request )
207+ if extractor .is_json ():
208+ parsed_body = extractor .json ()
191209
192- parsed_body = extractor .parsed_body ()
193210 if parsed_body is not None :
194211 data = parsed_body
195212 elif raw_data :
0 commit comments