-
Notifications
You must be signed in to change notification settings - Fork 24.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement NetworkRequestDelegate on iOS
Summary: Implement `jsinspector_modern:: NetworkRequestDelegate` for iOS (bridge and bridgeless) to satisfy CDP `Network.loadNetworkResource` (etc) requests. Changelog: [iOS][Added] Debugger: Implement CDP methods for loading network resources through the debug target. Differential Revision: D54496969
- Loading branch information
1 parent
0ddb8a0
commit 7fcbc8e
Showing
4 changed files
with
174 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
packages/react-native/React/DevSupport/RCTInspectorNetworkHelper.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#import <jsinspector-modern/ReactCdp.h> | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
typedef std::shared_ptr<facebook::react::jsinspector_modern::NetworkRequestListener> RCTInspectorNetworkListener; | ||
|
||
/** | ||
* A helper class that wraps around NSURLSession to make network requests. | ||
*/ | ||
@interface RCTInspectorNetworkHelper : NSObject | ||
- (instancetype)init; | ||
- (void)networkRequestWithUrl:(const std::string &)url listener:(RCTInspectorNetworkListener)listener; | ||
@end |
134 changes: 134 additions & 0 deletions
134
packages/react-native/React/DevSupport/RCTInspectorNetworkHelper.mm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
#import "RCTInspectorNetworkHelper.h" | ||
|
||
// Wraps RCTInspectorNetworkListener (a C++ shared_ptr) in an NSObject, | ||
// maintaining a ref while making it id-compatible for an NSDictionary. | ||
@interface RCTInspectorNetworkListenerWrapper : NSObject | ||
@property (nonatomic, readonly) RCTInspectorNetworkListener listener; | ||
- (instancetype)initWithListener:(RCTInspectorNetworkListener)listener; | ||
@end | ||
|
||
@interface RCTInspectorNetworkHelper () <NSURLSessionDataDelegate> | ||
@property (nonatomic, strong) NSURLSession *session; | ||
@property (nonatomic, strong) | ||
NSMutableDictionary<NSNumber *, RCTInspectorNetworkListenerWrapper *> *listenerWrappersByTaskId; | ||
@end | ||
|
||
@implementation RCTInspectorNetworkHelper | ||
|
||
- (instancetype)init | ||
{ | ||
self = [super init]; | ||
if (self) { | ||
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; | ||
self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; | ||
self.listenerWrappersByTaskId = [NSMutableDictionary new]; | ||
} | ||
return self; | ||
} | ||
|
||
- (void)networkRequestWithUrl:(const std::string &)rawUrl listener:(RCTInspectorNetworkListener)listener | ||
{ | ||
NSString *urlString = [NSString stringWithUTF8String:rawUrl.c_str()]; | ||
NSURL *url = [NSURL URLWithString:urlString]; | ||
if (url == nil) { | ||
listener->onError([NSString stringWithFormat:@"Not a valid URL: %@", urlString].UTF8String); | ||
return; | ||
} | ||
|
||
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url]; | ||
[urlRequest setHTTPMethod:@"GET"]; | ||
NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:urlRequest]; | ||
__weak NSURLSessionDataTask *weakDataTask = dataTask; | ||
listener->setCancelFunction([weakDataTask]() { [weakDataTask cancel]; }); | ||
// Store the listener using the task identifier as the key | ||
RCTInspectorNetworkListenerWrapper *listenerWrapper = | ||
[[RCTInspectorNetworkListenerWrapper alloc] initWithListener:listener]; | ||
self.listenerWrappersByTaskId[@(dataTask.taskIdentifier)] = listenerWrapper; | ||
[dataTask resume]; | ||
} | ||
|
||
- (RCTInspectorNetworkListener)listenerForTask:(NSNumber *)taskIdentifier | ||
{ | ||
auto *listenerWrapper = self.listenerWrappersByTaskId[taskIdentifier]; | ||
return listenerWrapper ? listenerWrapper.listener : nil; | ||
} | ||
|
||
#pragma mark - NSURLSessionDataDelegate | ||
|
||
- (void)URLSession:(NSURLSession *)session | ||
dataTask:(NSURLSessionDataTask *)dataTask | ||
didReceiveResponse:(NSURLResponse *)response | ||
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler | ||
{ | ||
RCTInspectorNetworkListener listener = [self listenerForTask:@(dataTask.taskIdentifier)]; | ||
if (!listener) { | ||
[dataTask cancel]; | ||
return; | ||
} | ||
if ([response isKindOfClass:[NSHTTPURLResponse class]]) { | ||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; | ||
std::map<std::string, std::string> headersMap; | ||
for (NSString *key in httpResponse.allHeaderFields) { | ||
headersMap[[key UTF8String]] = [[httpResponse.allHeaderFields objectForKey:key] UTF8String]; | ||
} | ||
completionHandler(NSURLSessionResponseAllow); | ||
listener->onHeaders(httpResponse.statusCode, headersMap); | ||
} else { | ||
listener->onError("Unsupported response type"); | ||
completionHandler(NSURLSessionResponseCancel); | ||
} | ||
} | ||
|
||
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data | ||
{ | ||
RCTInspectorNetworkListener listener = [self listenerForTask:@(dataTask.taskIdentifier)]; | ||
if (!listener) { | ||
[dataTask cancel]; | ||
return; | ||
} | ||
if (data) { | ||
listener->onData(std::string_view(static_cast<const char *>(data.bytes), data.length)); | ||
} | ||
} | ||
|
||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error | ||
{ | ||
RCTInspectorNetworkListener listener = [self listenerForTask:@(task.taskIdentifier)]; | ||
if (!listener) { | ||
return; | ||
} | ||
if (error != nil) { | ||
listener->onError(error.localizedDescription.UTF8String); | ||
} else { | ||
listener->onEnd(); | ||
} | ||
[self.listenerWrappersByTaskId removeObjectForKey:@(task.taskIdentifier)]; | ||
} | ||
|
||
@end | ||
|
||
@implementation RCTInspectorNetworkListenerWrapper { | ||
RCTInspectorNetworkListener _listener; | ||
} | ||
|
||
- (instancetype)initWithListener:(RCTInspectorNetworkListener)listener | ||
{ | ||
if (self = [super init]) { | ||
_listener = listener; | ||
} | ||
return self; | ||
} | ||
|
||
- (RCTInspectorNetworkListener)listener | ||
{ | ||
return _listener; | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters