firebase log level
This commit is contained in:
56
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.h
generated
Normal file
56
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.h
generated
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2019 Google
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
OBJC_EXTERN const NSUInteger FIRCLSNetworkMaximumRetryCount;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^FIRCLSNetworkDataTaskCompletionHandlerBlock)(NSData *__nullable data,
|
||||
NSURLResponse *__nullable response,
|
||||
NSError *__nullable error);
|
||||
typedef void (^FIRCLSNetworkDownloadTaskCompletionHandlerBlock)(NSURL *__nullable location,
|
||||
NSURLResponse *__nullable response,
|
||||
NSError *__nullable error);
|
||||
|
||||
@interface FIRCLSFABNetworkClient : NSObject
|
||||
|
||||
- (instancetype)init;
|
||||
- (instancetype)initWithQueue:(nullable NSOperationQueue *)operationQueue;
|
||||
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)config
|
||||
queue:(nullable NSOperationQueue *)operationQueue
|
||||
NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (void)startDataTaskWithRequest:(NSURLRequest *)request
|
||||
retryLimit:(NSUInteger)retryLimit
|
||||
completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler;
|
||||
- (void)startDownloadTaskWithRequest:(NSURLRequest *)request
|
||||
retryLimit:(NSUInteger)retryLimit
|
||||
completionHandler:
|
||||
(FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler;
|
||||
|
||||
- (void)invalidateAndCancel;
|
||||
|
||||
// Backwards compatibility (we cannot change an interface in Fabric Base that other kits rely on,
|
||||
// since we have no control of versioning dependencies)
|
||||
- (void)startDataTaskWithRequest:(NSURLRequest *)request
|
||||
completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler;
|
||||
- (void)startDownloadTaskWithRequest:(NSURLRequest *)request
|
||||
completionHandler:
|
||||
(FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
267
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.m
generated
Normal file
267
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.m
generated
Normal file
@ -0,0 +1,267 @@
|
||||
// Copyright 2019 Google
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.h"
|
||||
|
||||
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.h"
|
||||
|
||||
static const float FIRCLSNetworkMinimumRetryJitter = 0.90f;
|
||||
static const float FIRCLSNetworkMaximumRetryJitter = 1.10f;
|
||||
const NSUInteger FIRCLSNetworkMaximumRetryCount = 10;
|
||||
|
||||
@interface FIRCLSFABNetworkClient () <NSURLSessionDelegate, NSURLSessionTaskDelegate>
|
||||
|
||||
@property(nonatomic, strong, readonly) NSURLSession *session;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FIRCLSFABNetworkClient
|
||||
|
||||
- (instancetype)init {
|
||||
return [self initWithQueue:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithQueue:(nullable NSOperationQueue *)operationQueue {
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
return [self initWithSessionConfiguration:config queue:operationQueue];
|
||||
}
|
||||
|
||||
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)config
|
||||
queue:(nullable NSOperationQueue *)operationQueue {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_session = [NSURLSession sessionWithConfiguration:config
|
||||
delegate:self
|
||||
delegateQueue:operationQueue];
|
||||
|
||||
if (!_session) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_session finishTasksAndInvalidate];
|
||||
}
|
||||
|
||||
#pragma mark - Delay Handling
|
||||
- (double)randomDoubleWithMin:(double)min max:(double)max {
|
||||
return min + ((max - min) * drand48());
|
||||
}
|
||||
|
||||
- (double)generateRandomJitter {
|
||||
return [self randomDoubleWithMin:FIRCLSNetworkMinimumRetryJitter
|
||||
max:FIRCLSNetworkMaximumRetryJitter];
|
||||
}
|
||||
|
||||
- (NSTimeInterval)computeDelayForResponse:(NSURLResponse *)response
|
||||
withRetryCount:(NSUInteger)count {
|
||||
NSTimeInterval initialValue = [FIRCLSNetworkResponseHandler retryValueForResponse:response];
|
||||
|
||||
// make sure count is > 0
|
||||
count = MAX(count, 1);
|
||||
// make sure initialValue is >2 for exponential backoff to work reasonably with low count numbers
|
||||
initialValue = MAX(initialValue, 2.0);
|
||||
|
||||
const double jitter = [self generateRandomJitter];
|
||||
|
||||
return pow(initialValue, count) * jitter; // exponential backoff
|
||||
}
|
||||
|
||||
- (void)runAfterRetryValueFromResponse:(NSURLResponse *)response
|
||||
attempts:(NSUInteger)count
|
||||
onQueue:(dispatch_queue_t)queue
|
||||
block:(void (^)(void))block {
|
||||
const NSTimeInterval delay = [self computeDelayForResponse:response withRetryCount:count];
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (uint64_t)(delay * NSEC_PER_SEC)), queue, block);
|
||||
}
|
||||
|
||||
- (void)runAfterRetryValueFromResponse:(NSURLResponse *)response
|
||||
attempts:(NSUInteger)count
|
||||
block:(void (^)(void))block {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
|
||||
[self runAfterRetryValueFromResponse:response attempts:count onQueue:queue block:block];
|
||||
}
|
||||
|
||||
#pragma mark - Tasks
|
||||
|
||||
- (void)startDataTaskWithRequest:(NSURLRequest *)request
|
||||
retryLimit:(NSUInteger)retryLimit
|
||||
tries:(NSUInteger)tries
|
||||
completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler {
|
||||
NSURLSessionTask *task = [self.session
|
||||
dataTaskWithRequest:request
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *taskError) {
|
||||
[FIRCLSNetworkResponseHandler
|
||||
handleCompletedResponse:response
|
||||
forOriginalRequest:request
|
||||
error:taskError
|
||||
block:^(BOOL retry, NSError *error) {
|
||||
if (!retry) {
|
||||
completionHandler(data, response, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tries >= retryLimit) {
|
||||
NSDictionary *userInfo = @{
|
||||
@"retryLimit" : @(retryLimit),
|
||||
NSURLErrorFailingURLStringErrorKey : request.URL
|
||||
};
|
||||
completionHandler(
|
||||
nil, nil,
|
||||
[NSError
|
||||
errorWithDomain:FIRCLSNetworkErrorDomain
|
||||
code:FIRCLSNetworkErrorMaximumAttemptsReached
|
||||
userInfo:userInfo]);
|
||||
return;
|
||||
}
|
||||
|
||||
[self
|
||||
runAfterRetryValueFromResponse:response
|
||||
attempts:tries
|
||||
block:^{
|
||||
[self
|
||||
startDataTaskWithRequest:
|
||||
request
|
||||
retryLimit:
|
||||
retryLimit
|
||||
tries:
|
||||
(tries +
|
||||
1)
|
||||
completionHandler:
|
||||
completionHandler];
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
|
||||
if (!task) {
|
||||
completionHandler(nil, nil,
|
||||
[NSError errorWithDomain:FIRCLSNetworkErrorDomain
|
||||
code:FIRCLSNetworkErrorFailedToStartOperation
|
||||
userInfo:nil]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)startDataTaskWithRequest:(NSURLRequest *)request
|
||||
retryLimit:(NSUInteger)retryLimit
|
||||
completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler {
|
||||
[self startDataTaskWithRequest:request
|
||||
retryLimit:retryLimit
|
||||
tries:0
|
||||
completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)startDataTaskWithRequest:(NSURLRequest *)request
|
||||
completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler {
|
||||
[self startDataTaskWithRequest:request
|
||||
retryLimit:FIRCLSNetworkMaximumRetryCount
|
||||
completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)startDownloadTaskWithRequest:(NSURLRequest *)request
|
||||
retryLimit:(NSUInteger)retryLimit
|
||||
tries:(NSUInteger)tries
|
||||
completionHandler:
|
||||
(FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler {
|
||||
NSURLSessionTask *task = [self.session
|
||||
downloadTaskWithRequest:request
|
||||
completionHandler:^(NSURL *location, NSURLResponse *response, NSError *taskError) {
|
||||
[FIRCLSNetworkResponseHandler
|
||||
handleCompletedResponse:response
|
||||
forOriginalRequest:request
|
||||
error:taskError
|
||||
block:^(BOOL retry, NSError *error) {
|
||||
if (!retry) {
|
||||
completionHandler(location, response, error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tries >= retryLimit) {
|
||||
NSDictionary *userInfo = @{
|
||||
@"retryLimit" : @(retryLimit),
|
||||
NSURLErrorFailingURLStringErrorKey : request.URL
|
||||
};
|
||||
completionHandler(
|
||||
nil, nil,
|
||||
[NSError
|
||||
errorWithDomain:FIRCLSNetworkErrorDomain
|
||||
code:
|
||||
FIRCLSNetworkErrorMaximumAttemptsReached
|
||||
userInfo:userInfo]);
|
||||
return;
|
||||
}
|
||||
|
||||
[self
|
||||
runAfterRetryValueFromResponse:response
|
||||
attempts:tries
|
||||
block:^{
|
||||
[self
|
||||
startDownloadTaskWithRequest:
|
||||
request
|
||||
retryLimit:
|
||||
retryLimit
|
||||
tries:
|
||||
(tries +
|
||||
1)
|
||||
completionHandler:
|
||||
completionHandler];
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
|
||||
if (!task) {
|
||||
completionHandler(nil, nil,
|
||||
[NSError errorWithDomain:FIRCLSNetworkErrorDomain
|
||||
code:FIRCLSNetworkErrorFailedToStartOperation
|
||||
userInfo:nil]);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)startDownloadTaskWithRequest:(NSURLRequest *)request
|
||||
retryLimit:(NSUInteger)retryLimit
|
||||
completionHandler:
|
||||
(FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler {
|
||||
[self startDownloadTaskWithRequest:request
|
||||
retryLimit:retryLimit
|
||||
tries:0
|
||||
completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)startDownloadTaskWithRequest:(NSURLRequest *)request
|
||||
completionHandler:
|
||||
(FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler {
|
||||
[self startDownloadTaskWithRequest:request
|
||||
retryLimit:FIRCLSNetworkMaximumRetryCount
|
||||
completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)invalidateAndCancel {
|
||||
[self.session invalidateAndCancel];
|
||||
}
|
||||
|
||||
#pragma mark - NSURLSession Delegate
|
||||
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error {
|
||||
}
|
||||
|
||||
@end
|
||||
87
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.h
generated
Normal file
87
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.h
generated
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright 2019 Google
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* Type to indicate response status
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, FIRCLSNetworkClientResponseType) {
|
||||
FIRCLSNetworkClientResponseSuccess,
|
||||
FIRCLSNetworkClientResponseInvalid,
|
||||
FIRCLSNetworkClientResponseFailure,
|
||||
FIRCLSNetworkClientResponseRetry,
|
||||
FIRCLSNetworkClientResponseBackOff
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, FIRCLSNetworkErrorType) {
|
||||
FIRCLSNetworkErrorUnknown = -1,
|
||||
FIRCLSNetworkErrorFailedToStartOperation = -3,
|
||||
FIRCLSNetworkErrorResponseInvalid = -4,
|
||||
FIRCLSNetworkErrorRequestFailed = -5,
|
||||
FIRCLSNetworkErrorMaximumAttemptsReached = -6,
|
||||
};
|
||||
|
||||
extern NSInteger const FIRCLSNetworkErrorUnknownURLCancelReason;
|
||||
|
||||
/**
|
||||
* This block is an input parameter to handleCompletedResponse: and handleCompletedTask: methods of
|
||||
* this class.
|
||||
* @param retryMightSucceed is YES if the request should be retried.
|
||||
* @param error is the error received back in response.
|
||||
*/
|
||||
typedef void (^FIRCLSNetworkResponseCompletionHandlerBlock)(BOOL retryMightSucceed, NSError *error);
|
||||
|
||||
/**
|
||||
* Error domain for Crashlytics network errors
|
||||
*/
|
||||
extern NSString *const FIRCLSNetworkErrorDomain;
|
||||
/**
|
||||
* This class handles network responses.
|
||||
*/
|
||||
@interface FIRCLSNetworkResponseHandler : NSObject
|
||||
/**
|
||||
* Returns the header in the given NSURLResponse with name as key
|
||||
*/
|
||||
+ (NSString *)headerForResponse:(NSURLResponse *)response withKey:(NSString *)key;
|
||||
/**
|
||||
* Returns Retry-After header value in response, and if absent returns a default retry value
|
||||
*/
|
||||
+ (NSTimeInterval)retryValueForResponse:(NSURLResponse *)response;
|
||||
/**
|
||||
* Checks if the content type for response matches the request
|
||||
*/
|
||||
+ (BOOL)contentTypeForResponse:(NSURLResponse *)response matchesRequest:(NSURLRequest *)request;
|
||||
|
||||
+ (NSInteger)cancelReasonFromURLError:(NSError *)error;
|
||||
|
||||
+ (BOOL)retryableURLError:(NSError *)error;
|
||||
|
||||
/**
|
||||
* Convenience method that calls back the input block with FIRCLSNetworkClientResponseType after
|
||||
* checking the response code in response
|
||||
*/
|
||||
+ (void)clientResponseType:(NSURLResponse *)response
|
||||
handler:(void (^)(FIRCLSNetworkClientResponseType type,
|
||||
NSInteger statusCode))responseTypeAndStatusCodeHandlerBlock;
|
||||
/**
|
||||
* Handles a completed response for request and calls back input block. Populates error even if
|
||||
* error was nil, but response code indicated an error.
|
||||
*/
|
||||
+ (void)handleCompletedResponse:(NSURLResponse *)response
|
||||
forOriginalRequest:(NSURLRequest *)originalRequest
|
||||
error:(NSError *)error
|
||||
block:(FIRCLSNetworkResponseCompletionHandlerBlock)completionHandlerBlock;
|
||||
|
||||
@end
|
||||
290
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.m
generated
Normal file
290
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.m
generated
Normal file
@ -0,0 +1,290 @@
|
||||
// Copyright 2019 Google
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.h"
|
||||
|
||||
@implementation FIRCLSNetworkResponseHandler
|
||||
|
||||
static const NSTimeInterval kFIRCLSNetworkResponseHandlerDefaultRetryInterval = 2.0;
|
||||
static NSString *const kFIRCLSNetworkResponseHandlerContentType = @"Content-Type";
|
||||
NSString *const FIRCLSNetworkErrorDomain = @"FIRCLSNetworkError";
|
||||
|
||||
NSInteger const FIRCLSNetworkErrorUnknownURLCancelReason = -1;
|
||||
|
||||
#pragma mark - Header Handling
|
||||
+ (NSString *)headerForResponse:(NSURLResponse *)response withKey:(NSString *)key {
|
||||
if (![response respondsToSelector:@selector(allHeaderFields)]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [((NSHTTPURLResponse *)response).allHeaderFields objectForKey:key];
|
||||
}
|
||||
|
||||
+ (NSTimeInterval)retryValueForResponse:(NSURLResponse *)response {
|
||||
NSString *retryValueString = [self headerForResponse:response withKey:@"Retry-After"];
|
||||
if (!retryValueString) {
|
||||
return kFIRCLSNetworkResponseHandlerDefaultRetryInterval;
|
||||
}
|
||||
|
||||
NSTimeInterval value = retryValueString.doubleValue;
|
||||
if (value < 0.0) {
|
||||
return kFIRCLSNetworkResponseHandlerDefaultRetryInterval;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
+ (NSString *)requestIdForResponse:(NSURLResponse *)response {
|
||||
return [self headerForResponse:response withKey:@"X-Request-Id"];
|
||||
}
|
||||
|
||||
+ (BOOL)contentTypeForResponse:(NSURLResponse *)response matchesRequest:(NSURLRequest *)request {
|
||||
NSString *accept = [request.allHTTPHeaderFields objectForKey:@"Accept"];
|
||||
if (!accept) {
|
||||
// An omitted accept header is defined to match everything
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSString *contentHeader = [self.class headerForResponse:response
|
||||
withKey:kFIRCLSNetworkResponseHandlerContentType];
|
||||
if (!contentHeader) {
|
||||
// FIRCLSDeveloperLog("Network", @"Content-Type not present in response");
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *acceptCharset = request.allHTTPHeaderFields[@"Accept-Charset"];
|
||||
|
||||
NSArray *parts = [contentHeader componentsSeparatedByString:@"; charset="];
|
||||
if (!parts) {
|
||||
parts = @[ contentHeader ];
|
||||
}
|
||||
|
||||
if ([[parts objectAtIndex:0] caseInsensitiveCompare:accept] != NSOrderedSame) {
|
||||
// FIRCLSDeveloperLog("Network", @"Content-Type does not match Accept");
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (!acceptCharset) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (parts.count < 2) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return [[parts objectAtIndex:1] caseInsensitiveCompare:acceptCharset] == NSOrderedSame;
|
||||
}
|
||||
|
||||
+ (NSInteger)cancelReasonFromURLError:(NSError *)error {
|
||||
if (![[error domain] isEqualToString:NSURLErrorDomain]) {
|
||||
return FIRCLSNetworkErrorUnknownURLCancelReason;
|
||||
}
|
||||
|
||||
if ([error code] != NSURLErrorCancelled) {
|
||||
return FIRCLSNetworkErrorUnknownURLCancelReason;
|
||||
}
|
||||
|
||||
NSNumber *reason = [[error userInfo] objectForKey:NSURLErrorBackgroundTaskCancelledReasonKey];
|
||||
if (reason == nil) {
|
||||
return FIRCLSNetworkErrorUnknownURLCancelReason;
|
||||
}
|
||||
|
||||
return [reason integerValue];
|
||||
}
|
||||
|
||||
+ (BOOL)retryableURLError:(NSError *)error {
|
||||
// So far, the only task errors seen are NSURLErrorDomain. For others, we're not
|
||||
// sure what to do.
|
||||
if (![[error domain] isEqualToString:NSURLErrorDomain]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// cases that we know are definitely not retryable
|
||||
switch ([error code]) {
|
||||
case NSURLErrorBadURL:
|
||||
case NSURLErrorUnsupportedURL:
|
||||
case NSURLErrorHTTPTooManyRedirects:
|
||||
case NSURLErrorRedirectToNonExistentLocation:
|
||||
case NSURLErrorUserCancelledAuthentication:
|
||||
case NSURLErrorUserAuthenticationRequired:
|
||||
case NSURLErrorAppTransportSecurityRequiresSecureConnection:
|
||||
case NSURLErrorFileDoesNotExist:
|
||||
case NSURLErrorFileIsDirectory:
|
||||
case NSURLErrorDataLengthExceedsMaximum:
|
||||
case NSURLErrorSecureConnectionFailed:
|
||||
case NSURLErrorServerCertificateHasBadDate:
|
||||
case NSURLErrorServerCertificateUntrusted:
|
||||
case NSURLErrorServerCertificateHasUnknownRoot:
|
||||
case NSURLErrorServerCertificateNotYetValid:
|
||||
case NSURLErrorClientCertificateRejected:
|
||||
case NSURLErrorClientCertificateRequired:
|
||||
case NSURLErrorBackgroundSessionRequiresSharedContainer:
|
||||
return NO;
|
||||
}
|
||||
|
||||
// All other errors, as far as I can tell, are things that could clear up
|
||||
// without action on the part of the client.
|
||||
|
||||
// NSURLErrorCancelled is a potential special-case. I believe there are
|
||||
// situations where a cancelled request cannot be successfully restarted. But,
|
||||
// until I can prove it, we'll retry. There are definitely many cases where
|
||||
// a cancelled request definitely can be restarted and will work.
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Error Creation
|
||||
+ (NSError *)errorForCode:(NSInteger)code userInfo:(NSDictionary *)userInfo {
|
||||
return [NSError errorWithDomain:FIRCLSNetworkErrorDomain code:code userInfo:userInfo];
|
||||
}
|
||||
|
||||
+ (NSError *)errorForResponse:(NSURLResponse *)response
|
||||
ofType:(FIRCLSNetworkClientResponseType)type
|
||||
status:(NSInteger)status {
|
||||
if (type == FIRCLSNetworkClientResponseSuccess) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *requestId = [self requestIdForResponse:response];
|
||||
NSString *contentType = [self headerForResponse:response
|
||||
withKey:kFIRCLSNetworkResponseHandlerContentType];
|
||||
|
||||
// this could be nil, so be careful
|
||||
requestId = requestId ? requestId : @"";
|
||||
contentType = contentType ? contentType : @"";
|
||||
|
||||
NSDictionary *userInfo = @{
|
||||
@"type" : @(type),
|
||||
@"status_code" : @(status),
|
||||
@"request_id" : requestId,
|
||||
@"content_type" : contentType
|
||||
};
|
||||
|
||||
// compute a reasonable error code type
|
||||
NSInteger errorCode = FIRCLSNetworkErrorUnknown;
|
||||
switch (type) {
|
||||
case FIRCLSNetworkClientResponseFailure:
|
||||
errorCode = FIRCLSNetworkErrorRequestFailed;
|
||||
break;
|
||||
case FIRCLSNetworkClientResponseInvalid:
|
||||
errorCode = FIRCLSNetworkErrorResponseInvalid;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return [self errorForCode:errorCode userInfo:userInfo];
|
||||
}
|
||||
|
||||
+ (void)clientResponseType:(NSURLResponse *)response
|
||||
handler:(void (^)(FIRCLSNetworkClientResponseType type,
|
||||
NSInteger statusCode))responseTypeAndStatusCodeHandlerBlock {
|
||||
if (![response respondsToSelector:@selector(statusCode)]) {
|
||||
responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseInvalid, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
NSInteger code = ((NSHTTPURLResponse *)response).statusCode;
|
||||
|
||||
switch (code) {
|
||||
case 200:
|
||||
case 201:
|
||||
case 202:
|
||||
case 204:
|
||||
case 304:
|
||||
responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseSuccess, code);
|
||||
return;
|
||||
case 420:
|
||||
case 429:
|
||||
responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseBackOff, code);
|
||||
return;
|
||||
case 408:
|
||||
responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseRetry, code);
|
||||
return;
|
||||
case 400:
|
||||
case 401:
|
||||
case 403:
|
||||
case 404:
|
||||
case 406:
|
||||
case 410:
|
||||
case 411:
|
||||
case 413:
|
||||
case 419:
|
||||
case 422:
|
||||
case 431:
|
||||
responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseFailure, code);
|
||||
return;
|
||||
}
|
||||
|
||||
// check for a 5xx
|
||||
if (code >= 500 && code <= 599) {
|
||||
responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseRetry, code);
|
||||
return;
|
||||
}
|
||||
|
||||
responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseInvalid, code);
|
||||
}
|
||||
|
||||
+ (void)handleCompletedResponse:(NSURLResponse *)response
|
||||
forOriginalRequest:(NSURLRequest *)originalRequest
|
||||
error:(NSError *)originalError
|
||||
block:
|
||||
(FIRCLSNetworkResponseCompletionHandlerBlock)completionHandlerBlock {
|
||||
// if we have an error, we can just continue
|
||||
if (originalError) {
|
||||
BOOL retryable = [self retryableURLError:originalError];
|
||||
|
||||
completionHandlerBlock(retryable, originalError);
|
||||
return;
|
||||
}
|
||||
|
||||
[self.class clientResponseType:response
|
||||
handler:^(FIRCLSNetworkClientResponseType type, NSInteger statusCode) {
|
||||
NSError *error = nil;
|
||||
|
||||
switch (type) {
|
||||
case FIRCLSNetworkClientResponseInvalid:
|
||||
error = [self errorForResponse:response
|
||||
ofType:type
|
||||
status:statusCode];
|
||||
break;
|
||||
case FIRCLSNetworkClientResponseBackOff:
|
||||
case FIRCLSNetworkClientResponseRetry:
|
||||
error = [self errorForResponse:response
|
||||
ofType:type
|
||||
status:statusCode];
|
||||
completionHandlerBlock(YES, error);
|
||||
return;
|
||||
case FIRCLSNetworkClientResponseFailure:
|
||||
error = [self errorForResponse:response
|
||||
ofType:type
|
||||
status:statusCode];
|
||||
break;
|
||||
case FIRCLSNetworkClientResponseSuccess:
|
||||
if (![self contentTypeForResponse:response
|
||||
matchesRequest:originalRequest]) {
|
||||
error = [self errorForResponse:response
|
||||
ofType:FIRCLSNetworkClientResponseInvalid
|
||||
status:statusCode];
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
completionHandlerBlock(NO, error);
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
44
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h
generated
Normal file
44
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h
generated
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2019 Google
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
* This is a convenience class to ease constructing NSURLs.
|
||||
*/
|
||||
@interface FIRCLSURLBuilder : NSObject
|
||||
|
||||
/**
|
||||
* Convenience method that returns a FIRCLSURLBuilder instance with the input base URL appended to
|
||||
* it.
|
||||
*/
|
||||
+ (instancetype)URLWithBase:(NSString *)base;
|
||||
/**
|
||||
* Appends the component to the URL being built by FIRCLSURLBuilder instance
|
||||
*/
|
||||
- (void)appendComponent:(NSString *)component;
|
||||
/**
|
||||
* Escapes and appends the component to the URL being built by FIRCLSURLBuilder instance
|
||||
*/
|
||||
- (void)escapeAndAppendComponent:(NSString *)component;
|
||||
/**
|
||||
* Adds a query and value to the URL being built
|
||||
*/
|
||||
- (void)appendValue:(id)value forQueryParam:(NSString *)param;
|
||||
/**
|
||||
* Returns the built URL
|
||||
*/
|
||||
- (NSURL *)URL;
|
||||
|
||||
@end
|
||||
104
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.m
generated
Normal file
104
Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.m
generated
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright 2019 Google
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h"
|
||||
|
||||
#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"
|
||||
|
||||
@interface FIRCLSURLBuilder ()
|
||||
|
||||
@property(nonatomic) NSMutableString *URLString;
|
||||
@property(nonatomic) NSUInteger queryParams;
|
||||
|
||||
- (NSString *)escapeString:(NSString *)string;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FIRCLSURLBuilder
|
||||
|
||||
+ (instancetype)URLWithBase:(NSString *)base {
|
||||
FIRCLSURLBuilder *url = [[FIRCLSURLBuilder alloc] init];
|
||||
|
||||
[url appendComponent:base];
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_URLString = [[NSMutableString alloc] init];
|
||||
_queryParams = 0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)escapeString:(NSString *)string {
|
||||
#if TARGET_OS_WATCH
|
||||
// TODO: Question - Why does watchOS use a different encoding from the other platforms and the
|
||||
// Android SDK?
|
||||
// This broken the unit test on watchOS: https://github.com/firebase/firebase-ios-sdk/pull/10511
|
||||
return
|
||||
[string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet
|
||||
URLPathAllowedCharacterSet]];
|
||||
#else
|
||||
return
|
||||
[string stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet
|
||||
.URLQueryAllowedCharacterSet];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)appendComponent:(NSString *)component {
|
||||
if (component.length == 0) {
|
||||
FIRCLSErrorLog(@"URLBuilder parameter component must not be empty");
|
||||
return;
|
||||
}
|
||||
|
||||
[self.URLString appendString:component];
|
||||
}
|
||||
|
||||
- (void)escapeAndAppendComponent:(NSString *)component {
|
||||
[self appendComponent:[self escapeString:component]];
|
||||
}
|
||||
|
||||
- (void)appendValue:(id)value forQueryParam:(NSString *)param {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.queryParams == 0) {
|
||||
[self appendComponent:@"?"];
|
||||
} else {
|
||||
[self appendComponent:@"&"];
|
||||
}
|
||||
|
||||
self.queryParams += 1;
|
||||
|
||||
[self appendComponent:param];
|
||||
[self appendComponent:@"="];
|
||||
if ([value isKindOfClass:NSString.class]) {
|
||||
[self escapeAndAppendComponent:value];
|
||||
} else {
|
||||
[self escapeAndAppendComponent:[value description]];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSURL *)URL {
|
||||
return [NSURL URLWithString:self.URLString];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user