feat(network-details): Introduce new swizzling to capture response bodies for session replay#7584
feat(network-details): Introduce new swizzling to capture response bodies for session replay#758443jay wants to merge 4 commits intomobile-935/data-classesfrom
Conversation
Semver Impact of This PR🟡 Minor (new features) 📋 Changelog PreviewThis is how your changes will appear in the changelog. This PR will not appear in the changelog. 🤖 This preview updates automatically when you update the PR. |
|
❌ 2 Tests Failed:
View the top 2 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
82a2dd5 to
9473efb
Compare
philipphofmann
left a comment
There was a problem hiding this comment.
Thanks for tackling this. I have one major high-level question before reviewing this more closely.
71fd40b to
78d1d60
Compare
9473efb to
5bc5830
Compare
78d1d60 to
9a4f8b3
Compare
5bc5830 to
7faf4ef
Compare
9a4f8b3 to
c62d15c
Compare
7faf4ef to
6e19c0a
Compare
c62d15c to
e717c1a
Compare
6e19c0a to
9a8d48d
Compare
8584657 to
c3afd6d
Compare
2d31c8d to
72a427a
Compare
6e873ec to
a691160
Compare
72a427a to
56c7a59
Compare
Tests/SentryTests/Integrations/Performance/Network/SentryNSURLSessionTaskSearchTests.swift
Outdated
Show resolved
Hide resolved
Tests/SentryTests/Integrations/Performance/Network/SentryNSURLSessionTaskSearchTests.swift
Outdated
Show resolved
Hide resolved
Tests/SentryTests/Integrations/Performance/Network/SentryNSURLSessionTaskSearchTests.swift
Show resolved
Hide resolved
56c7a59 to
a41d68f
Compare
a691160 to
7db5474
Compare
Review notes — treat with care
TL;DR — suggested restructureThe
The completion handler swizzle would become a simple, self-contained block with no tricky patterns: wrapped = ^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error && data) {
[networkTracker captureNetworkDetailsForReplayWithRequest:request
response:response
responseData:data];
}
completionHandler(data, response, error);
};No Detailed findings from Claude Code investigation1. The
|
appreciate the input, will work through it fully. At a glance some is valid and some I already worked through. The main issue :
The issue I hit was that The others don't seem relevant or seem inaccurate:
This isn't correct based on my local testing. The completionHandler always fired before Regardless the code is written so that if completionHandler fires before ANY call to setState, then sentry-cocoa/Sources/Sentry/SentryNetworkTracker.m Lines 605 to 610 in fea8910
This is our other convo - basically NSURLSession dataTask initializers are NOT currently class clusters (claude misspoke/inaccurate above). Regardless, the impl might change. The tests added to
This is point 1. The taskHolder chicken-and-egg pattern |
7db5474 to
a75e679
Compare
a41d68f to
41f8885
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Fabricated request creates inconsistency between swizzled methods
- Both swizzles now pass
task.currentRequest ?: task.originalRequestand the URL-based swizzle no longer fabricates an eager URL-only request.
- Both swizzles now pass
Or push these changes by commenting:
@cursor push 089f8d3da3
Preview (089f8d3da3)
diff --git a/Sources/Sentry/SentrySwizzleWrapperHelper.m b/Sources/Sentry/SentrySwizzleWrapperHelper.m
--- a/Sources/Sentry/SentrySwizzleWrapperHelper.m
+++ b/Sources/Sentry/SentrySwizzleWrapperHelper.m
@@ -129,11 +129,12 @@
void (^wrappedHandler)(NSData *, NSURLResponse *, NSError *) = nil;
if (completionHandler) {
wrappedHandler = ^(NSData *data, NSURLResponse *response, NSError *error) {
- if (!error && data && task) {
+ NSURLRequest *capturedRequest = task.currentRequest ?: task.originalRequest;
+ if (!error && data && task && capturedRequest) {
[networkTracker captureResponseDetails:data
- response:response
- request:request
- task:task];
+ response:response
+ request:capturedRequest
+ task:task];
}
completionHandler(data, response, error);
};
@@ -158,16 +159,16 @@
SentrySWArguments(
NSURL * url, void (^completionHandler)(NSData *, NSURLResponse *, NSError *)),
SentrySWReplacement({
- NSURLRequest *request = [NSURLRequest requestWithURL:url];
__block NSURLSessionDataTask *task = nil;
void (^wrappedHandler)(NSData *, NSURLResponse *, NSError *) = nil;
if (completionHandler) {
wrappedHandler = ^(NSData *data, NSURLResponse *response, NSError *error) {
- if (!error && data && task) {
+ NSURLRequest *capturedRequest = task.currentRequest ?: task.originalRequest;
+ if (!error && data && task && capturedRequest) {
[networkTracker captureResponseDetails:data
- response:response
- request:request
- task:task];
+ response:response
+ request:capturedRequest
+ task:task];
}
completionHandler(data, response, error);
};This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
a75e679 to
75d4331
Compare
| /** | ||
| * Swizzles -[NSURLSession dataTaskWithRequest:completionHandler:] to intercept response data. | ||
| */ | ||
| + (void)swizzleDataTaskWithRequestCompletionHandler:(SentryNetworkTracker *)networkTracker |
There was a problem hiding this comment.
h: I would like to see some test verifying the swizzling actually work.
While this looks good, it may break at any point in later versions.
While it is not the same, a strategy similar to SentryNSDataSwizzlingHelperTests.swift could be used to verify the methods are swizzled when executing a datatask
The current tests are verifying the method are changed, but not that they are actually called (what we actually care for)
Once that is added, this would look good to me to merge
There was a problem hiding this comment.
something like the following ? (kind of like an API test / integration test - i.e. use the API and validate that the swizzling callbacks a) occur and ideally b) occur as expected )
test scenario
- Initialize a NSUrlSessionDataTask
resumeit (or whatever the API is to get it to run)- have it run to completion
- verify our completionHandler called, verify the original completion handler called
Couple different versions:
For both newly swizzled initializers:
- With networkDetailAllowUrls populated (feature turned on; swizzling active)
- With networkDetailAllowUrls populated (feature turned off; swizzling non-existent)
Will do.
if you see this in time => help me by weighing in on whether this sounds like a test that should use an actual server (there is some test server set-up that i haven't needed to use it but will set it up if you say it's the right direction).
Or if the current test harness (à la unit test with mocking) is good enough,
There was a problem hiding this comment.
That sounds good to me, you can use https://postman-echo.com
If it is flaky we can boot a local server, but I would prefer not to do that if possible
…onse capture Add (no-op) callback into SentryNetworkTracker Remove run-time discovery for swizzle targets; directly swizzle [NSURLSession class] Add unit test to do run-time discovery and report if assumptions invalid
#7584 (comment) test_dataTaskWithURL_doesNotCallThrough_dataTaskWithRequest test_dataTaskWithRequest_doesNotCallThrough_dataTaskWithURL were asserting that one impl does not rely on the other internally. There's no reason to believe that they do - the test was probably checking for something that would not happen. Additionally it was relying on method_setImplementation which could cause random failures in CI if not cleaned up properly => remove
…etworkDetailHasUrls
…wizzling Verify that the swizzled dataTaskWithRequest:completionHandler: and dataTaskWithURL:completionHandler: actually fire and populate network details on breadcrumbs using real HTTP requests to postman-echo.com.
75d4331 to
c24784c
Compare
41f8885 to
389f418
Compare
🚨 Detected changes in high risk code 🚨High-risk code can easily blow up and is hard to test. We had severe bugs in the past. Be extra careful when changing these files, and have an extra careful look at these:
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit c24784c. Configure here.


📜 Description
Newly swizzled methods:
[NSURLSession dataTaskWithURL:completionHandler:][NSURLSession dataTaskWithRequest:completionHandler:]This swizzling is skipped when network detail capture is not enabled (SentryReplayOptions#networkDetailAllowUrls is empty)
Added testing to validate for future iOS SDKs that the
IMPs we are swizzling are implemented directly on NSURLSession: SentryNSURLSessionTaskSearchTeststest_URLSessionDataTaskWithRequest_ByIosVersiontest_URLSessionDataTaskWithURL_ByIosVersion💡 Motivation and Context
With this change sentry-cocoa can inspect response bodies of NSURLSession
dataTask's that use completionHandlers.Swizzling is added to inspect the NSURLResponse before delegating to the original completionHandler.
The request body will be captured via existing swizzling into SentryNetworkTracker (
setState,resume).See swizzling discussion on #7582 for more context.
💚 How did you test it?
Unit tests
📝 Checklist
You have to check all boxes before merging:
sendDefaultPIIis enabled. gated by networkDetailAllowUrls