| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697 |
- // Copyright 2020 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- /** NSURLSession is a class cluster and the type of class you get back from the various
- * initialization methods might not actually be NSURLSession. Inside those methods, this class
- * keeps track of seen NSURLSession subclasses and lazily swizzles them if they've not been seen.
- * Consequently, swizzling needs to occur on a serial queue for thread safety.
- */
- #import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument.h"
- #import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument_Private.h"
- #import "FirebasePerformance/Sources/Common/FPRDiagnostics.h"
- #import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h"
- #import "FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h"
- #import "FirebasePerformance/Sources/Instrumentation/FPRInstrument_Private.h"
- #import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h"
- #import "FirebasePerformance/Sources/Instrumentation/FPRProxyObjectHelper.h"
- #import "FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h"
- #import "FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegate.h"
- #import "FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.h"
- #import <GoogleUtilities/GULObjectSwizzler.h>
- // Declared for use in instrumentation functions below.
- @interface FPRNSURLSessionInstrument ()
- /** Registers an instrumentor for an NSURLSession subclass if it hasn't yet been instrumented.
- *
- * @param aClass The class we wish to instrument.
- */
- - (void)registerInstrumentorForClass:(Class)aClass;
- /** Registers an instrumentor for an NSURLSession proxy object if it hasn't yet been instrumented.
- *
- * @param proxy The proxy object we wish to instrument.
- */
- - (void)registerProxyObject:(id)proxy;
- @end
- /** Returns the dispatch queue for all instrumentation to occur on. */
- static dispatch_queue_t GetInstrumentationQueue(void) {
- static dispatch_queue_t queue = nil;
- static dispatch_once_t token = 0;
- dispatch_once(&token, ^{
- queue =
- dispatch_queue_create("com.google.FPRNSURLSessionInstrumentation", DISPATCH_QUEUE_SERIAL);
- });
- return queue;
- }
- // This completion handler type is commonly used throughout NSURLSession.
- typedef void (^FPRDataTaskCompletionHandler)(NSData *_Nullable,
- NSURLResponse *_Nullable,
- NSError *_Nullable);
- typedef void (^FPRDownloadTaskCompletionHandler)(NSURL *_Nullable location,
- NSURLResponse *_Nullable response,
- NSError *_Nullable error);
- #pragma mark - Instrumentation Functions
- /** Wraps +sharedSession.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentSharedSession(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(sharedSession);
- Class instrumentedClass = instrumentor.instrumentedClass;
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, YES);
- __weak FPRNSURLSessionInstrument *weakInstrument = instrument;
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session) {
- __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument;
- if (!strongInstrument) {
- ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentedClass);
- }
- typedef NSURLSession *(*OriginalImp)(id, SEL);
- NSURLSession *sharedSession = ((OriginalImp)currentIMP)(session, selector);
- if ([sharedSession isProxy]) {
- [strongInstrument registerProxyObject:sharedSession];
- } else {
- [strongInstrument registerInstrumentorForClass:[sharedSession class]];
- }
- return sharedSession;
- }];
- }
- /** Wraps +sessionWithConfiguration:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentSessionWithConfiguration(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(sessionWithConfiguration:);
- Class instrumentedClass = instrumentor.instrumentedClass;
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, YES);
- __weak FPRNSURLSessionInstrument *weakInstrument = instrument;
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURLSessionConfiguration *configuration) {
- __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument;
- if (!strongInstrument) {
- ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentedClass);
- }
- typedef NSURLSession *(*OriginalImp)(id, SEL, NSURLSessionConfiguration *);
- NSURLSession *sessionInstance = ((OriginalImp)currentIMP)(session, selector, configuration);
- if ([sessionInstance isProxy]) {
- [strongInstrument registerProxyObject:sessionInstance];
- } else {
- [strongInstrument registerInstrumentorForClass:[sessionInstance class]];
- }
- return sessionInstance;
- }];
- }
- /** Wraps +sessionWithConfiguration:delegate:delegateQueue:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- * @param delegateInstrument The FPRNSURLSessionDelegateInstrument that will track the delegate
- * selectors.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentSessionWithConfigurationDelegateDelegateQueue(
- FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor,
- FPRNSURLSessionDelegateInstrument *delegateInstrument) {
- SEL selector = @selector(sessionWithConfiguration:delegate:delegateQueue:);
- Class instrumentedClass = instrumentor.instrumentedClass;
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, YES);
- __weak FPRNSURLSessionInstrument *weakInstrument = instrument;
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor
- setReplacingBlock:^(id session, NSURLSessionConfiguration *configuration,
- id<NSURLSessionDelegate> delegate, NSOperationQueue *queue) {
- __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument;
- if (!strongInstrument) {
- ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentedClass);
- }
- if (delegate) {
- [delegateInstrument registerClass:[delegate class]];
- [delegateInstrument registerObject:delegate];
- } else {
- delegate = [[FPRNSURLSessionDelegate alloc] init];
- }
- typedef NSURLSession *(*OriginalImp)(id, SEL, NSURLSessionConfiguration *,
- id<NSURLSessionDelegate>, NSOperationQueue *);
- NSURLSession *sessionInstance =
- ((OriginalImp)currentIMP)([session class], selector, configuration, delegate, queue);
- if ([sessionInstance isProxy]) {
- [strongInstrument registerProxyObject:sessionInstance];
- } else {
- [strongInstrument registerInstrumentorForClass:[sessionInstance class]];
- }
- return sessionInstance;
- }];
- }
- /** Wraps -dataTaskWithURL:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentDataTaskWithURL(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(dataTaskWithURL:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- __weak FPRNSURLSessionInstrument *weakInstrument = instrument;
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURL *url) {
- __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument;
- if (!strongInstrument) {
- ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass);
- }
- typedef NSURLSessionDataTask *(*OriginalImp)(id, SEL, NSURL *);
- NSURLSessionDataTask *dataTask = ((OriginalImp)currentIMP)(session, selector, url);
- if (dataTask.originalRequest) {
- FPRNetworkTrace *trace =
- [[FPRNetworkTrace alloc] initWithURLRequest:dataTask.originalRequest];
- [trace start];
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [FPRNetworkTrace addNetworkTrace:trace toObject:dataTask];
- }
- return dataTask;
- }];
- }
- /** Instruments -dataTaskWithURL:completionHandler:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentDataTaskWithURLCompletionHandler(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(dataTaskWithURL:completionHandler:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURL *URL,
- FPRDataTaskCompletionHandler completionHandler) {
- __block NSURLSessionDataTask *task = nil;
- FPRDataTaskCompletionHandler wrappedCompletionHandler = nil;
- if (completionHandler) {
- wrappedCompletionHandler = ^(NSData *data, NSURLResponse *response, NSError *error) {
- FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:task];
- [trace didReceiveData:data];
- [trace didCompleteRequestWithResponse:response error:error];
- [FPRNetworkTrace removeNetworkTraceFromObject:task];
- completionHandler(data, response, error);
- };
- }
- typedef NSURLSessionDataTask *(*OriginalImp)(id, SEL, NSURL *, FPRDataTaskCompletionHandler);
- task = ((OriginalImp)currentIMP)(session, selector, URL, wrappedCompletionHandler);
- // Add the network trace object only when the trace object is not added to the task object.
- if ([FPRNetworkTrace networkTraceFromObject:task] == nil) {
- FPRNetworkTrace *trace = [[FPRNetworkTrace alloc] initWithURLRequest:task.originalRequest];
- [trace start];
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [FPRNetworkTrace addNetworkTrace:trace toObject:task];
- }
- return task;
- }];
- }
- /** Wraps -dataTaskWithRequest:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentDataTaskWithRequest(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(dataTaskWithRequest:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- __weak FPRNSURLSessionInstrument *weakInstrument = instrument;
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request) {
- __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument;
- if (!strongInstrument) {
- ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass);
- }
- typedef NSURLSessionDataTask *(*OriginalImp)(id, SEL, NSURLRequest *);
- NSURLSessionDataTask *dataTask = ((OriginalImp)currentIMP)(session, selector, request);
- if (dataTask.originalRequest) {
- FPRNetworkTrace *trace =
- [[FPRNetworkTrace alloc] initWithURLRequest:dataTask.originalRequest];
- [trace start];
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [FPRNetworkTrace addNetworkTrace:trace toObject:dataTask];
- }
- return dataTask;
- }];
- }
- /** Instruments -dataTaskWithRequest:completionHandler:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentDataTaskWithRequestCompletionHandler(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(dataTaskWithRequest:completionHandler:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request,
- FPRDataTaskCompletionHandler completionHandler) {
- __block NSURLSessionDataTask *task = nil;
- FPRDataTaskCompletionHandler wrappedCompletionHandler = nil;
- if (completionHandler) {
- wrappedCompletionHandler = ^(NSData *data, NSURLResponse *response, NSError *error) {
- FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:task];
- [trace didReceiveData:data];
- [trace didCompleteRequestWithResponse:response error:error];
- [FPRNetworkTrace removeNetworkTraceFromObject:task];
- completionHandler(data, response, error);
- };
- }
- typedef NSURLSessionDataTask *(*OriginalImp)(id, SEL, NSURLRequest *,
- FPRDataTaskCompletionHandler);
- task = ((OriginalImp)currentIMP)(session, selector, request, wrappedCompletionHandler);
- // Add the network trace object only when the trace object is not added to the task object.
- if ([FPRNetworkTrace networkTraceFromObject:task] == nil) {
- FPRNetworkTrace *trace = [[FPRNetworkTrace alloc] initWithURLRequest:task.originalRequest];
- [trace start];
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [FPRNetworkTrace addNetworkTrace:trace toObject:task];
- }
- return task;
- }];
- }
- /** Instruments -uploadTaskWithRequest:fromFile:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentUploadTaskWithRequestFromFile(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(uploadTaskWithRequest:fromFile:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- __weak FPRNSURLSessionInstrument *weakInstrument = instrument;
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request, NSURL *fileURL) {
- __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument;
- if (!strongInstrument) {
- ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass);
- }
- typedef NSURLSessionUploadTask *(*OriginalImp)(id, SEL, NSURLRequest *, NSURL *);
- NSURLSessionUploadTask *uploadTask =
- ((OriginalImp)currentIMP)(session, selector, request, fileURL);
- if (uploadTask.originalRequest) {
- FPRNetworkTrace *trace =
- [[FPRNetworkTrace alloc] initWithURLRequest:uploadTask.originalRequest];
- [trace start];
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [FPRNetworkTrace addNetworkTrace:trace toObject:uploadTask];
- }
- return uploadTask;
- }];
- }
- /** Instruments -uploadTaskWithRequest:fromFile:completionHandler:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentUploadTaskWithRequestFromFileCompletionHandler(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(uploadTaskWithRequest:fromFile:completionHandler:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request, NSURL *fileURL,
- FPRDataTaskCompletionHandler completionHandler) {
- FPRNetworkTrace *trace = [[FPRNetworkTrace alloc] initWithURLRequest:request];
- [trace start];
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [trace didUploadFileWithURL:fileURL];
- FPRDataTaskCompletionHandler wrappedCompletionHandler = nil;
- if (completionHandler) {
- wrappedCompletionHandler = ^(NSData *data, NSURLResponse *response, NSError *error) {
- [trace didReceiveData:data];
- [trace didCompleteRequestWithResponse:response error:error];
- completionHandler(data, response, error);
- };
- }
- typedef NSURLSessionUploadTask *(*OriginalImp)(id, SEL, NSURLRequest *, NSURL *,
- FPRDataTaskCompletionHandler);
- return ((OriginalImp)currentIMP)(session, selector, request, fileURL, wrappedCompletionHandler);
- }];
- }
- /** Instruments -uploadTaskWithRequest:fromData:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentUploadTaskWithRequestFromData(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(uploadTaskWithRequest:fromData:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- __weak FPRNSURLSessionInstrument *weakInstrument = instrument;
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request, NSData *bodyData) {
- __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument;
- if (!strongInstrument) {
- ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass);
- }
- typedef NSURLSessionUploadTask *(*OriginalImp)(id, SEL, NSURLRequest *, NSData *);
- NSURLSessionUploadTask *uploadTask =
- ((OriginalImp)currentIMP)(session, selector, request, bodyData);
- if (uploadTask.originalRequest) {
- FPRNetworkTrace *trace =
- [[FPRNetworkTrace alloc] initWithURLRequest:uploadTask.originalRequest];
- [trace start];
- trace.requestSize = bodyData.length;
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [FPRNetworkTrace addNetworkTrace:trace toObject:uploadTask];
- }
- return uploadTask;
- }];
- }
- /** Instruments -uploadTaskWithRequest:fromData:completionHandler:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentUploadTaskWithRequestFromDataCompletionHandler(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(uploadTaskWithRequest:fromData:completionHandler:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request, NSData *bodyData,
- FPRDataTaskCompletionHandler completionHandler) {
- FPRNetworkTrace *trace = [[FPRNetworkTrace alloc] initWithURLRequest:request];
- [trace start];
- trace.requestSize = bodyData.length;
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- FPRDataTaskCompletionHandler wrappedCompletionHandler = nil;
- if (completionHandler) {
- wrappedCompletionHandler = ^(NSData *data, NSURLResponse *response, NSError *error) {
- [trace didReceiveData:data];
- [trace didCompleteRequestWithResponse:response error:error];
- completionHandler(data, response, error);
- };
- }
- typedef NSURLSessionUploadTask *(*OriginalImp)(id, SEL, NSURLRequest *, NSData *,
- FPRDataTaskCompletionHandler);
- return ((OriginalImp)currentIMP)(session, selector, request, bodyData,
- wrappedCompletionHandler);
- }];
- }
- /** Instruments -uploadTaskWithStreamedRequest:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentUploadTaskWithStreamedRequest(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(uploadTaskWithStreamedRequest:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- __weak FPRNSURLSessionInstrument *weakInstrument = instrument;
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request) {
- __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument;
- if (!strongInstrument) {
- ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass);
- }
- typedef NSURLSessionUploadTask *(*OriginalImp)(id, SEL, NSURLRequest *);
- NSURLSessionUploadTask *uploadTask = ((OriginalImp)currentIMP)(session, selector, request);
- if (uploadTask.originalRequest) {
- FPRNetworkTrace *trace =
- [[FPRNetworkTrace alloc] initWithURLRequest:uploadTask.originalRequest];
- [trace start];
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [FPRNetworkTrace addNetworkTrace:trace toObject:uploadTask];
- }
- return uploadTask;
- }];
- }
- /** Instruments -downloadTaskWithURL:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentDownloadTaskWithURL(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(downloadTaskWithURL:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- __weak FPRNSURLSessionInstrument *weakInstrument = instrument;
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURL *url) {
- __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument;
- if (!strongInstrument) {
- ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass);
- }
- typedef NSURLSessionDownloadTask *(*OriginalImp)(id, SEL, NSURL *);
- NSURLSessionDownloadTask *downloadTask = ((OriginalImp)currentIMP)(session, selector, url);
- if (downloadTask.originalRequest) {
- FPRNetworkTrace *trace =
- [[FPRNetworkTrace alloc] initWithURLRequest:downloadTask.originalRequest];
- [trace start];
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [FPRNetworkTrace addNetworkTrace:trace toObject:downloadTask];
- }
- return downloadTask;
- }];
- }
- /** Instruments -downloadTaskWithURL:completionHandler:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentDownloadTaskWithURLCompletionHandler(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(downloadTaskWithURL:completionHandler:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURL *URL,
- FPRDownloadTaskCompletionHandler completionHandler) {
- __block NSURLSessionDownloadTask *downloadTask = nil;
- FPRDownloadTaskCompletionHandler wrappedCompletionHandler = nil;
- if (completionHandler) {
- wrappedCompletionHandler = ^(NSURL *location, NSURLResponse *response, NSError *error) {
- FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:downloadTask];
- [trace didReceiveFileURL:location];
- [trace didCompleteRequestWithResponse:response error:error];
- completionHandler(location, response, error);
- };
- }
- typedef NSURLSessionDownloadTask *(*OriginalImp)(id, SEL, NSURL *,
- FPRDownloadTaskCompletionHandler);
- downloadTask = ((OriginalImp)currentIMP)(session, selector, URL, wrappedCompletionHandler);
- // Add the network trace object only when the trace object is not added to the task object.
- if ([FPRNetworkTrace networkTraceFromObject:downloadTask] == nil) {
- FPRNetworkTrace *trace =
- [[FPRNetworkTrace alloc] initWithURLRequest:downloadTask.originalRequest];
- [trace start];
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [FPRNetworkTrace addNetworkTrace:trace toObject:downloadTask];
- }
- return downloadTask;
- }];
- }
- /** Instruments -downloadTaskWithRequest:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentDownloadTaskWithRequest(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(downloadTaskWithRequest:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- __weak FPRNSURLSessionInstrument *weakInstrument = instrument;
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request) {
- __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument;
- if (!strongInstrument) {
- ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass);
- }
- typedef NSURLSessionDownloadTask *(*OriginalImp)(id, SEL, NSURLRequest *);
- NSURLSessionDownloadTask *downloadTask = ((OriginalImp)currentIMP)(session, selector, request);
- if (downloadTask.originalRequest) {
- FPRNetworkTrace *trace =
- [[FPRNetworkTrace alloc] initWithURLRequest:downloadTask.originalRequest];
- [trace start];
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [FPRNetworkTrace addNetworkTrace:trace toObject:downloadTask];
- }
- return downloadTask;
- }];
- }
- /** Instruments -downloadTaskWithRequest:completionHandler:.
- *
- * @param instrument The FPRNSURLSessionInstrument instance.
- * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to.
- */
- FOUNDATION_STATIC_INLINE
- NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")
- void InstrumentDownloadTaskWithRequestCompletionHandler(FPRNSURLSessionInstrument *instrument,
- FPRClassInstrumentor *instrumentor) {
- SEL selector = @selector(downloadTaskWithRequest:completionHandler:);
- FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO);
- IMP currentIMP = selectorInstrumentor.currentIMP;
- [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request,
- FPRDownloadTaskCompletionHandler completionHandler) {
- __block NSURLSessionDownloadTask *downloadTask = nil;
- FPRDownloadTaskCompletionHandler wrappedCompletionHandler = nil;
- if (completionHandler) {
- wrappedCompletionHandler = ^(NSURL *location, NSURLResponse *response, NSError *error) {
- FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:downloadTask];
- [trace didReceiveFileURL:location];
- [trace didCompleteRequestWithResponse:response error:error];
- completionHandler(location, response, error);
- };
- }
- typedef NSURLSessionDownloadTask *(*OriginalImp)(id, SEL, NSURLRequest *,
- FPRDownloadTaskCompletionHandler);
- downloadTask = ((OriginalImp)currentIMP)(session, selector, request, wrappedCompletionHandler);
- // Add the network trace object only when the trace object is not added to the task object.
- if ([FPRNetworkTrace networkTraceFromObject:downloadTask] == nil) {
- FPRNetworkTrace *trace =
- [[FPRNetworkTrace alloc] initWithURLRequest:downloadTask.originalRequest];
- [trace start];
- [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated];
- [FPRNetworkTrace addNetworkTrace:trace toObject:downloadTask];
- }
- return downloadTask;
- }];
- }
- #pragma mark - FPRNSURLSessionInstrument
- @implementation FPRNSURLSessionInstrument
- - (instancetype)init {
- self = [super init];
- if (self) {
- _delegateInstrument = [[FPRNSURLSessionDelegateInstrument alloc] init];
- [_delegateInstrument registerInstrumentors];
- }
- return self;
- }
- - (void)registerInstrumentors {
- [self registerInstrumentorForClass:[NSURLSession class]];
- }
- - (void)deregisterInstrumentors {
- [_delegateInstrument deregisterInstrumentors];
- [super deregisterInstrumentors];
- }
- - (void)registerInstrumentorForClass:(Class)aClass {
- dispatch_sync(GetInstrumentationQueue(), ^{
- FPRAssert([aClass isSubclassOfClass:[NSURLSession class]],
- @"Class %@ is not a subclass of "
- "NSURLSession",
- aClass);
- // If this class has already been instrumented, just return.
- FPRClassInstrumentor *instrumentor = [[FPRClassInstrumentor alloc] initWithClass:aClass];
- if (![self registerClassInstrumentor:instrumentor]) {
- return;
- }
- InstrumentSharedSession(self, instrumentor);
- InstrumentSessionWithConfiguration(self, instrumentor);
- InstrumentSessionWithConfigurationDelegateDelegateQueue(self, instrumentor,
- _delegateInstrument);
- InstrumentDataTaskWithURL(self, instrumentor);
- InstrumentDataTaskWithURLCompletionHandler(self, instrumentor);
- InstrumentDataTaskWithRequest(self, instrumentor);
- InstrumentDataTaskWithRequestCompletionHandler(self, instrumentor);
- InstrumentUploadTaskWithRequestFromFile(self, instrumentor);
- InstrumentUploadTaskWithRequestFromFileCompletionHandler(self, instrumentor);
- InstrumentUploadTaskWithRequestFromData(self, instrumentor);
- InstrumentUploadTaskWithRequestFromDataCompletionHandler(self, instrumentor);
- InstrumentUploadTaskWithStreamedRequest(self, instrumentor);
- InstrumentDownloadTaskWithURL(self, instrumentor);
- InstrumentDownloadTaskWithURLCompletionHandler(self, instrumentor);
- InstrumentDownloadTaskWithRequest(self, instrumentor);
- InstrumentDownloadTaskWithRequestCompletionHandler(self, instrumentor);
- [instrumentor swizzle];
- });
- }
- - (void)registerProxyObject:(id)proxy {
- [FPRProxyObjectHelper registerProxyObject:proxy
- forSuperclass:[NSURLSession class]
- varFoundHandler:^(id ivar) {
- [self registerInstrumentorForClass:[ivar class]];
- }];
- }
- @end
|