mirror of
https://github.com/status-im/react-native.git
synced 2025-02-23 06:38:13 +00:00
Summary: Fixes https://github.com/facebook/react-native/issues/19376 On iOS, the `HTTPShouldHandleCookies` boolean has no effect when custom cookies are set (see https://developer.apple.com/documentation/foundation/nsmutableurlrequest/1415485-httpshouldhandlecookies?preferredLanguage=occ). Setting custom cookies prevents the cookies of a redirect response from being re-used in the subsequent request. This is why issue https://github.com/facebook/react-native/issues/19376 is opened. The fix is to intercept the redirect request, and to manually set the cookies. This effectively makes the Android and iOS behaviours converge. Changelog: ---------- [iOS] [Fixed] - Fix cookies not being sent on iOS after redirect Pull Request resolved: https://github.com/facebook/react-native/pull/22178 Differential Revision: D13191961 Pulled By: shergin fbshipit-source-id: 4445a2499034a9846c6d7c37c1f1b72c9fd30129
164 lines
4.9 KiB
Plaintext
164 lines
4.9 KiB
Plaintext
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#import "RCTHTTPRequestHandler.h"
|
|
|
|
#import <mutex>
|
|
|
|
#import "RCTNetworking.h"
|
|
|
|
@interface RCTHTTPRequestHandler () <NSURLSessionDataDelegate>
|
|
|
|
@end
|
|
|
|
@implementation RCTHTTPRequestHandler
|
|
{
|
|
NSMapTable *_delegates;
|
|
NSURLSession *_session;
|
|
std::mutex _mutex;
|
|
}
|
|
|
|
@synthesize bridge = _bridge;
|
|
|
|
RCT_EXPORT_MODULE()
|
|
|
|
- (void)invalidate
|
|
{
|
|
[_session invalidateAndCancel];
|
|
_session = nil;
|
|
}
|
|
|
|
- (BOOL)isValid
|
|
{
|
|
// if session == nil and delegates != nil, we've been invalidated
|
|
return _session || !_delegates;
|
|
}
|
|
|
|
#pragma mark - NSURLRequestHandler
|
|
|
|
- (BOOL)canHandleRequest:(NSURLRequest *)request
|
|
{
|
|
static NSSet<NSString *> *schemes = nil;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
// technically, RCTHTTPRequestHandler can handle file:// as well,
|
|
// but it's less efficient than using RCTFileRequestHandler
|
|
schemes = [[NSSet alloc] initWithObjects:@"http", @"https", nil];
|
|
});
|
|
return [schemes containsObject:request.URL.scheme.lowercaseString];
|
|
}
|
|
|
|
- (NSURLSessionDataTask *)sendRequest:(NSURLRequest *)request
|
|
withDelegate:(id<RCTURLRequestDelegate>)delegate
|
|
{
|
|
// Lazy setup
|
|
if (!_session && [self isValid]) {
|
|
NSOperationQueue *callbackQueue = [NSOperationQueue new];
|
|
callbackQueue.maxConcurrentOperationCount = 1;
|
|
callbackQueue.underlyingQueue = [[_bridge networking] methodQueue];
|
|
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
|
[configuration setHTTPShouldSetCookies:YES];
|
|
[configuration setHTTPCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
|
|
[configuration setHTTPCookieStorage:[NSHTTPCookieStorage sharedHTTPCookieStorage]];
|
|
_session = [NSURLSession sessionWithConfiguration:configuration
|
|
delegate:self
|
|
delegateQueue:callbackQueue];
|
|
|
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
_delegates = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
|
|
valueOptions:NSPointerFunctionsStrongMemory
|
|
capacity:0];
|
|
}
|
|
|
|
NSURLSessionDataTask *task = [_session dataTaskWithRequest:request];
|
|
{
|
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
[_delegates setObject:delegate forKey:task];
|
|
}
|
|
[task resume];
|
|
return task;
|
|
}
|
|
|
|
- (void)cancelRequest:(NSURLSessionDataTask *)task
|
|
{
|
|
{
|
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
[_delegates removeObjectForKey:task];
|
|
}
|
|
[task cancel];
|
|
}
|
|
|
|
#pragma mark - NSURLSession delegate
|
|
|
|
- (void)URLSession:(NSURLSession *)session
|
|
task:(NSURLSessionTask *)task
|
|
didSendBodyData:(int64_t)bytesSent
|
|
totalBytesSent:(int64_t)totalBytesSent
|
|
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
|
|
{
|
|
id<RCTURLRequestDelegate> delegate;
|
|
{
|
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
delegate = [_delegates objectForKey:task];
|
|
}
|
|
[delegate URLRequest:task didSendDataWithProgress:totalBytesSent];
|
|
}
|
|
|
|
- (void)URLSession:(NSURLSession *)session
|
|
task:(NSURLSessionTask *)task
|
|
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
|
|
newRequest:(NSURLRequest *)request
|
|
completionHandler:(void (^)(NSURLRequest *))completionHandler
|
|
{
|
|
// Reset the cookies on redirect.
|
|
// This is necessary because we're not letting iOS handle cookies by itself
|
|
NSMutableURLRequest *nextRequest = [request mutableCopy];
|
|
|
|
NSArray<NSHTTPCookie *> *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:request.URL];
|
|
nextRequest.allHTTPHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
|
|
completionHandler(nextRequest);
|
|
}
|
|
|
|
- (void)URLSession:(NSURLSession *)session
|
|
dataTask:(NSURLSessionDataTask *)task
|
|
didReceiveResponse:(NSURLResponse *)response
|
|
completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
|
|
{
|
|
id<RCTURLRequestDelegate> delegate;
|
|
{
|
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
delegate = [_delegates objectForKey:task];
|
|
}
|
|
[delegate URLRequest:task didReceiveResponse:response];
|
|
completionHandler(NSURLSessionResponseAllow);
|
|
}
|
|
|
|
- (void)URLSession:(NSURLSession *)session
|
|
dataTask:(NSURLSessionDataTask *)task
|
|
didReceiveData:(NSData *)data
|
|
{
|
|
id<RCTURLRequestDelegate> delegate;
|
|
{
|
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
delegate = [_delegates objectForKey:task];
|
|
}
|
|
[delegate URLRequest:task didReceiveData:data];
|
|
}
|
|
|
|
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
|
|
{
|
|
id<RCTURLRequestDelegate> delegate;
|
|
{
|
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
delegate = [_delegates objectForKey:task];
|
|
[_delegates removeObjectForKey:task];
|
|
}
|
|
[delegate URLRequest:task didCompleteWithError:error];
|
|
}
|
|
|
|
@end
|