From 75247a52502b525556f835acf9186891b16b804f Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 17 Feb 2026 10:08:56 -0800 Subject: [PATCH 1/7] Add RCTDevSupportHttpHeaders singleton Summary: Add a thread-safe singleton that holds custom HTTP headers to be applied to all iOS devsupport network requests. This mirrors the Android `DevSupportHttpClient` from D93481539. Uses a GCD concurrent queue with barrier writes for reader-writer synchronization. Differential Revision: D93490954 --- .../React/Base/RCTDevSupportHttpHeaders.h | 24 +++++++ .../React/Base/RCTDevSupportHttpHeaders.m | 65 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 packages/react-native/React/Base/RCTDevSupportHttpHeaders.h create mode 100644 packages/react-native/React/Base/RCTDevSupportHttpHeaders.m 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 From 4e7f04262ee315ca597a6b165bb09b1369cbf330 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 17 Feb 2026 10:08:56 -0800 Subject: [PATCH 2/7] Apply custom headers in RCTMultipartDataTask Summary: Inject custom devsupport headers into bundle download requests. This ensures that multipart bundle fetches include any headers registered via `RCTDevSupportHttpHeaders`. Differential Revision: D93490951 --- packages/react-native/React/Base/RCTMultipartDataTask.m | 3 +++ 1 file changed, 3 insertions(+) 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]; From cc61e5f4e798d7a5a48759192dc16c5ba85beb2b Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 17 Feb 2026 10:08:56 -0800 Subject: [PATCH 3/7] Apply custom headers in RCTBundleURLProvider Summary: Inject custom devsupport headers into the packager status check request. Changes NSURLRequest to NSMutableURLRequest to allow header mutation before the request is sent. Differential Revision: D93490952 --- packages/react-native/React/Base/RCTBundleURLProvider.mm | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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; From d9a7608d20148aebd795210ef67ba852c24fb1fa Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 17 Feb 2026 10:08:56 -0800 Subject: [PATCH 4/7] Apply custom headers in RCTInspectorDevServerHelper Summary: Inject custom devsupport headers into the open-debugger POST request. This ensures the debugger launch request includes any registered custom headers. Differential Revision: D93490950 --- .../React/DevSupport/RCTInspectorDevServerHelper.mm | 2 ++ 1 file changed, 2 insertions(+) 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 From 9c8bd4938f31b1ceecabf7621163188b95b52dc9 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 17 Feb 2026 10:08:56 -0800 Subject: [PATCH 5/7] Apply custom headers in RCTInspectorNetworkHelper Summary: Inject custom devsupport headers into inspector resource loading requests. This ensures that inspector network fetches include any registered custom headers. Differential Revision: D93490953 --- .../react-native/React/DevSupport/RCTInspectorNetworkHelper.mm | 2 ++ 1 file changed, 2 insertions(+) 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; From 13e5eeac86250f578085df086ff02ebab9fc2652 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 17 Feb 2026 10:08:56 -0800 Subject: [PATCH 6/7] Apply custom headers in RCTReconnectingWebSocket Summary: Inject custom devsupport headers into the HMR WebSocket connection. Changes from `initWithURL:` to `initWithURLRequest:` so headers can be set on the HTTP upgrade handshake. Differential Revision: D93490948 --- .../Libraries/WebSocket/RCTReconnectingWebSocket.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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]; From 15b8192676058a5f94bffa89ee32aec1a3c09f98 Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Tue, 17 Feb 2026 10:08:56 -0800 Subject: [PATCH 7/7] Apply custom headers in RCTCxxInspectorWebSocketAdapter Summary: Inject custom devsupport headers into the inspector CDP WebSocket connection. Changes from `initWithURL:` to `initWithURLRequest:` so headers can be set on the HTTP upgrade handshake. Differential Revision: D93490949 --- .../React/Inspector/RCTCxxInspectorWebSocketAdapter.mm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/react-native/React/Inspector/RCTCxxInspectorWebSocketAdapter.mm b/packages/react-native/React/Inspector/RCTCxxInspectorWebSocketAdapter.mm index 78e8aa3787c8..db72380fb078 100644 --- a/packages/react-native/React/Inspector/RCTCxxInspectorWebSocketAdapter.mm +++ b/packages/react-native/React/Inspector/RCTCxxInspectorWebSocketAdapter.mm @@ -10,6 +10,7 @@ #if RCT_DEV || RCT_REMOTE_PROFILE #import +#import #import #import #import @@ -40,7 +41,10 @@ - (instancetype)initWithURL:(const std::string &)url delegate:(std::weak_ptr