Source/TNLRequestConfiguration.m (664 lines of code) (raw):
//
// TNLRequestConfiguration.m
// TwitterNetworkLayer
//
// Created on 7/15/14.
// Copyright © 2020 Twitter. All rights reserved.
//
#include <objc/message.h>
#import "NSHTTPCookieStorage+TNLAdditions.h"
#import "NSURLCache+TNLAdditions.h"
#import "NSURLCredentialStorage+TNLAdditions.h"
#import "NSURLSessionConfiguration+TNLAdditions.h"
#import "TNL_Project.h"
#import "TNLParameterCollection.h"
#import "TNLPseudoURLProtocol.h"
#import "TNLRequestConfiguration_Project.h"
#import "TNLURLSessionManager.h"
NS_ASSUME_NONNULL_BEGIN
static const char kAssociatedConfigKey[] = "tnl.associated.config";
typedef struct {
const NSTimeInterval idleTimeout;
const NSTimeInterval attemptTimeout;
const NSTimeInterval operationTimeout;
} TNLRequestAnatomyTimeouts;
static const TNLRequestAnatomyTimeouts kAnatomyTimeouts[] = {
// TNLRequestAnatomySmallRequestSmallResponse
{ .idleTimeout = 30, .attemptTimeout = 30, .operationTimeout = 90 },
// TNLRequestAnatomySmallRequestLargeResponse (default)
{ .idleTimeout = 30, .attemptTimeout = 60, .operationTimeout = 180 },
// TNLRequestAnatomyLargeRequestSmallResponse
{ .idleTimeout = 30, .attemptTimeout = 60, .operationTimeout = 180 },
// TNLRequestAnatomyLargeRequestLargeResponse
{ .idleTimeout = 30, .attemptTimeout = 120, .operationTimeout = 360 },
// TNLRequestAnatomyVeryLargeRequestSmallResponse
{ .idleTimeout = 30, .attemptTimeout = 240, .operationTimeout = 480 },
// TNLRequestAnatomySmallRequestVeryLargeResponse
{ .idleTimeout = 30, .attemptTimeout = 180, .operationTimeout = 480 },
// TNLRequestAnatomySmallRequestStreamingResponse
{ .idleTimeout = 30, .attemptTimeout = NSTimeIntervalSince1970, .operationTimeout = NSTimeIntervalSince1970 },
};
static const NSInteger kMaxAnatomyTimeouts = TNLRequestAnatomySmallRequestStreamingResponse + 1;
TNLStaticAssert((sizeof(kAnatomyTimeouts) / sizeof(kAnatomyTimeouts[0])) == kMaxAnatomyTimeouts, ANATOMY_TIMEOUT_COUNT_MISSMATCH);
#define kConfigurationIdleTimeoutDefault (kAnatomyTimeouts[TNLRequestAnatomyDefault].idleTimeout)
#define kConfigurationAttemptTimeoutDefault (kAnatomyTimeouts[TNLRequestAnatomyDefault].attemptTimeout) // Apple's default is 7 days (biasing towards background sessions). We'll bias towards foreground sessions.
#define kConfigurationOperationTimeoutDefault (kAnatomyTimeouts[TNLRequestAnatomyDefault].operationTimeout)
static const NSTimeInterval kConfigurationDeferrableIntervalDefault = 0.0;
TNLStaticAssert(TNLResponseHashComputeAlgorithmNone == 0, ALGORITHM_NONE_WRONG_VALUE);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
TNLStaticAssert(TNLResponseHashComputeAlgorithmMD2 == 1835294514, ALGORITHM_MD2_WRONG_VALUE);
TNLStaticAssert(TNLResponseHashComputeAlgorithmMD4 == 1835294516, ALGORITHM_MD4_WRONG_VALUE);
TNLStaticAssert(TNLResponseHashComputeAlgorithmMD5 == 1835294517, ALGORITHM_MD5_WRONG_VALUE);
#pragma clang diagnostic pop
TNLStaticAssert(TNLResponseHashComputeAlgorithmSHA1 == 1936220465, ALGORITHM_SHA1_WRONG_VALUE);
TNLStaticAssert(TNLResponseHashComputeAlgorithmSHA256 == 1932670262, ALGORITHM_SHA256_WRONG_VALUE);
TNLStaticAssert(TNLResponseHashComputeAlgorithmSHA512 == 1932865842, ALGORITHM_SHA512_WRONG_VALUE);
@interface TNLRequestConfiguration ()
- (instancetype)initWithConfiguration:(nullable TNLRequestConfiguration *)config;
- (instancetype)initWithIdleTimeout:(NSTimeInterval)idleTimeout
attemptTimeout:(NSTimeInterval)attemptTimeout
operationTimeout:(NSTimeInterval)operationTimeout;
@end
@implementation TNLRequestConfiguration
#pragma mark @synthesize
@synthesize retryPolicyProvider = _retryPolicyProvider;
@synthesize contentEncoder = _contentEncoder;
@synthesize additionalContentDecoders = _additionalContentDecoders;
@synthesize URLCredentialStorage = _URLCredentialStorage;
@synthesize URLCache = _URLCache;
@synthesize sharedContainerIdentifier = _sharedContainerIdentifier;
@synthesize cookieStorage = _cookieStorage;
#pragma mark properties
- (TNLRequestExecutionMode)executionMode
{
return _ivars.executionMode;
}
- (TNLRequestRedirectPolicy)redirectPolicy
{
return _ivars.redirectPolicy;
}
- (TNLResponseDataConsumptionMode)responseDataConsumptionMode
{
return _ivars.responseDataConsumptionMode;
}
- (TNLRequestProtocolOptions)protocolOptions
{
return _ivars.protocolOptions;
}
- (TNLRequestConnectivityOptions)connectivityOptions
{
return _ivars.connectivityOptions;
}
- (BOOL)contributeToExecutingNetworkConnectionsCount
{
return _ivars.contributeToExecutingNetworkConnectionsCount;
}
- (BOOL)skipHostSanitization
{
return _ivars.skipHostSanitization;
}
- (TNLResponseHashComputeAlgorithm)responseComputeHashAlgorithm
{
return _ivars.responseComputeHashAlgorithm;
}
- (NSTimeInterval)idleTimeout
{
return _ivars.idleTimeout;
}
- (NSTimeInterval)attemptTimeout
{
return _ivars.attemptTimeout;
}
- (NSTimeInterval)operationTimeout
{
return _ivars.operationTimeout;
}
- (NSTimeInterval)deferrableInterval
{
return _ivars.deferrableInterval;
}
- (NSURLRequestCachePolicy)cachePolicy
{
return _ivars.cachePolicy;
}
- (NSURLRequestNetworkServiceType)networkServiceType
{
return _ivars.networkServiceType;
}
- (NSHTTPCookieAcceptPolicy)cookieAcceptPolicy
{
return _ivars.cookieAcceptPolicy;
}
- (BOOL)shouldSetCookies
{
return _ivars.shouldSetCookies;
}
- (BOOL)allowsCellularAccess
{
return _ivars.allowsCellularAccess;
}
- (BOOL)isDiscretionary
{
return _ivars.discretionary;
}
- (BOOL)shouldLaunchAppForBackgroundEvents
{
return _ivars.shouldLaunchAppForBackgroundEvents;
}
- (NSURLSessionMultipathServiceType)multipathServiceType
{
#if TARGET_OS_IOS
if (tnl_available_ios_11) {
return _ivars.multipathServiceType;
}
#endif
return 0;
}
- (BOOL)shouldUseExtendedBackgroundIdleMode
{
return _ivars.shouldUseExtendedBackgroundIdleMode;
}
#pragma mark Constructors
+ (instancetype)defaultConfiguration
{
return [[[self class] alloc] init];
}
+ (instancetype)configurationWithExpectedAnatomy:(TNLRequestAnatomy)anatomy
{
if (anatomy >= kMaxAnatomyTimeouts) {
anatomy = TNLRequestAnatomyDefault;
TNLLogWarning(@"Invalid TNLRequestAnatomy provided! Coersing to default.");
}
const TNLRequestAnatomyTimeouts timeouts = kAnatomyTimeouts[anatomy];
return [[[self class] alloc] initWithIdleTimeout:timeouts.idleTimeout
attemptTimeout:timeouts.attemptTimeout
operationTimeout:timeouts.operationTimeout];
}
#pragma mark init
- (instancetype)initWithConfiguration:(nullable TNLRequestConfiguration *)config
{
if (!config) {
self = [self init];
} else if ((self = [super init])) {
_retryPolicyProvider = config->_retryPolicyProvider;
_contentEncoder = config->_contentEncoder;
_additionalContentDecoders = [config->_additionalContentDecoders copy];
_URLCredentialStorage = config->_URLCredentialStorage;
_URLCache = config->_URLCache;
_cookieStorage = config->_cookieStorage;
_sharedContainerIdentifier = [config->_sharedContainerIdentifier copy];
memcpy(&_ivars, &(config->_ivars), sizeof(_ivars));
if (_ivars.connectivityOptions != TNLRequestConnectivityOptionsNone) {
if (![NSURLSessionConfiguration tnl_URLSessionCanUseWaitsForConnectivity]) {
_ivars.connectivityOptions = TNLRequestConnectivityOptionsNone;
TNL_LOG_WAITS_FOR_CONNECTIVITY_WARNING();
}
}
}
return self;
}
- (instancetype)init
{
static NSURLSessionConfiguration *sTemplateConfig;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sTemplateConfig = [NSURLSessionConfiguration tnl_defaultSessionConfigurationWithNilPersistence];
});
TNLAssert(sTemplateConfig != nil);
TNLAssert(!sTemplateConfig.URLCache);
TNLAssert(!sTemplateConfig.URLCredentialStorage);
TNLAssert(!sTemplateConfig.HTTPCookieStorage);
return [self initWithSessionConfiguration:sTemplateConfig];
}
- (instancetype)initWithIdleTimeout:(NSTimeInterval)idleTimeout
attemptTimeout:(NSTimeInterval)attemptTimeout
operationTimeout:(NSTimeInterval)operationTimeout
{
if (self = [self init]) {
_ivars.idleTimeout = idleTimeout;
_ivars.attemptTimeout = attemptTimeout;
_ivars.operationTimeout = operationTimeout;
}
return self;
}
#pragma mark NSMutableCopying
- (id)copyWithZone:(nullable NSZone *)zone
{
return self;
}
- (id)mutableCopyWithZone:(nullable NSZone *)zone
{
TNLMutableRequestConfiguration *config = [[TNLMutableRequestConfiguration allocWithZone:zone] initWithConfiguration:self];
return config;
}
#pragma mark Description
- (NSString *)description
{
NSMutableDictionary *d = [NSMutableDictionary dictionary];
#define D_SET(prop) \
d[@"" #prop] = @(self.prop);
D_SET(executionMode);
D_SET(redirectPolicy);
D_SET(responseDataConsumptionMode);
D_SET(protocolOptions);
D_SET(connectivityOptions);
D_SET(contributeToExecutingNetworkConnectionsCount);
D_SET(skipHostSanitization);
D_SET(responseComputeHashAlgorithm);
D_SET(attemptTimeout);
D_SET(idleTimeout);
D_SET(operationTimeout);
D_SET(deferrableInterval);
D_SET(cachePolicy);
D_SET(networkServiceType);
D_SET(cookieAcceptPolicy);
D_SET(allowsCellularAccess);
D_SET(isDiscretionary);
D_SET(shouldLaunchAppForBackgroundEvents);
D_SET(shouldSetCookies);
D_SET(shouldUseExtendedBackgroundIdleMode);
#if TARGET_OS_IOS
if (tnl_available_ios_11) {
D_SET(multipathServiceType);
}
#endif
#undef D_SET
#define D_SET(prop) \
if (self.prop) { \
d[@"" #prop] = self.prop; \
}
D_SET(retryPolicyProvider);
D_SET(contentEncoder);
D_SET(additionalContentDecoders);
D_SET(sharedContainerIdentifier);
D_SET(URLCredentialStorage);
D_SET(URLCache);
D_SET(cookieStorage);
#undef D_SET
return [NSString stringWithFormat:@"<%@ %p: %@>", NSStringFromClass([self class]), self, d];
}
#pragma mark Equivilence
- (NSUInteger)hash
{
TNLMutableParameterCollection *params = TNLMutableParametersFromRequestConfiguration(self, nil, nil, nil);
TNLMutableParametersStripURLCacheAndURLCredentialStorageAndCookieStorage(params);
return params.hash +
(NSUInteger)(self.responseComputeHashAlgorithm) +
(NSUInteger)(self.contributeToExecutingNetworkConnectionsCount * 7) +
(NSUInteger)(self.skipHostSanitization * 11) +
(NSUInteger)(self.executionMode * 17);
}
- (BOOL)isEqual:(id)object
{
if ([super isEqual:object]) {
return YES;
}
if (![object isKindOfClass:[TNLRequestConfiguration class]]) {
return NO;
}
TNLRequestConfiguration *other = object;
if (0 != memcmp(&_ivars, &(other->_ivars), sizeof(_ivars))) {
return NO;
}
if (self.retryPolicyProvider != other.retryPolicyProvider) {
return NO;
}
if (self.sharedContainerIdentifier != other.sharedContainerIdentifier && ![self.sharedContainerIdentifier isEqualToString:other.sharedContainerIdentifier]) {
return NO;
}
if (self.URLCredentialStorage != other.URLCredentialStorage) {
return NO;
}
if (self.URLCache != other.URLCache) {
return NO;
}
if (self.cookieStorage != other.cookieStorage) {
return NO;
}
return YES;
}
@end
#pragma mark - TNLMutableRequestConfiguration
@implementation TNLMutableRequestConfiguration
@dynamic contributeToExecutingNetworkConnectionsCount;
@dynamic skipHostSanitization;
@dynamic responseComputeHashAlgorithm;
@dynamic executionMode;
@dynamic redirectPolicy;
@dynamic responseDataConsumptionMode;
@dynamic protocolOptions;
@dynamic connectivityOptions;
@dynamic retryPolicyProvider;
@dynamic contentEncoder;
@dynamic additionalContentDecoders;
@dynamic idleTimeout;
@dynamic attemptTimeout;
@dynamic operationTimeout;
@dynamic deferrableInterval;
@dynamic cachePolicy;
@dynamic networkServiceType;
@dynamic cookieAcceptPolicy;
@dynamic shouldSetCookies;
@dynamic allowsCellularAccess;
@dynamic discretionary;
@dynamic sharedContainerIdentifier;
@dynamic shouldLaunchAppForBackgroundEvents;
@dynamic URLCredentialStorage;
@dynamic URLCache;
@dynamic cookieStorage;
@dynamic multipathServiceType;
@dynamic shouldUseExtendedBackgroundIdleMode;
- (id)copyWithZone:(nullable NSZone *)zone
{
TNLRequestConfiguration *config = [[TNLRequestConfiguration allocWithZone:zone] initWithConfiguration:self];
return config;
}
- (void)setExecutionMode:(TNLRequestExecutionMode)executionMode
{
_ivars.executionMode = executionMode;
}
- (void)setRedirectPolicy:(TNLRequestRedirectPolicy)redirectPolicy
{
_ivars.redirectPolicy = redirectPolicy;
}
- (void)setResponseDataConsumptionMode:(TNLResponseDataConsumptionMode)responseDataConsumptionMode
{
_ivars.responseDataConsumptionMode = responseDataConsumptionMode;
}
- (void)setProtocolOptions:(TNLRequestProtocolOptions)protocolOptions
{
_ivars.protocolOptions = protocolOptions;
}
- (void)setConnectivityOptions:(TNLRequestConnectivityOptions)connectivityOptions
{
if (![NSURLSessionConfiguration tnl_URLSessionCanUseWaitsForConnectivity]) {
TNL_LOG_WAITS_FOR_CONNECTIVITY_WARNING();
return;
}
_ivars.connectivityOptions = (connectivityOptions & 0xf);
}
- (void)setContributeToExecutingNetworkConnectionsCount:(BOOL)contributeToExecutingNetworkConnectionsCount
{
_ivars.contributeToExecutingNetworkConnectionsCount = (contributeToExecutingNetworkConnectionsCount != NO);
}
- (void)setSkipHostSanitization:(BOOL)skipHostSanitization
{
_ivars.skipHostSanitization = (skipHostSanitization != NO);
}
- (void)setResponseComputeHashAlgorithm:(TNLResponseHashComputeAlgorithm)responseComputeHashAlgorithm
{
_ivars.responseComputeHashAlgorithm = responseComputeHashAlgorithm;
}
- (void)setRetryPolicyProvider:(nullable id<TNLRequestRetryPolicyProvider>)retryPolicyProvider
PROP_RETAIN_ASSIGN_IMP(retryPolicyProvider);
- (void)setContentEncoder:(nullable id<TNLContentEncoder>)contentEncoder
PROP_RETAIN_ASSIGN_IMP(contentEncoder);
- (void)setAdditionalContentDecoders:(nullable NSArray<id<TNLContentDecoder>> *)additionalContentDecoders
PROP_COPY_IMP(additionalContentDecoders);
- (void)setIdleTimeout:(NSTimeInterval)idleTimeout
{
_ivars.idleTimeout = idleTimeout;
}
- (void)setAttemptTimeout:(NSTimeInterval)attemptTimeout
{
_ivars.attemptTimeout = attemptTimeout;
}
- (void)setOperationTimeout:(NSTimeInterval)operationTimeout
{
_ivars.operationTimeout = operationTimeout;
}
- (void)setDeferrableInterval:(NSTimeInterval)deferrableInterval
{
_ivars.deferrableInterval = deferrableInterval;
}
- (void)setCachePolicy:(NSURLRequestCachePolicy)cachePolicy
{
_ivars.cachePolicy = cachePolicy;
}
- (void)setNetworkServiceType:(NSURLRequestNetworkServiceType)networkServiceType
{
_ivars.networkServiceType = networkServiceType;
}
- (void)setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)cookieAcceptPolicy
{
_ivars.cookieAcceptPolicy = cookieAcceptPolicy;
}
- (void)setShouldSetCookies:(BOOL)shouldSetCookies
{
_ivars.shouldSetCookies = shouldSetCookies;
}
- (void)setAllowsCellularAccess:(BOOL)allowsCellularAccess
{
_ivars.allowsCellularAccess = (allowsCellularAccess != NO);
}
- (void)setDiscretionary:(BOOL)discretionary
{
_ivars.discretionary = (discretionary != NO);
}
- (void)setSharedContainerIdentifier:(nullable NSString *)sharedContainerIdentifier
{
PROP_COPY_IMP(sharedContainerIdentifier);
}
- (void)setShouldLaunchAppForBackgroundEvents:(BOOL)shouldLaunchAppForBackgroundEvents
{
_ivars.shouldLaunchAppForBackgroundEvents = (shouldLaunchAppForBackgroundEvents != NO);
}
- (void)setURLCredentialStorage:(nullable NSURLCredentialStorage *)URLCredentialStorage
PROP_RETAIN_ASSIGN_IMP(URLCredentialStorage);
- (void)setURLCache:(nullable NSURLCache *)URLCache
PROP_RETAIN_ASSIGN_IMP(URLCache);
- (void)setCookieStorage:(nullable NSHTTPCookieStorage *)cookieStorage
PROP_RETAIN_ASSIGN_IMP(cookieStorage);
- (void)setMultipathServiceType:(NSURLSessionMultipathServiceType)multipathServiceType
{
#if TARGET_OS_IOS
if (tnl_available_ios_11) {
_ivars.multipathServiceType = multipathServiceType;
}
#endif
}
- (void)setShouldUseExtendedBackgroundIdleMode:(BOOL)shouldUseExtendedBackgroundIdleMode
{
_ivars.shouldUseExtendedBackgroundIdleMode = (shouldUseExtendedBackgroundIdleMode != NO);
}
- (void)configureAsLowPriority
{
self.discretionary = YES;
self.deferrableInterval = TNLDeferrableIntervalForPriority(TNLPriorityLow);
self.networkServiceType = NSURLNetworkServiceTypeBackground;
}
@end
#pragma mark TNLRequestConfiguration
@implementation TNLRequestConfiguration (Project)
+ (nullable instancetype)parseConfigurationFromIdentifier:(nullable NSString *)identifier
{
if (!identifier) {
return nil;
}
NSURL *url = [NSURL URLWithString:identifier];
if (![url.scheme isEqualToString:TNLTwitterNetworkLayerURLScheme]) {
return nil;
}
if (url.host.length == 0) {
return nil;
}
NSArray *pathComponents = url.pathComponents;
if (pathComponents.count != 3) {
// 0 == '/' (root)
// 1 == TNLRequestOperationQueue identifier
// 2 == 'InApp' || 'Background'
return nil;
}
NSString *version = [pathComponents[1] stringByReplacingOccurrencesOfString:@"_" withString:@"."];
NSString *modeStr = pathComponents[2];
TNLRequestExecutionMode mode = TNLRequestExecutionModeInApp;
if ([modeStr isEqualToString:@"Background"]) {
mode = TNLRequestExecutionModeBackground;
}
TNLParameterCollection *params = url.tnl_queryCollection;
return [self configurationFromParameters:params
executionMode:mode
version:version];
}
+ (instancetype)configurationFromParameters:(nullable TNLParameterCollection *)params
executionMode:(TNLRequestExecutionMode)mode
version:(nullable NSString *)tnlVersion
{
TNLMutableRequestConfiguration *mConfig = [TNLMutableRequestConfiguration defaultConfiguration];
NSString *value;
#define PULL_VALUE(key, target, accessor, type) \
do { \
value = params[key]; \
if (value) { \
mConfig.target = ( type )[value accessor]; \
} \
} while (0)
PULL_VALUE(TNLRequestConfigurationPropertyKeyRedirectPolicy, redirectPolicy, integerValue, TNLRequestRedirectPolicy);
PULL_VALUE(TNLRequestConfigurationPropertyKeyResponseDataConsumptionMode, responseDataConsumptionMode, integerValue, TNLResponseDataConsumptionMode);
PULL_VALUE(TNLRequestConfigurationPropertyKeyProtocolOptions, protocolOptions, integerValue, TNLRequestProtocolOptions);
PULL_VALUE(TNLRequestConfigurationPropertyKeyConnectivityOptions, connectivityOptions, integerValue, TNLRequestConnectivityOptions);
PULL_VALUE(TNLRequestConfigurationPropertyKeyIdleTimeout, idleTimeout, doubleValue, NSTimeInterval);
PULL_VALUE(TNLRequestConfigurationPropertyKeyAttemptTimeout, attemptTimeout, doubleValue, NSTimeInterval);
PULL_VALUE(TNLRequestConfigurationPropertyKeyOperationTimeout, operationTimeout, doubleValue, NSTimeInterval);
PULL_VALUE(TNLRequestConfigurationPropertyKeyDeferrableInterval, deferrableInterval, doubleValue, NSTimeInterval);
PULL_VALUE(TNLRequestConfigurationPropertyKeyCachePolicy, cachePolicy, integerValue, NSURLRequestCachePolicy);
PULL_VALUE(TNLRequestConfigurationPropertyKeyNetworkServiceType, networkServiceType, integerValue, NSURLRequestNetworkServiceType);
PULL_VALUE(TNLRequestConfigurationPropertyKeyCookieAcceptPolicy, cookieAcceptPolicy, integerValue, NSHTTPCookieAcceptPolicy);
PULL_VALUE(TNLRequestConfigurationPropertyKeyShouldSetCookies, shouldSetCookies, boolValue, BOOL);
PULL_VALUE(TNLRequestConfigurationPropertyKeyAllowsCellularAccess, allowsCellularAccess, boolValue, BOOL);
PULL_VALUE(TNLRequestConfigurationPropertyKeyDiscrectionary, discretionary, boolValue, BOOL);
PULL_VALUE(TNLRequestConfigurationPropertyKeyShouldLaunchAppForBackgroundEvents, shouldLaunchAppForBackgroundEvents, boolValue, BOOL);
PULL_VALUE(TNLRequestConfigurationPropertyKeyShouldUseExtendedBackgroundIdleMode, shouldUseExtendedBackgroundIdleMode, boolValue, BOOL);
#if TARGET_OS_IOS
if (tnl_available_ios_11) {
PULL_VALUE(TNLRequestConfigurationPropertyKeyMultipathServiceType, multipathServiceType, integerValue, NSURLSessionMultipathServiceType);
}
#endif
mConfig.sharedContainerIdentifier = params[TNLRequestConfigurationPropertyKeySharedContainerIdentifier];
// These cannot loaded from the params so it's best to have them be nil.
// Having them be the default shared objects could hide that this constructor
// doesn't actually load in these objects.
mConfig.URLCredentialStorage = nil;
mConfig.URLCache = nil;
mConfig.cookieStorage = nil;
#undef PULL_VALUE
mConfig.executionMode = mode;
return mConfig;
}
- (void)applyDefaultTimeouts
{
_ivars.idleTimeout = kConfigurationIdleTimeoutDefault;
_ivars.attemptTimeout = kConfigurationAttemptTimeoutDefault;
_ivars.operationTimeout = kConfigurationOperationTimeoutDefault;
_ivars.deferrableInterval = kConfigurationDeferrableIntervalDefault;
}
@end
#pragma mark - Functions
NSURLCache * __nullable TNLUnwrappedURLCache(NSURLCache * __nullable cache)
{
if (cache == [NSURLCache tnl_sharedURLCacheProxy]) {
return [NSURLCache sharedURLCache];
}
return cache;
}
NSURLCredentialStorage * __nullable TNLUnwrappedURLCredentialStorage(NSURLCredentialStorage * __nullable storage)
{
if (storage == [NSURLCredentialStorage tnl_sharedCredentialStorageProxy]) {
return [NSURLCredentialStorage sharedCredentialStorage];
}
return storage;
}
NSHTTPCookieStorage * __nullable TNLUnwrappedCookieStorage(NSHTTPCookieStorage * __nullable storage)
{
if (storage == [NSHTTPCookieStorage tnl_sharedHTTPCookieStorageProxy]) {
return [NSHTTPCookieStorage sharedHTTPCookieStorage];
}
return storage;
}
void TNLMutableParametersStripURLCacheAndURLCredentialStorageAndCookieStorage(TNLMutableParameterCollection *params)
{
params[TNLRequestConfigurationPropertyKeyURLCredentialStorage] = nil;
params[TNLRequestConfigurationPropertyKeyURLCache] = nil;
params[TNLRequestConfigurationPropertyKeyCookieStorage] = nil;
}
TNLMutableParameterCollection * __nullable TNLMutableParametersFromRequestConfiguration(TNLRequestConfiguration *config,
NSURLCache * __nullable canonicalCache,
NSURLCredentialStorage * __nullable canonicalCredentialStorage,
NSHTTPCookieStorage * __nullable canonicalCookieStorage)
{
if (!config) {
return nil;
}
if (!canonicalCache) {
canonicalCache = TNLUnwrappedURLCache(config.URLCache);
}
if (!canonicalCredentialStorage) {
canonicalCredentialStorage = TNLUnwrappedURLCredentialStorage(config.URLCredentialStorage);
}
if (!canonicalCookieStorage) {
canonicalCookieStorage = TNLUnwrappedCookieStorage(config.cookieStorage);
}
TNLMutableParameterCollection *params = [[TNLMutableParameterCollection alloc] init];
// Only for TNL layer (not NSURLSession)
params[TNLRequestConfigurationPropertyKeyRedirectPolicy] = @(config.redirectPolicy);
params[TNLRequestConfigurationPropertyKeyResponseDataConsumptionMode] = @(config.responseDataConsumptionMode);
params[TNLRequestConfigurationPropertyKeyOperationTimeout] = @(config.operationTimeout);
params[TNLRequestConfigurationPropertyKeyDeferrableInterval] = @(config.deferrableInterval);
params[TNLRequestConfigurationPropertyKeyConnectivityOptions] = @(config.connectivityOptions);
// For NSURLSession layer in the background
params[TNLRequestConfigurationPropertyKeyIdleTimeout] = @(config.idleTimeout);
params[TNLRequestConfigurationPropertyKeyAttemptTimeout] = @(config.attemptTimeout);
params[TNLRequestConfigurationPropertyKeyShouldLaunchAppForBackgroundEvents] = @(config.shouldLaunchAppForBackgroundEvents);
#if TARGET_OS_IOS
if (tnl_available_ios_11) {
const NSURLSessionMultipathServiceType type = config.multipathServiceType;
if (type != 0) {
params[TNLRequestConfigurationPropertyKeyMultipathServiceType] = @(type);
}
}
#endif
// Other properties
params[TNLRequestConfigurationPropertyKeyProtocolOptions] = @(config.protocolOptions);
params[TNLRequestConfigurationPropertyKeyConnectivityOptions] = @(config.connectivityOptions);
params[TNLRequestConfigurationPropertyKeyCachePolicy] = @(config.cachePolicy);
params[TNLRequestConfigurationPropertyKeyNetworkServiceType] = @(config.networkServiceType);
params[TNLRequestConfigurationPropertyKeyAllowsCellularAccess] = @(config.allowsCellularAccess);
params[TNLRequestConfigurationPropertyKeyDiscrectionary] = @(config.isDiscretionary);
params[TNLRequestConfigurationPropertyKeyCookieAcceptPolicy] = @(config.cookieAcceptPolicy);
params[TNLRequestConfigurationPropertyKeyShouldSetCookies] = @(config.shouldSetCookies);
params[TNLRequestConfigurationPropertyKeyShouldUseExtendedBackgroundIdleMode] = @(config.shouldUseExtendedBackgroundIdleMode);
id value;
value = config.sharedContainerIdentifier;
if (value) {
params[TNLRequestConfigurationPropertyKeySharedContainerIdentifier] = value;
}
value = canonicalCredentialStorage ?: config.URLCredentialStorage;
if (value) {
params[TNLRequestConfigurationPropertyKeyURLCredentialStorage] = [NSString stringWithFormat:@"%@_%p", NSStringFromClass([value class]), value];
}
value = canonicalCache ?: config.URLCache;
if (value) {
params[TNLRequestConfigurationPropertyKeyURLCache] = [NSString stringWithFormat:@"%@_%p", NSStringFromClass([value class]), value];
}
value = canonicalCookieStorage ?: config.cookieStorage;
if (value) {
params[TNLRequestConfigurationPropertyKeyCookieStorage] = [NSString stringWithFormat:@"%@_%p", NSStringFromClass([value class]), value];
}
/**
Note:
config.contributeToExecutingNetworkConnectionsCount,
config.skipHostSanitization,
config.responseComputeHashAlgorithm,
config.contentEncoder,
config.additionContentDecoders,
config.retryPolicyProvider and
config.executionMode
are omitted on purpose.
*/
return params;
}
NSArray *TNLProtocolClassesForProtocolOptions(TNLRequestProtocolOptions options)
{
if (!options) {
return nil;
}
NSMutableArray *protocols = [[NSMutableArray alloc] init];
if (TNL_BITMASK_HAS_SUBSET_FLAGS(options, TNLRequestProtocolOptionPseudo)) {
[protocols addObject:[TNLPseudoURLProtocol class]];
}
return protocols;
}
TNLRequestProtocolOptions TNLProtocolOptionsForProtocolClasses(NSArray * __nullable protocols)
{
TNLRequestProtocolOptions options = 0;
for (Class c in protocols) {
if ([c isSubclassOfClass:[TNLPseudoURLProtocol class]]) {
options |= TNLRequestProtocolOptionPseudo;
}
}
return options;
}
void TNLRequestConfigurationAssociateWithRequest(TNLRequestConfiguration *config, NSURLRequest *request)
{
TNLAssert(request);
TNLAssert(config);
if (request) {
objc_setAssociatedObject(request, &kAssociatedConfigKey, config, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
}
TNLRequestConfiguration * __nullable TNLRequestConfigurationGetAssociatedWithRequest(NSURLRequest *request)
{
TNLAssert(request);
if (request) {
return objc_getAssociatedObject(request, &kAssociatedConfigKey);
}
return nil;
}
NS_ASSUME_NONNULL_END