diff --git a/packages/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m b/packages/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m index 1bd4de74a724..ce64e0af0aca 100644 --- a/packages/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m +++ b/packages/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m @@ -9,6 +9,7 @@ #import #import +#import #import @@ -46,7 +47,9 @@ - (void)start { [self stop]; _stopped = NO; - _socket = [[SRWebSocket alloc] initWithURL:_url]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_url]; + [[RCTDevSupportHttpHeaders sharedInstance] applyHeadersToRequest:request]; + _socket = [[SRWebSocket alloc] initWithURLRequest:request]; _socket.delegate = self; [_socket setDelegateDispatchQueue:_delegateDispatchQueue]; [_socket open]; diff --git a/packages/react-native/React/Base/RCTBundleURLProvider.mm b/packages/react-native/React/Base/RCTBundleURLProvider.mm index e99b2dcc1515..b599cb95eca7 100644 --- a/packages/react-native/React/Base/RCTBundleURLProvider.mm +++ b/packages/react-native/React/Base/RCTBundleURLProvider.mm @@ -10,6 +10,7 @@ #import "RCTConstants.h" #import "RCTConvert.h" #import "RCTDefines.h" +#import "RCTDevSupportHttpHeaders.h" #import "RCTLog.h" #import @@ -93,9 +94,10 @@ + (BOOL)isPackagerRunning:(NSString *)hostPort scheme:(NSString *)scheme NSURL *url = [serverRootWithHostPort(hostPort, scheme) URLByAppendingPathComponent:@"status"]; NSURLSession *session = [NSURLSession sharedSession]; - NSURLRequest *request = [NSURLRequest requestWithURL:url - cachePolicy:NSURLRequestUseProtocolCachePolicy - timeoutInterval:10]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url + cachePolicy:NSURLRequestUseProtocolCachePolicy + timeoutInterval:10]; + [[RCTDevSupportHttpHeaders sharedInstance] applyHeadersToRequest:request]; __block NSURLResponse *response; __block NSData *data; diff --git a/packages/react-native/React/Base/RCTDevSupportHttpHeaders.h b/packages/react-native/React/Base/RCTDevSupportHttpHeaders.h new file mode 100644 index 000000000000..e73cdd3c4b88 --- /dev/null +++ b/packages/react-native/React/Base/RCTDevSupportHttpHeaders.h @@ -0,0 +1,24 @@ +/* + * 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 + +/** + * Thread-safe singleton that holds custom HTTP headers to be applied + * to all devsupport network requests (bundle fetches, packager status + * checks, inspector and HMR WebSocket connections). + */ +@interface RCTDevSupportHttpHeaders : NSObject + ++ (instancetype)sharedInstance; + +- (void)addRequestHeader:(NSString *)name value:(NSString *)value; +- (void)removeRequestHeader:(NSString *)name; +- (NSDictionary *)allHeaders; +- (void)applyHeadersToRequest:(NSMutableURLRequest *)request; + +@end diff --git a/packages/react-native/React/Base/RCTDevSupportHttpHeaders.m b/packages/react-native/React/Base/RCTDevSupportHttpHeaders.m new file mode 100644 index 000000000000..3476e8d0e55d --- /dev/null +++ b/packages/react-native/React/Base/RCTDevSupportHttpHeaders.m @@ -0,0 +1,65 @@ +/* + * 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 "RCTDevSupportHttpHeaders.h" + +@implementation RCTDevSupportHttpHeaders { + NSMutableDictionary *_headers; + dispatch_queue_t _queue; +} + ++ (instancetype)sharedInstance +{ + static RCTDevSupportHttpHeaders *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[RCTDevSupportHttpHeaders alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init +{ + if (self = [super init]) { + _headers = [NSMutableDictionary new]; + _queue = dispatch_queue_create("com.facebook.react.RCTDevSupportHttpHeaders", DISPATCH_QUEUE_CONCURRENT); + } + return self; +} + +- (void)addRequestHeader:(NSString *)name value:(NSString *)value +{ + dispatch_barrier_async(_queue, ^{ + self->_headers[name] = value; + }); +} + +- (void)removeRequestHeader:(NSString *)name +{ + dispatch_barrier_async(_queue, ^{ + [self->_headers removeObjectForKey:name]; + }); +} + +- (NSDictionary *)allHeaders +{ + __block NSDictionary *snapshot; + dispatch_sync(_queue, ^{ + snapshot = [self->_headers copy]; + }); + return snapshot; +} + +- (void)applyHeadersToRequest:(NSMutableURLRequest *)request +{ + NSDictionary *headers = [self allHeaders]; + for (NSString *name in headers) { + [request setValue:headers[name] forHTTPHeaderField:name]; + } +} + +@end diff --git a/packages/react-native/React/Base/RCTMultipartDataTask.m b/packages/react-native/React/Base/RCTMultipartDataTask.m index 3ac07683eb93..9f5ff5995535 100644 --- a/packages/react-native/React/Base/RCTMultipartDataTask.m +++ b/packages/react-native/React/Base/RCTMultipartDataTask.m @@ -7,6 +7,8 @@ #import "RCTMultipartDataTask.h" +#import "RCTDevSupportHttpHeaders.h" + @interface RCTMultipartDataTask () @end @@ -40,6 +42,7 @@ - (void)startTask delegateQueue:nil]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_url]; [request addValue:@"multipart/mixed" forHTTPHeaderField:@"Accept"]; + [[RCTDevSupportHttpHeaders sharedInstance] applyHeadersToRequest:request]; NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request]; [dataTask resume]; [session finishTasksAndInvalidate]; diff --git a/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.mm b/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.mm index 9230dd3b3322..36e18415eed3 100644 --- a/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.mm +++ b/packages/react-native/React/DevSupport/RCTInspectorDevServerHelper.mm @@ -14,6 +14,7 @@ #import #import +#import #import #import @@ -154,6 +155,7 @@ + (void)openDebugger:(NSURL *)bundleURL withErrorMessage:(NSString *)errorMessag escapedInspectorDeviceId]]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [request setHTTPMethod:@"POST"]; + [[RCTDevSupportHttpHeaders sharedInstance] applyHeadersToRequest:request]; [[[NSURLSession sharedSession] dataTaskWithRequest:request diff --git a/packages/react-native/React/DevSupport/RCTInspectorNetworkHelper.mm b/packages/react-native/React/DevSupport/RCTInspectorNetworkHelper.mm index 8e775d3185df..f0fa55333445 100644 --- a/packages/react-native/React/DevSupport/RCTInspectorNetworkHelper.mm +++ b/packages/react-native/React/DevSupport/RCTInspectorNetworkHelper.mm @@ -6,6 +6,7 @@ */ #import "RCTInspectorNetworkHelper.h" +#import #import using ListenerBlock = void (^)(RCTInspectorNetworkListener *); @@ -47,6 +48,7 @@ - (void)loadNetworkResourceWithParams:(const RCTInspectorLoadNetworkResourceRequ NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url]; [urlRequest setHTTPMethod:@"GET"]; + [[RCTDevSupportHttpHeaders sharedInstance] applyHeadersToRequest:urlRequest]; NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:urlRequest]; __weak NSURLSessionDataTask *weakDataTask = dataTask;