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..0717537f8424 --- /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_SERIAL); + } + return self; +} + +- (void)addRequestHeader:(NSString *)name value:(NSString *)value +{ + dispatch_sync(_queue, ^{ + self->_headers[name] = value; + }); +} + +- (void)removeRequestHeader:(NSString *)name +{ + dispatch_sync(_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]; + [headers enumerateKeysAndObjectsUsingBlock:^(NSString *headerName, NSString *headerValue, BOOL *stop) { + [request setValue:headerValue forHTTPHeaderField:headerName]; + }]; +} + +@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];