From 98b6eef71eac368692ae249f056a75d89ed0350d Mon Sep 17 00:00:00 2001 From: Paul Beusterien Date: Fri, 6 Jul 2018 09:37:23 -0700 Subject: Split GoogleUtilities from FirebaseCore (#1370) --- Firebase/Core/FIRApp.m | 1 - Firebase/Core/FIRLogger.m | 175 +----- Firebase/Core/FIRMutableDictionary.m | 97 --- Firebase/Core/FIRNetwork.m | 390 ------------ Firebase/Core/FIRNetworkConstants.m | 39 -- Firebase/Core/FIRNetworkURLSession.m | 669 --------------------- Firebase/Core/FIRReachabilityChecker.m | 256 -------- Firebase/Core/FIRVersion.m | 4 +- Firebase/Core/Private/FIRMutableDictionary.h | 46 -- Firebase/Core/Private/FIRNetwork.h | 87 --- Firebase/Core/Private/FIRNetworkConstants.h | 75 --- Firebase/Core/Private/FIRNetworkLoggerProtocol.h | 50 -- Firebase/Core/Private/FIRNetworkMessageCode.h | 52 -- Firebase/Core/Private/FIRNetworkURLSession.h | 60 -- .../Core/Private/FIRReachabilityChecker+Internal.h | 47 -- Firebase/Core/Private/FIRReachabilityChecker.h | 83 --- Firebase/Core/Private/FIRVersion.h | 4 +- Firebase/Core/Public/FIRLoggerLevel.h | 3 + Firebase/Core/third_party/FIRAppEnvironmentUtil.h | 43 -- Firebase/Core/third_party/FIRAppEnvironmentUtil.m | 239 -------- 20 files changed, 39 insertions(+), 2381 deletions(-) delete mode 100644 Firebase/Core/FIRMutableDictionary.m delete mode 100644 Firebase/Core/FIRNetwork.m delete mode 100644 Firebase/Core/FIRNetworkConstants.m delete mode 100644 Firebase/Core/FIRNetworkURLSession.m delete mode 100644 Firebase/Core/FIRReachabilityChecker.m delete mode 100644 Firebase/Core/Private/FIRMutableDictionary.h delete mode 100644 Firebase/Core/Private/FIRNetwork.h delete mode 100644 Firebase/Core/Private/FIRNetworkConstants.h delete mode 100644 Firebase/Core/Private/FIRNetworkLoggerProtocol.h delete mode 100644 Firebase/Core/Private/FIRNetworkMessageCode.h delete mode 100644 Firebase/Core/Private/FIRNetworkURLSession.h delete mode 100644 Firebase/Core/Private/FIRReachabilityChecker+Internal.h delete mode 100644 Firebase/Core/Private/FIRReachabilityChecker.h delete mode 100644 Firebase/Core/third_party/FIRAppEnvironmentUtil.h delete mode 100644 Firebase/Core/third_party/FIRAppEnvironmentUtil.m (limited to 'Firebase/Core') diff --git a/Firebase/Core/FIRApp.m b/Firebase/Core/FIRApp.m index 2ea7f6b..9f698cf 100644 --- a/Firebase/Core/FIRApp.m +++ b/Firebase/Core/FIRApp.m @@ -23,7 +23,6 @@ #import "Private/FIRCoreConfigurable.h" #import "Private/FIRLogger.h" #import "Private/FIROptionsInternal.h" -#import "third_party/FIRAppEnvironmentUtil.h" NSString *const kFIRServiceAdMob = @"AdMob"; NSString *const kFIRServiceAuth = @"Auth"; diff --git a/Firebase/Core/FIRLogger.m b/Firebase/Core/FIRLogger.m index 2784ae9..dbec728 100644 --- a/Firebase/Core/FIRLogger.m +++ b/Firebase/Core/FIRLogger.m @@ -14,16 +14,11 @@ #import "Private/FIRLogger.h" -#import "FIRLoggerLevel.h" -#import "Private/FIRVersion.h" -#import "third_party/FIRAppEnvironmentUtil.h" +#import +#import +#import -#include -#include -#include -#include -#include -#include +#import "Private/FIRVersion.h" FIRLoggerService kFIRLoggerABTesting = @"[Firebase/ABTesting]"; FIRLoggerService kFIRLoggerAdMob = @"[Firebase/AdMob]"; @@ -51,24 +46,11 @@ NSString *const kFIRLoggerForceSDTERRApplicationArgument = @"-FIRLoggerForceSTDE /// Key for the debug mode bit in NSUserDefaults. NSString *const kFIRPersistedDebugModeKey = @"/google/firebase/debug_mode"; -/// ASL client facility name used by FIRLogger. -const char *kFIRLoggerASLClientFacilityName = "com.firebase.app.logger"; - -/// Keys for the number of errors and warnings logged. -NSString *const kFIRLoggerErrorCountKey = @"/google/firebase/count_of_errors_logged"; -NSString *const kFIRLoggerWarningCountKey = @"/google/firebase/count_of_warnings_logged"; - -static dispatch_once_t sFIRLoggerOnceToken; - -static aslclient sFIRLoggerClient; - -static dispatch_queue_t sFIRClientQueue; - /// NSUserDefaults that should be used to store and read variables. If nil, `standardUserDefaults` /// will be used. static NSUserDefaults *sFIRLoggerUserDefaults; -static BOOL sFIRLoggerDebugMode; +static dispatch_once_t sFIRLoggerOnceToken; // The sFIRAnalyticsDebugMode flag is here to support the -FIRDebugEnabled/-FIRDebugDisabled // flags used by Analytics. Users who use those flags expect Analytics to log verbosely, @@ -76,8 +58,6 @@ static BOOL sFIRLoggerDebugMode; // that behavior. static BOOL sFIRAnalyticsDebugMode; -static FIRLoggerLevel sFIRLoggerMaximumLevel; - #ifdef DEBUG /// The regex pattern for the message code. static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$"; @@ -86,96 +66,53 @@ static NSRegularExpression *sMessageCodeRegex; void FIRLoggerInitializeASL() { dispatch_once(&sFIRLoggerOnceToken, ^{ - NSInteger majorOSVersion = [[FIRAppEnvironmentUtil systemVersion] integerValue]; - uint32_t aslOptions = ASL_OPT_STDERR; -#if TARGET_OS_SIMULATOR - // The iOS 11 simulator doesn't need the ASL_OPT_STDERR flag. - if (majorOSVersion >= 11) { - aslOptions = 0; - } -#else - // Devices running iOS 10 or higher don't need the ASL_OPT_STDERR flag. - if (majorOSVersion >= 10) { - aslOptions = 0; - } -#endif // TARGET_OS_SIMULATOR + // Register Firebase Version with GULLogger. + GULLoggerRegisterVersion(FIRVersionString); // Override the aslOptions to ASL_OPT_STDERR if the override argument is passed in. NSArray *arguments = [NSProcessInfo processInfo].arguments; - if ([arguments containsObject:kFIRLoggerForceSDTERRApplicationArgument]) { - aslOptions = ASL_OPT_STDERR; - } - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" // asl is deprecated - // Initialize the ASL client handle. - sFIRLoggerClient = asl_open(NULL, kFIRLoggerASLClientFacilityName, aslOptions); - - // Set the filter used by system/device log. Initialize in default mode. - asl_set_filter(sFIRLoggerClient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_NOTICE)); - sFIRLoggerDebugMode = NO; - sFIRAnalyticsDebugMode = NO; - sFIRLoggerMaximumLevel = FIRLoggerLevelNotice; + BOOL overrideSTDERR = [arguments containsObject:kFIRLoggerForceSDTERRApplicationArgument]; // Use the standard NSUserDefaults if it hasn't been explicitly set. if (sFIRLoggerUserDefaults == nil) { sFIRLoggerUserDefaults = [NSUserDefaults standardUserDefaults]; } + BOOL forceDebugMode = NO; BOOL debugMode = [sFIRLoggerUserDefaults boolForKey:kFIRPersistedDebugModeKey]; if ([arguments containsObject:kFIRDisableDebugModeApplicationArgument]) { // Default mode [sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey]; } else if ([arguments containsObject:kFIREnableDebugModeApplicationArgument] || debugMode) { // Debug mode [sFIRLoggerUserDefaults setBool:YES forKey:kFIRPersistedDebugModeKey]; - asl_set_filter(sFIRLoggerClient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); - sFIRLoggerDebugMode = YES; - } - - // We should disable debug mode if we are running from App Store. - if (sFIRLoggerDebugMode && [FIRAppEnvironmentUtil isFromAppStore]) { - sFIRLoggerDebugMode = NO; + forceDebugMode = YES; } - - sFIRClientQueue = dispatch_queue_create("FIRLoggingClientQueue", DISPATCH_QUEUE_SERIAL); - dispatch_set_target_queue(sFIRClientQueue, - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)); - -#ifdef DEBUG - sMessageCodeRegex = - [NSRegularExpression regularExpressionWithPattern:kMessageCodePattern options:0 error:NULL]; -#endif + GULLoggerInitializeASL(overrideSTDERR, forceDebugMode); }); } -void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode) { - FIRLoggerInitializeASL(); - dispatch_async(sFIRClientQueue, ^{ - // We should not enable debug mode if we are running from App Store. - if (analyticsDebugMode && [FIRAppEnvironmentUtil isFromAppStore]) { - return; - } - sFIRAnalyticsDebugMode = analyticsDebugMode; - asl_set_filter(sFIRLoggerClient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); - }); +__attribute__((no_sanitize("thread"))) void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode) { + sFIRAnalyticsDebugMode = analyticsDebugMode; } void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel) { - if (loggerLevel < FIRLoggerLevelMin || loggerLevel > FIRLoggerLevelMax) { - FIRLogError(kFIRLoggerCore, @"I-COR000023", @"Invalid logger level, %ld", (long)loggerLevel); - return; - } FIRLoggerInitializeASL(); - // We should not raise the logger level if we are running from App Store. - if (loggerLevel >= FIRLoggerLevelNotice && [FIRAppEnvironmentUtil isFromAppStore]) { - return; - } + GULSetLoggerLevel((GULLoggerLevel)loggerLevel); +} - sFIRLoggerMaximumLevel = loggerLevel; - dispatch_async(sFIRClientQueue, ^{ - asl_set_filter(sFIRLoggerClient, ASL_FILTER_MASK_UPTO(loggerLevel)); - }); +#ifdef DEBUG +void FIRResetLogger() { + extern void GULResetLogger(void); + sFIRLoggerOnceToken = 0; + [sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey]; + sFIRLoggerUserDefaults = nil; + GULResetLogger(); +} + +void FIRSetLoggerUserDefaults(NSUserDefaults *defaults) { + sFIRLoggerUserDefaults = defaults; } +#endif /** * Check if the level is high enough to be loggable. @@ -186,37 +123,11 @@ void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel) { __attribute__((no_sanitize("thread"))) BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent) { FIRLoggerInitializeASL(); - if (sFIRLoggerDebugMode) { - return YES; - } else if (sFIRAnalyticsDebugMode && analyticsComponent) { + if (sFIRAnalyticsDebugMode && analyticsComponent) { return YES; } - return (BOOL)(loggerLevel <= sFIRLoggerMaximumLevel); -} - -#ifdef DEBUG -void FIRResetLogger() { - sFIRLoggerOnceToken = 0; - [sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey]; - sFIRLoggerUserDefaults = nil; -} - -void FIRSetLoggerUserDefaults(NSUserDefaults *defaults) { - sFIRLoggerUserDefaults = defaults; -} - -aslclient getFIRLoggerClient() { - return sFIRLoggerClient; -} - -dispatch_queue_t getFIRClientQueue() { - return sFIRClientQueue; -} - -BOOL getFIRLoggerDebugMode() { - return sFIRLoggerDebugMode; + return GULIsLoggableLevel((GULLoggerLevel)loggerLevel); } -#endif void FIRLogBasic(FIRLoggerLevel level, FIRLoggerService service, @@ -224,32 +135,10 @@ void FIRLogBasic(FIRLoggerLevel level, NSString *message, va_list args_ptr) { FIRLoggerInitializeASL(); - BOOL canLog = level <= sFIRLoggerMaximumLevel; - - if (sFIRLoggerDebugMode) { - canLog = YES; - } else if (sFIRAnalyticsDebugMode && [kFIRLoggerAnalytics isEqualToString:service]) { - canLog = YES; - } - - if (!canLog) { - return; - } -#ifdef DEBUG - NSCAssert(messageCode.length == 11, @"Incorrect message code length."); - NSRange messageCodeRange = NSMakeRange(0, messageCode.length); - NSUInteger numberOfMatches = - [sMessageCodeRegex numberOfMatchesInString:messageCode options:0 range:messageCodeRange]; - NSCAssert(numberOfMatches == 1, @"Incorrect message code format."); -#endif - NSString *logMsg = [[NSString alloc] initWithFormat:message arguments:args_ptr]; - logMsg = - [NSString stringWithFormat:@"%s - %@[%@] %@", FIRVersionString, service, messageCode, logMsg]; - dispatch_async(sFIRClientQueue, ^{ - asl_log(sFIRLoggerClient, NULL, level, "%s", logMsg.UTF8String); - }); + GULLogBasic((GULLoggerLevel)level, service, + sFIRAnalyticsDebugMode && [kFIRLoggerAnalytics isEqualToString:service], messageCode, + message, args_ptr); } -#pragma clang diagnostic pop /** * Generates the logging functions using macros. diff --git a/Firebase/Core/FIRMutableDictionary.m b/Firebase/Core/FIRMutableDictionary.m deleted file mode 100644 index 31941bc..0000000 --- a/Firebase/Core/FIRMutableDictionary.m +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2017 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 "Private/FIRMutableDictionary.h" - -@implementation FIRMutableDictionary { - /// The mutable dictionary. - NSMutableDictionary *_objects; - - /// Serial synchronization queue. All reads should use dispatch_sync, while writes use - /// dispatch_async. - dispatch_queue_t _queue; -} - -- (instancetype)init { - self = [super init]; - - if (self) { - _objects = [[NSMutableDictionary alloc] init]; - _queue = dispatch_queue_create("FIRMutableDictionary", DISPATCH_QUEUE_SERIAL); - } - - return self; -} - -- (NSString *)description { - __block NSString *description; - dispatch_sync(_queue, ^{ - description = self->_objects.description; - }); - return description; -} - -- (id)objectForKey:(id)key { - __block id object; - dispatch_sync(_queue, ^{ - object = self->_objects[key]; - }); - return object; -} - -- (void)setObject:(id)object forKey:(id)key { - dispatch_async(_queue, ^{ - self->_objects[key] = object; - }); -} - -- (void)removeObjectForKey:(id)key { - dispatch_async(_queue, ^{ - [self->_objects removeObjectForKey:key]; - }); -} - -- (void)removeAllObjects { - dispatch_async(_queue, ^{ - [self->_objects removeAllObjects]; - }); -} - -- (NSUInteger)count { - __block NSUInteger count; - dispatch_sync(_queue, ^{ - count = self->_objects.count; - }); - return count; -} - -- (id)objectForKeyedSubscript:(id)key { - // The method this calls is already synchronized. - return [self objectForKey:key]; -} - -- (void)setObject:(id)obj forKeyedSubscript:(id)key { - // The method this calls is already synchronized. - [self setObject:obj forKey:key]; -} - -- (NSDictionary *)dictionary { - __block NSDictionary *dictionary; - dispatch_sync(_queue, ^{ - dictionary = [self->_objects copy]; - }); - return dictionary; -} - -@end diff --git a/Firebase/Core/FIRNetwork.m b/Firebase/Core/FIRNetwork.m deleted file mode 100644 index ff292fc..0000000 --- a/Firebase/Core/FIRNetwork.m +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright 2017 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 "Private/FIRNetwork.h" -#import "Private/FIRNetworkMessageCode.h" - -#import "Private/FIRLogger.h" -#import "Private/FIRMutableDictionary.h" -#import "Private/FIRNetworkConstants.h" -#import "Private/FIRReachabilityChecker.h" - -#import - -/// Constant string for request header Content-Encoding. -static NSString *const kFIRNetworkContentCompressionKey = @"Content-Encoding"; - -/// Constant string for request header Content-Encoding value. -static NSString *const kFIRNetworkContentCompressionValue = @"gzip"; - -/// Constant string for request header Content-Length. -static NSString *const kFIRNetworkContentLengthKey = @"Content-Length"; - -/// Constant string for request header Content-Type. -static NSString *const kFIRNetworkContentTypeKey = @"Content-Type"; - -/// Constant string for request header Content-Type value. -static NSString *const kFIRNetworkContentTypeValue = @"application/x-www-form-urlencoded"; - -/// Constant string for GET request method. -static NSString *const kFIRNetworkGETRequestMethod = @"GET"; - -/// Constant string for POST request method. -static NSString *const kFIRNetworkPOSTRequestMethod = @"POST"; - -/// Default constant string as a prefix for network logger. -static NSString *const kFIRNetworkLogTag = @"Firebase/Network"; - -@interface FIRNetwork () -@end - -@implementation FIRNetwork { - /// Network reachability. - FIRReachabilityChecker *_reachability; - - /// The dictionary of requests by session IDs { NSString : id }. - FIRMutableDictionary *_requests; -} - -- (instancetype)init { - return [self initWithReachabilityHost:kFIRNetworkReachabilityHost]; -} - -- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost { - self = [super init]; - if (self) { - // Setup reachability. - _reachability = [[FIRReachabilityChecker alloc] initWithReachabilityDelegate:self - loggerDelegate:self - withHost:reachabilityHost]; - if (![_reachability start]) { - return nil; - } - - _requests = [[FIRMutableDictionary alloc] init]; - _timeoutInterval = kFIRNetworkTimeOutInterval; - } - return self; -} - -- (void)dealloc { - _reachability.reachabilityDelegate = nil; - [_reachability stop]; -} - -#pragma mark - External Methods - -+ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID - completionHandler:(FIRNetworkSystemCompletionHandler)completionHandler { - [FIRNetworkURLSession handleEventsForBackgroundURLSessionID:sessionID - completionHandler:completionHandler]; -} - -- (NSString *)postURL:(NSURL *)url - payload:(NSData *)payload - queue:(dispatch_queue_t)queue - usingBackgroundSession:(BOOL)usingBackgroundSession - completionHandler:(FIRNetworkCompletionHandler)handler { - if (!url.absoluteString.length) { - [self handleErrorWithCode:FIRErrorCodeNetworkInvalidURL queue:queue withHandler:handler]; - return nil; - } - - NSTimeInterval timeOutInterval = _timeoutInterval ?: kFIRNetworkTimeOutInterval; - - NSMutableURLRequest *request = - [[NSMutableURLRequest alloc] initWithURL:url - cachePolicy:NSURLRequestReloadIgnoringLocalCacheData - timeoutInterval:timeOutInterval]; - - if (!request) { - [self handleErrorWithCode:FIRErrorCodeNetworkSessionTaskCreation - queue:queue - withHandler:handler]; - return nil; - } - - NSError *compressError = nil; - NSData *compressedData = [NSData gtm_dataByGzippingData:payload error:&compressError]; - if (!compressedData || compressError) { - if (compressError || payload.length > 0) { - // If the payload is not empty but it fails to compress the payload, something has been wrong. - [self handleErrorWithCode:FIRErrorCodeNetworkPayloadCompression - queue:queue - withHandler:handler]; - return nil; - } - compressedData = [[NSData alloc] init]; - } - - NSString *postLength = @(compressedData.length).stringValue; - - // Set up the request with the compressed data. - [request setValue:postLength forHTTPHeaderField:kFIRNetworkContentLengthKey]; - request.HTTPBody = compressedData; - request.HTTPMethod = kFIRNetworkPOSTRequestMethod; - [request setValue:kFIRNetworkContentTypeValue forHTTPHeaderField:kFIRNetworkContentTypeKey]; - [request setValue:kFIRNetworkContentCompressionValue - forHTTPHeaderField:kFIRNetworkContentCompressionKey]; - - FIRNetworkURLSession *fetcher = [[FIRNetworkURLSession alloc] initWithNetworkLoggerDelegate:self]; - fetcher.backgroundNetworkEnabled = usingBackgroundSession; - - __weak FIRNetwork *weakSelf = self; - NSString *requestID = [fetcher - sessionIDFromAsyncPOSTRequest:request - completionHandler:^(NSHTTPURLResponse *response, NSData *data, - NSString *sessionID, NSError *error) { - FIRNetwork *strongSelf = weakSelf; - if (!strongSelf) { - return; - } - dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); - dispatch_async(queueToDispatch, ^{ - if (sessionID.length) { - [strongSelf->_requests removeObjectForKey:sessionID]; - } - if (handler) { - handler(response, data, error); - } - }); - }]; - if (!requestID) { - [self handleErrorWithCode:FIRErrorCodeNetworkSessionTaskCreation - queue:queue - withHandler:handler]; - return nil; - } - - [self firNetwork_logWithLevel:kFIRNetworkLogLevelDebug - messageCode:kFIRNetworkMessageCodeNetwork000 - message:@"Uploading data. Host" - context:url]; - _requests[requestID] = fetcher; - return requestID; -} - -- (NSString *)getURL:(NSURL *)url - headers:(NSDictionary *)headers - queue:(dispatch_queue_t)queue - usingBackgroundSession:(BOOL)usingBackgroundSession - completionHandler:(FIRNetworkCompletionHandler)handler { - if (!url.absoluteString.length) { - [self handleErrorWithCode:FIRErrorCodeNetworkInvalidURL queue:queue withHandler:handler]; - return nil; - } - - NSTimeInterval timeOutInterval = _timeoutInterval ?: kFIRNetworkTimeOutInterval; - NSMutableURLRequest *request = - [[NSMutableURLRequest alloc] initWithURL:url - cachePolicy:NSURLRequestReloadIgnoringLocalCacheData - timeoutInterval:timeOutInterval]; - - if (!request) { - [self handleErrorWithCode:FIRErrorCodeNetworkSessionTaskCreation - queue:queue - withHandler:handler]; - return nil; - } - - request.HTTPMethod = kFIRNetworkGETRequestMethod; - request.allHTTPHeaderFields = headers; - - FIRNetworkURLSession *fetcher = [[FIRNetworkURLSession alloc] initWithNetworkLoggerDelegate:self]; - fetcher.backgroundNetworkEnabled = usingBackgroundSession; - - __weak FIRNetwork *weakSelf = self; - NSString *requestID = [fetcher - sessionIDFromAsyncGETRequest:request - completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSString *sessionID, - NSError *error) { - FIRNetwork *strongSelf = weakSelf; - if (!strongSelf) { - return; - } - dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); - dispatch_async(queueToDispatch, ^{ - if (sessionID.length) { - [strongSelf->_requests removeObjectForKey:sessionID]; - } - if (handler) { - handler(response, data, error); - } - }); - }]; - - if (!requestID) { - [self handleErrorWithCode:FIRErrorCodeNetworkSessionTaskCreation - queue:queue - withHandler:handler]; - return nil; - } - - [self firNetwork_logWithLevel:kFIRNetworkLogLevelDebug - messageCode:kFIRNetworkMessageCodeNetwork001 - message:@"Downloading data. Host" - context:url]; - _requests[requestID] = fetcher; - return requestID; -} - -- (BOOL)hasUploadInProgress { - return _requests.count > 0; -} - -#pragma mark - Network Reachability - -/// Tells reachability delegate to call reachabilityDidChangeToStatus: to notify the network -/// reachability has changed. -- (void)reachability:(FIRReachabilityChecker *)reachability - statusChanged:(FIRReachabilityStatus)status { - _networkConnected = (status == kFIRReachabilityViaCellular || status == kFIRReachabilityViaWifi); - [_reachabilityDelegate reachabilityDidChange]; -} - -#pragma mark - Network logger delegate - -- (void)setLoggerDelegate:(id)loggerDelegate { - // Explicitly check whether the delegate responds to the methods because conformsToProtocol does - // not work correctly even though the delegate does respond to the methods. - if (!loggerDelegate || - ![loggerDelegate - respondsToSelector:@selector(firNetwork_logWithLevel:messageCode:message:contexts:)] || - ![loggerDelegate - respondsToSelector:@selector(firNetwork_logWithLevel:messageCode:message:context:)] || - ! - [loggerDelegate respondsToSelector:@selector(firNetwork_logWithLevel:messageCode:message:)]) { - FIRLogError(kFIRLoggerAnalytics, - [NSString stringWithFormat:@"I-NET%06ld", (long)kFIRNetworkMessageCodeNetwork002], - @"Cannot set the network logger delegate: delegate does not conform to the network " - "logger protocol."); - return; - } - _loggerDelegate = loggerDelegate; -} - -#pragma mark - Private methods - -/// Handles network error and calls completion handler with the error. -- (void)handleErrorWithCode:(NSInteger)code - queue:(dispatch_queue_t)queue - withHandler:(FIRNetworkCompletionHandler)handler { - NSDictionary *userInfo = @{kFIRNetworkErrorContext : @"Failed to create network request"}; - NSError *error = - [[NSError alloc] initWithDomain:kFIRNetworkErrorDomain code:code userInfo:userInfo]; - [self firNetwork_logWithLevel:kFIRNetworkLogLevelWarning - messageCode:kFIRNetworkMessageCodeNetwork002 - message:@"Failed to create network request. Code, error" - contexts:@[ @(code), error ]]; - if (handler) { - dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); - dispatch_async(queueToDispatch, ^{ - handler(nil, nil, error); - }); - } -} - -#pragma mark - Network logger - -- (void)firNetwork_logWithLevel:(FIRNetworkLogLevel)logLevel - messageCode:(FIRNetworkMessageCode)messageCode - message:(NSString *)message - contexts:(NSArray *)contexts { - // Let the delegate log the message if there is a valid logger delegate. Otherwise, just log - // errors/warnings/info messages to the console log. - if (_loggerDelegate) { - [_loggerDelegate firNetwork_logWithLevel:logLevel - messageCode:messageCode - message:message - contexts:contexts]; - return; - } - if (_isDebugModeEnabled || logLevel == kFIRNetworkLogLevelError || - logLevel == kFIRNetworkLogLevelWarning || logLevel == kFIRNetworkLogLevelInfo) { - NSString *formattedMessage = FIRStringWithLogMessage(message, logLevel, contexts); - NSLog(@"%@", formattedMessage); - FIRLogBasic((FIRLoggerLevel)logLevel, kFIRLoggerCore, - [NSString stringWithFormat:@"I-NET%06ld", (long)messageCode], formattedMessage, - NULL); - } -} - -- (void)firNetwork_logWithLevel:(FIRNetworkLogLevel)logLevel - messageCode:(FIRNetworkMessageCode)messageCode - message:(NSString *)message - context:(id)context { - if (_loggerDelegate) { - [_loggerDelegate firNetwork_logWithLevel:logLevel - messageCode:messageCode - message:message - context:context]; - return; - } - NSArray *contexts = context ? @[ context ] : @[]; - [self firNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:contexts]; -} - -- (void)firNetwork_logWithLevel:(FIRNetworkLogLevel)logLevel - messageCode:(FIRNetworkMessageCode)messageCode - message:(NSString *)message { - if (_loggerDelegate) { - [_loggerDelegate firNetwork_logWithLevel:logLevel messageCode:messageCode message:message]; - return; - } - [self firNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:@[]]; -} - -/// Returns a string for the given log level (e.g. kFIRNetworkLogLevelError -> @"ERROR"). -static NSString *FIRLogLevelDescriptionFromLogLevel(FIRNetworkLogLevel logLevel) { - static NSDictionary *levelNames = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - levelNames = @{ - @(kFIRNetworkLogLevelError) : @"ERROR", - @(kFIRNetworkLogLevelWarning) : @"WARNING", - @(kFIRNetworkLogLevelInfo) : @"INFO", - @(kFIRNetworkLogLevelDebug) : @"DEBUG" - }; - }); - return levelNames[@(logLevel)]; -} - -/// Returns a formatted string to be used for console logging. -static NSString *FIRStringWithLogMessage(NSString *message, - FIRNetworkLogLevel logLevel, - NSArray *contexts) { - if (!message) { - message = @"(Message was nil)"; - } else if (!message.length) { - message = @"(Message was empty)"; - } - NSMutableString *result = [[NSMutableString alloc] - initWithFormat:@"<%@/%@> %@", kFIRNetworkLogTag, FIRLogLevelDescriptionFromLogLevel(logLevel), - message]; - - if (!contexts.count) { - return result; - } - - NSMutableArray *formattedContexts = [[NSMutableArray alloc] init]; - for (id item in contexts) { - [formattedContexts addObject:(item != [NSNull null] ? item : @"(nil)")]; - } - - [result appendString:@": "]; - [result appendString:[formattedContexts componentsJoinedByString:@", "]]; - return result; -} - -@end diff --git a/Firebase/Core/FIRNetworkConstants.m b/Firebase/Core/FIRNetworkConstants.m deleted file mode 100644 index c958201..0000000 --- a/Firebase/Core/FIRNetworkConstants.m +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2017 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 "Private/FIRNetworkConstants.h" - -#import - -NSString *const kFIRNetworkBackgroundSessionConfigIDPrefix = - @"com.firebase.network.background-upload"; -NSString *const kFIRNetworkApplicationSupportSubdirectory = @"Firebase/Network"; -NSString *const kFIRNetworkTempDirectoryName = @"FIRNetworkTemporaryDirectory"; -const NSTimeInterval kFIRNetworkTempFolderExpireTime = 60 * 60; // 1 hour -const NSTimeInterval kFIRNetworkTimeOutInterval = 60; // 1 minute. -NSString *const kFIRNetworkReachabilityHost = @"app-measurement.com"; -NSString *const kFIRNetworkErrorContext = @"Context"; - -const int kFIRNetworkHTTPStatusOK = 200; -const int kFIRNetworkHTTPStatusNoContent = 204; -const int kFIRNetworkHTTPStatusCodeMultipleChoices = 300; -const int kFIRNetworkHTTPStatusCodeMovedPermanently = 301; -const int kFIRNetworkHTTPStatusCodeFound = 302; -const int kFIRNetworkHTTPStatusCodeNotModified = 304; -const int kFIRNetworkHTTPStatusCodeMovedTemporarily = 307; -const int kFIRNetworkHTTPStatusCodeNotFound = 404; -const int kFIRNetworkHTTPStatusCodeCannotAcceptTraffic = 429; -const int kFIRNetworkHTTPStatusCodeUnavailable = 503; - -NSString *const kFIRNetworkErrorDomain = @"com.firebase.network.ErrorDomain"; diff --git a/Firebase/Core/FIRNetworkURLSession.m b/Firebase/Core/FIRNetworkURLSession.m deleted file mode 100644 index 470d3e9..0000000 --- a/Firebase/Core/FIRNetworkURLSession.m +++ /dev/null @@ -1,669 +0,0 @@ -// Copyright 2017 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 - -#import "Private/FIRNetworkURLSession.h" - -#import "Private/FIRLogger.h" -#import "Private/FIRMutableDictionary.h" -#import "Private/FIRNetworkConstants.h" -#import "Private/FIRNetworkMessageCode.h" - -@implementation FIRNetworkURLSession { - /// The handler to be called when the request completes or error has occurs. - FIRNetworkURLSessionCompletionHandler _completionHandler; - - /// Session ID generated randomly with a fixed prefix. - NSString *_sessionID; - - /// The session configuration. - NSURLSessionConfiguration *_sessionConfig; - - /// The path to the directory where all temporary files are stored before uploading. - NSURL *_networkDirectoryURL; - - /// The downloaded data from fetching. - NSData *_downloadedData; - - /// The path to the temporary file which stores the uploading data. - NSURL *_uploadingFileURL; - - /// The current request. - NSURLRequest *_request; -} - -#pragma mark - Init - -- (instancetype)initWithNetworkLoggerDelegate:(id)networkLoggerDelegate { - self = [super init]; - if (self) { - // Create URL to the directory where all temporary files to upload have to be stored. - NSArray *paths = - NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); - NSString *applicationSupportDirectory = paths.firstObject; - NSArray *tempPathComponents = @[ - applicationSupportDirectory, kFIRNetworkApplicationSupportSubdirectory, - kFIRNetworkTempDirectoryName - ]; - _networkDirectoryURL = [NSURL fileURLWithPathComponents:tempPathComponents]; - _sessionID = [NSString stringWithFormat:@"%@-%@", kFIRNetworkBackgroundSessionConfigIDPrefix, - [[NSUUID UUID] UUIDString]]; - _loggerDelegate = networkLoggerDelegate; - } - return self; -} - -#pragma mark - External Methods - -#pragma mark - To be called from AppDelegate - -+ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID - completionHandler: - (FIRNetworkSystemCompletionHandler)systemCompletionHandler { - // The session may not be FIRAnalytics background. Ignore those that do not have the prefix. - if (![sessionID hasPrefix:kFIRNetworkBackgroundSessionConfigIDPrefix]) { - return; - } - FIRNetworkURLSession *fetcher = [self fetcherWithSessionIdentifier:sessionID]; - if (fetcher != nil) { - [fetcher addSystemCompletionHandler:systemCompletionHandler forSession:sessionID]; - } else { - FIRLogError(kFIRLoggerCore, - [NSString stringWithFormat:@"I-NET%06ld", (long)kFIRNetworkMessageCodeNetwork003], - @"Failed to retrieve background session with ID %@ after app is relaunched.", - sessionID); - } -} - -#pragma mark - External Methods - -/// Sends an async POST request using NSURLSession for iOS >= 7.0, and returns an ID of the -/// connection. -- (NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request - completionHandler:(FIRNetworkURLSessionCompletionHandler)handler { - // NSURLSessionUploadTask does not work with NSData in the background. - // To avoid this issue, write the data to a temporary file to upload it. - // Make a temporary file with the data subset. - _uploadingFileURL = [self temporaryFilePathWithSessionID:_sessionID]; - NSError *writeError; - NSURLSessionUploadTask *postRequestTask; - NSURLSession *session; - BOOL didWriteFile = NO; - - // Clean up the entire temp folder to avoid temp files that remain in case the previous session - // crashed and did not clean up. - [self maybeRemoveTempFilesAtURL:_networkDirectoryURL - expiringTime:kFIRNetworkTempFolderExpireTime]; - - // If there is no background network enabled, no need to write to file. This will allow default - // network session which runs on the foreground. - if (_backgroundNetworkEnabled && [self ensureTemporaryDirectoryExists]) { - didWriteFile = [request.HTTPBody writeToFile:_uploadingFileURL.path - options:NSDataWritingAtomic - error:&writeError]; - - if (writeError) { - [_loggerDelegate firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeURLSession000 - message:@"Failed to write request data to file" - context:writeError]; - } - } - - if (didWriteFile) { - // Exclude this file from backing up to iTunes. There are conflicting reports that excluding - // directory from backing up does not excluding files of that directory from backing up. - [self excludeFromBackupForURL:_uploadingFileURL]; - - _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID]; - [self populateSessionConfig:_sessionConfig withRequest:request]; - session = [NSURLSession sessionWithConfiguration:_sessionConfig - delegate:self - delegateQueue:[NSOperationQueue mainQueue]]; - postRequestTask = [session uploadTaskWithRequest:request fromFile:_uploadingFileURL]; - } else { - // If we cannot write to file, just send it in the foreground. - _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; - [self populateSessionConfig:_sessionConfig withRequest:request]; - _sessionConfig.URLCache = nil; - session = [NSURLSession sessionWithConfiguration:_sessionConfig - delegate:self - delegateQueue:[NSOperationQueue mainQueue]]; - postRequestTask = [session uploadTaskWithRequest:request fromData:request.HTTPBody]; - } - - if (!session || !postRequestTask) { - NSError *error = [[NSError alloc] - initWithDomain:kFIRNetworkErrorDomain - code:FIRErrorCodeNetworkRequestCreation - userInfo:@{kFIRNetworkErrorContext : @"Cannot create network session"}]; - [self callCompletionHandler:handler withResponse:nil data:nil error:error]; - return nil; - } - - // Save the session into memory. - NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIDToFetcherMap]; - [sessionIdentifierToFetcherMap setObject:self forKey:_sessionID]; - - _request = [request copy]; - - // Store completion handler because background session does not accept handler block but custom - // delegate. - _completionHandler = [handler copy]; - [postRequestTask resume]; - - return _sessionID; -} - -/// Sends an async GET request using NSURLSession for iOS >= 7.0, and returns an ID of the session. -- (NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request - completionHandler:(FIRNetworkURLSessionCompletionHandler)handler { - if (_backgroundNetworkEnabled) { - _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID]; - } else { - _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; - } - - [self populateSessionConfig:_sessionConfig withRequest:request]; - - // Do not cache the GET request. - _sessionConfig.URLCache = nil; - - NSURLSession *session = [NSURLSession sessionWithConfiguration:_sessionConfig - delegate:self - delegateQueue:[NSOperationQueue mainQueue]]; - NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request]; - - if (!session || !downloadTask) { - NSError *error = [[NSError alloc] - initWithDomain:kFIRNetworkErrorDomain - code:FIRErrorCodeNetworkRequestCreation - userInfo:@{kFIRNetworkErrorContext : @"Cannot create network session"}]; - [self callCompletionHandler:handler withResponse:nil data:nil error:error]; - return nil; - } - - // Save the session into memory. - NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIDToFetcherMap]; - [sessionIdentifierToFetcherMap setObject:self forKey:_sessionID]; - - _request = [request copy]; - - _completionHandler = [handler copy]; - [downloadTask resume]; - - return _sessionID; -} - -#pragma mark - NSURLSessionTaskDelegate - -/// Called by the NSURLSession once the download task is completed. The file is saved in the -/// provided URL so we need to read the data and store into _downloadedData. Once the session is -/// completed, URLSession:task:didCompleteWithError will be called and the completion handler will -/// be called with the downloaded data. -- (void)URLSession:(NSURLSession *)session - downloadTask:(NSURLSessionDownloadTask *)task - didFinishDownloadingToURL:(NSURL *)url { - if (!url.path) { - [_loggerDelegate - firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeURLSession001 - message:@"Unable to read downloaded data from empty temp path"]; - _downloadedData = nil; - return; - } - - NSError *error; - _downloadedData = [NSData dataWithContentsOfFile:url.path options:0 error:&error]; - - if (error) { - [_loggerDelegate firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeURLSession002 - message:@"Cannot read the content of downloaded data" - context:error]; - _downloadedData = nil; - } -} - -#if TARGET_OS_IOS || TARGET_OS_TV -- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { - [_loggerDelegate firNetwork_logWithLevel:kFIRNetworkLogLevelDebug - messageCode:kFIRNetworkMessageCodeURLSession003 - message:@"Background session finished" - context:session.configuration.identifier]; - [self callSystemCompletionHandler:session.configuration.identifier]; -} -#endif - -- (void)URLSession:(NSURLSession *)session - task:(NSURLSessionTask *)task - didCompleteWithError:(NSError *)error { - // Avoid any chance of recursive behavior leading to it being used repeatedly. - FIRNetworkURLSessionCompletionHandler handler = _completionHandler; - _completionHandler = nil; - - if (task.response) { - // The following assertion should always be true for HTTP requests, see https://goo.gl/gVLxT7. - NSAssert([task.response isKindOfClass:[NSHTTPURLResponse class]], @"URL response must be HTTP"); - - // The server responded so ignore the error created by the system. - error = nil; - } else if (!error) { - error = [[NSError alloc] - initWithDomain:kFIRNetworkErrorDomain - code:FIRErrorCodeNetworkInvalidResponse - userInfo:@{kFIRNetworkErrorContext : @"Network Error: Empty network response"}]; - } - - [self callCompletionHandler:handler - withResponse:(NSHTTPURLResponse *)task.response - data:_downloadedData - error:error]; - - // Remove the temp file to avoid trashing devices with lots of temp files. - [self removeTempItemAtURL:_uploadingFileURL]; - - // Try to clean up stale files again. - [self maybeRemoveTempFilesAtURL:_networkDirectoryURL - expiringTime:kFIRNetworkTempFolderExpireTime]; -} - -- (void)URLSession:(NSURLSession *)session - task:(NSURLSessionTask *)task - didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge - completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, - NSURLCredential *credential))completionHandler { - // The handling is modeled after GTMSessionFetcher. - if ([challenge.protectionSpace.authenticationMethod - isEqualToString:NSURLAuthenticationMethodServerTrust]) { - SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; - if (serverTrust == NULL) { - [_loggerDelegate firNetwork_logWithLevel:kFIRNetworkLogLevelDebug - messageCode:kFIRNetworkMessageCodeURLSession004 - message:@"Received empty server trust for host. Host" - context:_request.URL]; - completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); - return; - } - NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; - if (!credential) { - [_loggerDelegate firNetwork_logWithLevel:kFIRNetworkLogLevelWarning - messageCode:kFIRNetworkMessageCodeURLSession005 - message:@"Unable to verify server identity. Host" - context:_request.URL]; - completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); - return; - } - - [_loggerDelegate firNetwork_logWithLevel:kFIRNetworkLogLevelDebug - messageCode:kFIRNetworkMessageCodeURLSession006 - message:@"Received SSL challenge for host. Host" - context:_request.URL]; - - void (^callback)(BOOL) = ^(BOOL allow) { - if (allow) { - completionHandler(NSURLSessionAuthChallengeUseCredential, credential); - } else { - [self->_loggerDelegate - firNetwork_logWithLevel:kFIRNetworkLogLevelDebug - messageCode:kFIRNetworkMessageCodeURLSession007 - message:@"Cancelling authentication challenge for host. Host" - context:self->_request.URL]; - completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); - } - }; - - // Retain the trust object to avoid a SecTrustEvaluate() crash on iOS 7. - CFRetain(serverTrust); - - // Evaluate the certificate chain. - // - // The delegate queue may be the main thread. Trust evaluation could cause some - // blocking network activity, so we must evaluate async, as documented at - // https://developer.apple.com/library/ios/technotes/tn2232/ - dispatch_queue_t evaluateBackgroundQueue = - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - - dispatch_async(evaluateBackgroundQueue, ^{ - SecTrustResultType trustEval = kSecTrustResultInvalid; - BOOL shouldAllow; - OSStatus trustError; - - @synchronized([FIRNetworkURLSession class]) { - trustError = SecTrustEvaluate(serverTrust, &trustEval); - } - - if (trustError != errSecSuccess) { - [self->_loggerDelegate firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeURLSession008 - message:@"Cannot evaluate server trust. Error, host" - contexts:@[ @(trustError), self->_request.URL ]]; - shouldAllow = NO; - } else { - // Having a trust level "unspecified" by the user is the usual result, described at - // https://developer.apple.com/library/mac/qa/qa1360 - shouldAllow = - (trustEval == kSecTrustResultUnspecified || trustEval == kSecTrustResultProceed); - } - - // Call the call back with the permission. - callback(shouldAllow); - - CFRelease(serverTrust); - }); - return; - } - - // Default handling for other Auth Challenges. - completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); -} - -#pragma mark - Internal Methods - -/// Stores system completion handler with session ID as key. -- (void)addSystemCompletionHandler:(FIRNetworkSystemCompletionHandler)handler - forSession:(NSString *)identifier { - if (!handler) { - [_loggerDelegate - firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeURLSession009 - message:@"Cannot store nil system completion handler in network"]; - return; - } - - if (!identifier.length) { - [_loggerDelegate - firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeURLSession010 - message: - @"Cannot store system completion handler with empty network " - "session identifier"]; - return; - } - - FIRMutableDictionary *systemCompletionHandlers = - [[self class] sessionIDToSystemCompletionHandlerDictionary]; - if (systemCompletionHandlers[identifier]) { - [_loggerDelegate firNetwork_logWithLevel:kFIRNetworkLogLevelWarning - messageCode:kFIRNetworkMessageCodeURLSession011 - message:@"Got multiple system handlers for a single session ID" - context:identifier]; - } - - systemCompletionHandlers[identifier] = handler; -} - -/// Calls the system provided completion handler with the session ID stored in the dictionary. -/// The handler will be removed from the dictionary after being called. -- (void)callSystemCompletionHandler:(NSString *)identifier { - FIRMutableDictionary *systemCompletionHandlers = - [[self class] sessionIDToSystemCompletionHandlerDictionary]; - FIRNetworkSystemCompletionHandler handler = [systemCompletionHandlers objectForKey:identifier]; - - if (handler) { - [systemCompletionHandlers removeObjectForKey:identifier]; - - dispatch_async(dispatch_get_main_queue(), ^{ - handler(); - }); - } -} - -/// Sets or updates the session ID of this session. -- (void)setSessionID:(NSString *)sessionID { - _sessionID = [sessionID copy]; -} - -/// Creates a background session configuration with the session ID using the supported method. -- (NSURLSessionConfiguration *)backgroundSessionConfigWithSessionID:(NSString *)sessionID { -#if (TARGET_OS_OSX && defined(MAC_OS_X_VERSION_10_10) && \ - MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10) || \ - TARGET_OS_TV || \ - (TARGET_OS_IOS && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0) - - // iOS 8/10.10 builds require the new backgroundSessionConfiguration method name. - return [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionID]; - -#elif (TARGET_OS_OSX && defined(MAC_OS_X_VERSION_10_10) && \ - MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10) || \ - (TARGET_OS_IOS && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0) - - // Do a runtime check to avoid a deprecation warning about using - // +backgroundSessionConfiguration: on iOS 8. - if ([NSURLSessionConfiguration - respondsToSelector:@selector(backgroundSessionConfigurationWithIdentifier:)]) { - // Running on iOS 8+/OS X 10.10+. - return [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionID]; - } else { - // Running on iOS 7/OS X 10.9. - return [NSURLSessionConfiguration backgroundSessionConfiguration:sessionID]; - } - -#else - // Building with an SDK earlier than iOS 8/OS X 10.10. - return [NSURLSessionConfiguration backgroundSessionConfiguration:sessionID]; -#endif -} - -- (void)maybeRemoveTempFilesAtURL:(NSURL *)folderURL expiringTime:(NSTimeInterval)staleTime { - if (!folderURL.absoluteString.length) { - return; - } - - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSError *error = nil; - - NSArray *properties = @[ NSURLCreationDateKey ]; - NSArray *directoryContent = - [fileManager contentsOfDirectoryAtURL:folderURL - includingPropertiesForKeys:properties - options:NSDirectoryEnumerationSkipsSubdirectoryDescendants - error:&error]; - if (error && error.code != NSFileReadNoSuchFileError) { - [_loggerDelegate - firNetwork_logWithLevel:kFIRNetworkLogLevelDebug - messageCode:kFIRNetworkMessageCodeURLSession012 - message:@"Cannot get files from the temporary network folder. Error" - context:error]; - return; - } - - if (!directoryContent.count) { - return; - } - - NSTimeInterval now = [NSDate date].timeIntervalSince1970; - for (NSURL *tempFile in directoryContent) { - NSDate *creationDate; - BOOL getCreationDate = - [tempFile getResourceValue:&creationDate forKey:NSURLCreationDateKey error:NULL]; - if (!getCreationDate) { - continue; - } - NSTimeInterval creationTimeInterval = creationDate.timeIntervalSince1970; - if (fabs(now - creationTimeInterval) > staleTime) { - [self removeTempItemAtURL:tempFile]; - } - } -} - -/// Removes the temporary file written to disk for sending the request. It has to be cleaned up -/// after the session is done. -- (void)removeTempItemAtURL:(NSURL *)fileURL { - if (!fileURL.absoluteString.length) { - return; - } - - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSError *error = nil; - - if (![fileManager removeItemAtURL:fileURL error:&error] && error.code != NSFileNoSuchFileError) { - [_loggerDelegate - firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeURLSession013 - message:@"Failed to remove temporary uploading data file. Error" - context:error.localizedDescription]; - } -} - -/// Gets the fetcher with the session ID. -+ (instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier { - NSMapTable *sessionIdentifierToFetcherMap = [self sessionIDToFetcherMap]; - FIRNetworkURLSession *session = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier]; - if (!session && [sessionIdentifier hasPrefix:kFIRNetworkBackgroundSessionConfigIDPrefix]) { - session = [[FIRNetworkURLSession alloc] initWithNetworkLoggerDelegate:nil]; - [session setSessionID:sessionIdentifier]; - [sessionIdentifierToFetcherMap setObject:session forKey:sessionIdentifier]; - } - return session; -} - -/// Returns a map of the fetcher by session ID. Creates a map if it is not created. -+ (NSMapTable *)sessionIDToFetcherMap { - static NSMapTable *sessionIDToFetcherMap; - - static dispatch_once_t sessionMapOnceToken; - dispatch_once(&sessionMapOnceToken, ^{ - sessionIDToFetcherMap = [NSMapTable strongToWeakObjectsMapTable]; - }); - return sessionIDToFetcherMap; -} - -/// Returns a map of system provided completion handler by session ID. Creates a map if it is not -/// created. -+ (FIRMutableDictionary *)sessionIDToSystemCompletionHandlerDictionary { - static FIRMutableDictionary *systemCompletionHandlers; - - static dispatch_once_t systemCompletionHandlerOnceToken; - dispatch_once(&systemCompletionHandlerOnceToken, ^{ - systemCompletionHandlers = [[FIRMutableDictionary alloc] init]; - }); - return systemCompletionHandlers; -} - -- (NSURL *)temporaryFilePathWithSessionID:(NSString *)sessionID { - NSString *tempName = [NSString stringWithFormat:@"FIRUpload_temp_%@", sessionID]; - return [_networkDirectoryURL URLByAppendingPathComponent:tempName]; -} - -/// Makes sure that the directory to store temp files exists. If not, tries to create it and returns -/// YES. If there is anything wrong, returns NO. -- (BOOL)ensureTemporaryDirectoryExists { - NSFileManager *fileManager = [NSFileManager defaultManager]; - NSError *error = nil; - - // Create a temporary directory if it does not exist or was deleted. - if ([_networkDirectoryURL checkResourceIsReachableAndReturnError:&error]) { - return YES; - } - - if (error && error.code != NSFileReadNoSuchFileError) { - [_loggerDelegate - firNetwork_logWithLevel:kFIRNetworkLogLevelWarning - messageCode:kFIRNetworkMessageCodeURLSession014 - message:@"Error while trying to access Network temp folder. Error" - context:error]; - } - - NSError *writeError = nil; - - [fileManager createDirectoryAtURL:_networkDirectoryURL - withIntermediateDirectories:YES - attributes:nil - error:&writeError]; - if (writeError) { - [_loggerDelegate firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeURLSession015 - message:@"Cannot create temporary directory. Error" - context:writeError]; - return NO; - } - - // Set the iCloud exclusion attribute on the Documents URL. - [self excludeFromBackupForURL:_networkDirectoryURL]; - - return YES; -} - -- (void)excludeFromBackupForURL:(NSURL *)url { - if (!url.path) { - return; - } - - // Set the iCloud exclusion attribute on the Documents URL. - NSError *preventBackupError = nil; - [url setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:&preventBackupError]; - if (preventBackupError) { - [_loggerDelegate firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeURLSession016 - message:@"Cannot exclude temporary folder from iTunes backup"]; - } -} - -- (void)URLSession:(NSURLSession *)session - task:(NSURLSessionTask *)task - willPerformHTTPRedirection:(NSHTTPURLResponse *)response - newRequest:(NSURLRequest *)request - completionHandler:(void (^)(NSURLRequest *))completionHandler { - NSArray *nonAllowedRedirectionCodes = @[ - @(kFIRNetworkHTTPStatusCodeFound), @(kFIRNetworkHTTPStatusCodeMovedPermanently), - @(kFIRNetworkHTTPStatusCodeMovedTemporarily), @(kFIRNetworkHTTPStatusCodeMultipleChoices) - ]; - - // Allow those not in the non allowed list to be followed. - if (![nonAllowedRedirectionCodes containsObject:@(response.statusCode)]) { - completionHandler(request); - return; - } - - // Do not allow redirection if the response code is in the non-allowed list. - NSURLRequest *newRequest = request; - - if (response) { - newRequest = nil; - } - - completionHandler(newRequest); -} - -#pragma mark - Helper Methods - -- (void)callCompletionHandler:(FIRNetworkURLSessionCompletionHandler)handler - withResponse:(NSHTTPURLResponse *)response - data:(NSData *)data - error:(NSError *)error { - if (error) { - [_loggerDelegate firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeURLSession017 - message:@"Encounter network error. Code, error" - contexts:@[ @(error.code), error ]]; - } - - if (handler) { - dispatch_async(dispatch_get_main_queue(), ^{ - handler(response, data, self->_sessionID, error); - }); - } -} - -- (void)populateSessionConfig:(NSURLSessionConfiguration *)sessionConfig - withRequest:(NSURLRequest *)request { - sessionConfig.HTTPAdditionalHeaders = request.allHTTPHeaderFields; - sessionConfig.timeoutIntervalForRequest = request.timeoutInterval; - sessionConfig.timeoutIntervalForResource = request.timeoutInterval; - sessionConfig.requestCachePolicy = request.cachePolicy; -} - -@end diff --git a/Firebase/Core/FIRReachabilityChecker.m b/Firebase/Core/FIRReachabilityChecker.m deleted file mode 100644 index cac87ff..0000000 --- a/Firebase/Core/FIRReachabilityChecker.m +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2017 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 - -#import "Private/FIRReachabilityChecker+Internal.h" -#import "Private/FIRReachabilityChecker.h" - -#import "Private/FIRLogger.h" -#import "Private/FIRNetwork.h" -#import "Private/FIRNetworkMessageCode.h" - -static void ReachabilityCallback(SCNetworkReachabilityRef reachability, - SCNetworkReachabilityFlags flags, - void *info); - -static const struct FIRReachabilityApi kFIRDefaultReachabilityApi = { - SCNetworkReachabilityCreateWithName, - SCNetworkReachabilitySetCallback, - SCNetworkReachabilityScheduleWithRunLoop, - SCNetworkReachabilityUnscheduleFromRunLoop, - CFRelease, -}; - -static NSString *const kFIRReachabilityUnknownStatus = @"Unknown"; -static NSString *const kFIRReachabilityConnectedStatus = @"Connected"; -static NSString *const kFIRReachabilityDisconnectedStatus = @"Disconnected"; - -@interface FIRReachabilityChecker () - -@property(nonatomic, assign) const struct FIRReachabilityApi *reachabilityApi; -@property(nonatomic, assign) FIRReachabilityStatus reachabilityStatus; -@property(nonatomic, copy) NSString *host; -@property(nonatomic, assign) SCNetworkReachabilityRef reachability; - -@end - -@implementation FIRReachabilityChecker - -@synthesize reachabilityApi = reachabilityApi_; -@synthesize reachability = reachability_; - -- (const struct FIRReachabilityApi *)reachabilityApi { - return reachabilityApi_; -} - -- (void)setReachabilityApi:(const struct FIRReachabilityApi *)reachabilityApi { - if (reachability_) { - NSString *message = - @"Cannot change reachability API while reachability is running. " - @"Call stop first."; - [loggerDelegate_ firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeReachabilityChecker000 - message:message]; - return; - } - reachabilityApi_ = reachabilityApi; -} - -@synthesize reachabilityStatus = reachabilityStatus_; -@synthesize host = host_; -@synthesize reachabilityDelegate = reachabilityDelegate_; -@synthesize loggerDelegate = loggerDelegate_; - -- (BOOL)isActive { - return reachability_ != nil; -} - -- (void)setReachabilityDelegate:(id)reachabilityDelegate { - if (reachabilityDelegate && - (![(NSObject *)reachabilityDelegate conformsToProtocol:@protocol(FIRReachabilityDelegate)])) { - FIRLogError(kFIRLoggerCore, - [NSString stringWithFormat:@"I-NET%06ld", - (long)kFIRNetworkMessageCodeReachabilityChecker005], - @"Reachability delegate doesn't conform to Reachability protocol."); - return; - } - reachabilityDelegate_ = reachabilityDelegate; -} - -- (void)setLoggerDelegate:(id)loggerDelegate { - if (loggerDelegate && - (![(NSObject *)loggerDelegate conformsToProtocol:@protocol(FIRNetworkLoggerDelegate)])) { - FIRLogError(kFIRLoggerCore, - [NSString stringWithFormat:@"I-NET%06ld", - (long)kFIRNetworkMessageCodeReachabilityChecker006], - @"Reachability delegate doesn't conform to Logger protocol."); - return; - } - loggerDelegate_ = loggerDelegate; -} - -- (instancetype)initWithReachabilityDelegate:(id)reachabilityDelegate - loggerDelegate:(id)loggerDelegate - withHost:(NSString *)host { - self = [super init]; - - [self setLoggerDelegate:loggerDelegate]; - - if (!host || !host.length) { - [loggerDelegate_ firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeReachabilityChecker001 - message:@"Invalid host specified"]; - return nil; - } - if (self) { - [self setReachabilityDelegate:reachabilityDelegate]; - reachabilityApi_ = &kFIRDefaultReachabilityApi; - reachabilityStatus_ = kFIRReachabilityUnknown; - host_ = [host copy]; - reachability_ = nil; - } - return self; -} - -- (void)dealloc { - reachabilityDelegate_ = nil; - loggerDelegate_ = nil; - [self stop]; -} - -- (BOOL)start { - if (!reachability_) { - reachability_ = reachabilityApi_->createWithNameFn(kCFAllocatorDefault, [host_ UTF8String]); - if (!reachability_) { - return NO; - } - SCNetworkReachabilityContext context = { - 0, /* version */ - (__bridge void *)(self), /* info (passed as last parameter to reachability callback) */ - NULL, /* retain */ - NULL, /* release */ - NULL /* copyDescription */ - }; - if (!reachabilityApi_->setCallbackFn(reachability_, ReachabilityCallback, &context) || - !reachabilityApi_->scheduleWithRunLoopFn(reachability_, CFRunLoopGetMain(), - kCFRunLoopCommonModes)) { - reachabilityApi_->releaseFn(reachability_); - reachability_ = nil; - [loggerDelegate_ firNetwork_logWithLevel:kFIRNetworkLogLevelError - messageCode:kFIRNetworkMessageCodeReachabilityChecker002 - message:@"Failed to start reachability handle"]; - return NO; - } - } - [loggerDelegate_ firNetwork_logWithLevel:kFIRNetworkLogLevelDebug - messageCode:kFIRNetworkMessageCodeReachabilityChecker003 - message:@"Monitoring the network status"]; - return YES; -} - -- (void)stop { - if (reachability_) { - reachabilityStatus_ = kFIRReachabilityUnknown; - reachabilityApi_->unscheduleFromRunLoopFn(reachability_, CFRunLoopGetMain(), - kCFRunLoopCommonModes); - reachabilityApi_->releaseFn(reachability_); - reachability_ = nil; - } -} - -- (FIRReachabilityStatus)statusForFlags:(SCNetworkReachabilityFlags)flags { - FIRReachabilityStatus status = kFIRReachabilityNotReachable; - // If the Reachable flag is not set, we definitely don't have connectivity. - if (flags & kSCNetworkReachabilityFlagsReachable) { - // Reachable flag is set. Check further flags. - if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired)) { -// Connection required flag is not set, so we have connectivity. -#if TARGET_OS_IOS || TARGET_OS_TV - status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kFIRReachabilityViaCellular - : kFIRReachabilityViaWifi; -#elif TARGET_OS_OSX - status = kFIRReachabilityViaWifi; -#endif - } else if ((flags & (kSCNetworkReachabilityFlagsConnectionOnDemand | - kSCNetworkReachabilityFlagsConnectionOnTraffic)) && - !(flags & kSCNetworkReachabilityFlagsInterventionRequired)) { -// If the connection on demand or connection on traffic flag is set, and user intervention -// is not required, we have connectivity. -#if TARGET_OS_IOS || TARGET_OS_TV - status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kFIRReachabilityViaCellular - : kFIRReachabilityViaWifi; -#elif TARGET_OS_OSX - status = kFIRReachabilityViaWifi; -#endif - } - } - return status; -} - -- (void)reachabilityFlagsChanged:(SCNetworkReachabilityFlags)flags { - FIRReachabilityStatus status = [self statusForFlags:flags]; - if (reachabilityStatus_ != status) { - NSString *reachabilityStatusString; - if (status == kFIRReachabilityUnknown) { - reachabilityStatusString = kFIRReachabilityUnknownStatus; - } else { - reachabilityStatusString = (status == kFIRReachabilityNotReachable) - ? kFIRReachabilityDisconnectedStatus - : kFIRReachabilityConnectedStatus; - } - [loggerDelegate_ firNetwork_logWithLevel:kFIRNetworkLogLevelDebug - messageCode:kFIRNetworkMessageCodeReachabilityChecker004 - message:@"Network status has changed. Code, status" - contexts:@[ @(status), reachabilityStatusString ]]; - reachabilityStatus_ = status; - [reachabilityDelegate_ reachability:self statusChanged:reachabilityStatus_]; - } -} - -@end - -static void ReachabilityCallback(SCNetworkReachabilityRef reachability, - SCNetworkReachabilityFlags flags, - void *info) { - FIRReachabilityChecker *checker = (__bridge FIRReachabilityChecker *)info; - [checker reachabilityFlagsChanged:flags]; -} - -// This function used to be at the top of the file, but it was moved here -// as a workaround for a suspected compiler bug. When compiled in Release mode -// and run on an iOS device with WiFi disabled, the reachability code crashed -// when calling SCNetworkReachabilityScheduleWithRunLoop, or shortly thereafter. -// After unsuccessfully trying to diagnose the cause of the crash, it was -// discovered that moving this function to the end of the file magically fixed -// the crash. If you are going to edit this file, exercise caution and make sure -// to test thoroughly with an iOS device under various network conditions. -const NSString *FIRReachabilityStatusString(FIRReachabilityStatus status) { - switch (status) { - case kFIRReachabilityUnknown: - return @"Reachability Unknown"; - - case kFIRReachabilityNotReachable: - return @"Not reachable"; - - case kFIRReachabilityViaWifi: - return @"Reachable via Wifi"; - - case kFIRReachabilityViaCellular: - return @"Reachable via Cellular Data"; - - default: - return [NSString stringWithFormat:@"Invalid reachability status %d", (int)status]; - } -} diff --git a/Firebase/Core/FIRVersion.m b/Firebase/Core/FIRVersion.m index 97cd1bc..ec0f6ba 100644 --- a/Firebase/Core/FIRVersion.m +++ b/Firebase/Core/FIRVersion.m @@ -29,5 +29,5 @@ #define STR(x) STR_EXPAND(x) #define STR_EXPAND(x) #x -const unsigned char *const FIRVersionString = (const unsigned char *const)STR(Firebase_VERSION); -const unsigned char *const FIRCoreVersionString = (const unsigned char *const)STR(FIRCore_VERSION); +const char *const FIRVersionString = (const char *const)STR(Firebase_VERSION); +const char *const FIRCoreVersionString = (const char *const)STR(FIRCore_VERSION); diff --git a/Firebase/Core/Private/FIRMutableDictionary.h b/Firebase/Core/Private/FIRMutableDictionary.h deleted file mode 100644 index 6829dbc..0000000 --- a/Firebase/Core/Private/FIRMutableDictionary.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2017 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 - -/// A mutable dictionary that provides atomic accessor and mutators. -@interface FIRMutableDictionary : NSObject - -/// Returns an object given a key in the dictionary or nil if not found. -- (id)objectForKey:(id)key; - -/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. -- (void)setObject:(id)object forKey:(id)key; - -/// Removes the object given its session ID from the dictionary. -- (void)removeObjectForKey:(id)key; - -/// Removes all objects. -- (void)removeAllObjects; - -/// Returns the number of current objects in the dictionary. -- (NSUInteger)count; - -/// Returns an object given a key in the dictionary or nil if not found. -- (id)objectForKeyedSubscript:(id)key; - -/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. -- (void)setObject:(id)obj forKeyedSubscript:(id)key; - -/// Returns the immutable dictionary. -- (NSDictionary *)dictionary; - -@end diff --git a/Firebase/Core/Private/FIRNetwork.h b/Firebase/Core/Private/FIRNetwork.h deleted file mode 100644 index 32be35a..0000000 --- a/Firebase/Core/Private/FIRNetwork.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2017 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 - -#import "FIRNetworkConstants.h" -#import "FIRNetworkLoggerProtocol.h" -#import "FIRNetworkURLSession.h" - -/// Delegate protocol for FIRNetwork events. -@protocol FIRNetworkReachabilityDelegate - -/// Tells the delegate to handle events when the network reachability changes to connected or not -/// connected. -- (void)reachabilityDidChange; - -@end - -/// The Network component that provides network status and handles network requests and responses. -/// This is not thread safe. -/// -/// NOTE: -/// User must add FIRAnalytics handleEventsForBackgroundURLSessionID:completionHandler to the -/// AppDelegate application:handleEventsForBackgroundURLSession:completionHandler: -@interface FIRNetwork : NSObject - -/// Indicates if network connectivity is available. -@property(nonatomic, readonly, getter=isNetworkConnected) BOOL networkConnected; - -/// Indicates if there are any uploads in progress. -@property(nonatomic, readonly, getter=hasUploadInProgress) BOOL uploadInProgress; - -/// An optional delegate that can be used in the event when network reachability changes. -@property(nonatomic, weak) id reachabilityDelegate; - -/// An optional delegate that can be used to log messages, warnings or errors that occur in the -/// network operations. -@property(nonatomic, weak) id loggerDelegate; - -/// Indicates whether the logger should display debug messages. -@property(nonatomic, assign) BOOL isDebugModeEnabled; - -/// The time interval in seconds for the network request to timeout. -@property(nonatomic, assign) NSTimeInterval timeoutInterval; - -/// Initializes with the default reachability host. -- (instancetype)init; - -/// Initializes with a custom reachability host. -- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost; - -/// Handles events when background session with the given ID has finished. -+ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID - completionHandler:(FIRNetworkSystemCompletionHandler)completionHandler; - -/// Compresses and sends a POST request with the provided data to the URL. The session will be -/// background session if usingBackgroundSession is YES. Otherwise, the POST session is default -/// session. Returns a session ID or nil if an error occurs. -- (NSString *)postURL:(NSURL *)url - payload:(NSData *)payload - queue:(dispatch_queue_t)queue - usingBackgroundSession:(BOOL)usingBackgroundSession - completionHandler:(FIRNetworkCompletionHandler)handler; - -/// Sends a GET request with the provided data to the URL. The session will be background session -/// if usingBackgroundSession is YES. Otherwise, the GET session is default session. Returns a -/// session ID or nil if an error occurs. -- (NSString *)getURL:(NSURL *)url - headers:(NSDictionary *)headers - queue:(dispatch_queue_t)queue - usingBackgroundSession:(BOOL)usingBackgroundSession - completionHandler:(FIRNetworkCompletionHandler)handler; - -@end diff --git a/Firebase/Core/Private/FIRNetworkConstants.h b/Firebase/Core/Private/FIRNetworkConstants.h deleted file mode 100644 index d318581..0000000 --- a/Firebase/Core/Private/FIRNetworkConstants.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2017 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 - -/// Error codes in Firebase Network error domain. -/// Note: these error codes should never change. It would make it harder to decode the errors if -/// we inadvertently altered any of these codes in a future SDK version. -typedef NS_ENUM(NSInteger, FIRNetworkErrorCode) { - /// Unknown error. - FIRNetworkErrorCodeUnknown = 0, - /// Error occurs when the request URL is invalid. - FIRErrorCodeNetworkInvalidURL = 1, - /// Error occurs when request cannot be constructed. - FIRErrorCodeNetworkRequestCreation = 2, - /// Error occurs when payload cannot be compressed. - FIRErrorCodeNetworkPayloadCompression = 3, - /// Error occurs when session task cannot be created. - FIRErrorCodeNetworkSessionTaskCreation = 4, - /// Error occurs when there is no response. - FIRErrorCodeNetworkInvalidResponse = 5 -}; - -#pragma mark - Network constants - -/// The prefix of the ID of the background session. -extern NSString *const kFIRNetworkBackgroundSessionConfigIDPrefix; - -/// The sub directory to store the files of data that is being uploaded in the background. -extern NSString *const kFIRNetworkApplicationSupportSubdirectory; - -/// Name of the temporary directory that stores files for background uploading. -extern NSString *const kFIRNetworkTempDirectoryName; - -/// The period when the temporary uploading file can stay. -extern const NSTimeInterval kFIRNetworkTempFolderExpireTime; - -/// The default network request timeout interval. -extern const NSTimeInterval kFIRNetworkTimeOutInterval; - -/// The host to check the reachability of the network. -extern NSString *const kFIRNetworkReachabilityHost; - -/// The key to get the error context of the UserInfo. -extern NSString *const kFIRNetworkErrorContext; - -#pragma mark - Network Status Code - -extern const int kFIRNetworkHTTPStatusOK; -extern const int kFIRNetworkHTTPStatusNoContent; -extern const int kFIRNetworkHTTPStatusCodeMultipleChoices; -extern const int kFIRNetworkHTTPStatusCodeMovedPermanently; -extern const int kFIRNetworkHTTPStatusCodeFound; -extern const int kFIRNetworkHTTPStatusCodeNotModified; -extern const int kFIRNetworkHTTPStatusCodeMovedTemporarily; -extern const int kFIRNetworkHTTPStatusCodeNotFound; -extern const int kFIRNetworkHTTPStatusCodeCannotAcceptTraffic; -extern const int kFIRNetworkHTTPStatusCodeUnavailable; - -#pragma mark - Error Domain - -extern NSString *const kFIRNetworkErrorDomain; diff --git a/Firebase/Core/Private/FIRNetworkLoggerProtocol.h b/Firebase/Core/Private/FIRNetworkLoggerProtocol.h deleted file mode 100644 index add70fc..0000000 --- a/Firebase/Core/Private/FIRNetworkLoggerProtocol.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2017 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 - -#import "FIRLoggerLevel.h" -#import "FIRNetworkMessageCode.h" - -/// The log levels used by FIRNetworkLogger. -typedef NS_ENUM(NSInteger, FIRNetworkLogLevel) { - kFIRNetworkLogLevelError = FIRLoggerLevelError, - kFIRNetworkLogLevelWarning = FIRLoggerLevelWarning, - kFIRNetworkLogLevelInfo = FIRLoggerLevelInfo, - kFIRNetworkLogLevelDebug = FIRLoggerLevelDebug, -}; - -@protocol FIRNetworkLoggerDelegate - -@required -/// Tells the delegate to log a message with an array of contexts and the log level. -- (void)firNetwork_logWithLevel:(FIRNetworkLogLevel)logLevel - messageCode:(FIRNetworkMessageCode)messageCode - message:(NSString *)message - contexts:(NSArray *)contexts; - -/// Tells the delegate to log a message with a context and the log level. -- (void)firNetwork_logWithLevel:(FIRNetworkLogLevel)logLevel - messageCode:(FIRNetworkMessageCode)messageCode - message:(NSString *)message - context:(id)context; - -/// Tells the delegate to log a message with the log level. -- (void)firNetwork_logWithLevel:(FIRNetworkLogLevel)logLevel - messageCode:(FIRNetworkMessageCode)messageCode - message:(NSString *)message; - -@end diff --git a/Firebase/Core/Private/FIRNetworkMessageCode.h b/Firebase/Core/Private/FIRNetworkMessageCode.h deleted file mode 100644 index 30f562f..0000000 --- a/Firebase/Core/Private/FIRNetworkMessageCode.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2017 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. - */ - -// Make sure these codes do not overlap with any contained in the FIRAMessageCode enum. -typedef NS_ENUM(NSInteger, FIRNetworkMessageCode) { - // FIRNetwork.m - kFIRNetworkMessageCodeNetwork000 = 900000, // I-NET900000 - kFIRNetworkMessageCodeNetwork001 = 900001, // I-NET900001 - kFIRNetworkMessageCodeNetwork002 = 900002, // I-NET900002 - kFIRNetworkMessageCodeNetwork003 = 900003, // I-NET900003 - // FIRNetworkURLSession.m - kFIRNetworkMessageCodeURLSession000 = 901000, // I-NET901000 - kFIRNetworkMessageCodeURLSession001 = 901001, // I-NET901001 - kFIRNetworkMessageCodeURLSession002 = 901002, // I-NET901002 - kFIRNetworkMessageCodeURLSession003 = 901003, // I-NET901003 - kFIRNetworkMessageCodeURLSession004 = 901004, // I-NET901004 - kFIRNetworkMessageCodeURLSession005 = 901005, // I-NET901005 - kFIRNetworkMessageCodeURLSession006 = 901006, // I-NET901006 - kFIRNetworkMessageCodeURLSession007 = 901007, // I-NET901007 - kFIRNetworkMessageCodeURLSession008 = 901008, // I-NET901008 - kFIRNetworkMessageCodeURLSession009 = 901009, // I-NET901009 - kFIRNetworkMessageCodeURLSession010 = 901010, // I-NET901010 - kFIRNetworkMessageCodeURLSession011 = 901011, // I-NET901011 - kFIRNetworkMessageCodeURLSession012 = 901012, // I-NET901012 - kFIRNetworkMessageCodeURLSession013 = 901013, // I-NET901013 - kFIRNetworkMessageCodeURLSession014 = 901014, // I-NET901014 - kFIRNetworkMessageCodeURLSession015 = 901015, // I-NET901015 - kFIRNetworkMessageCodeURLSession016 = 901016, // I-NET901016 - kFIRNetworkMessageCodeURLSession017 = 901017, // I-NET901017 - kFIRNetworkMessageCodeURLSession018 = 901018, // I-NET901018 - // FIRReachabilityChecker.m - kFIRNetworkMessageCodeReachabilityChecker000 = 902000, // I-NET902000 - kFIRNetworkMessageCodeReachabilityChecker001 = 902001, // I-NET902001 - kFIRNetworkMessageCodeReachabilityChecker002 = 902002, // I-NET902002 - kFIRNetworkMessageCodeReachabilityChecker003 = 902003, // I-NET902003 - kFIRNetworkMessageCodeReachabilityChecker004 = 902004, // I-NET902004 - kFIRNetworkMessageCodeReachabilityChecker005 = 902005, // I-NET902005 - kFIRNetworkMessageCodeReachabilityChecker006 = 902006, // I-NET902006 -}; diff --git a/Firebase/Core/Private/FIRNetworkURLSession.h b/Firebase/Core/Private/FIRNetworkURLSession.h deleted file mode 100644 index a51b8a9..0000000 --- a/Firebase/Core/Private/FIRNetworkURLSession.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2017 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 - -#import "FIRNetworkLoggerProtocol.h" - -typedef void (^FIRNetworkCompletionHandler)(NSHTTPURLResponse *response, - NSData *data, - NSError *error); -typedef void (^FIRNetworkURLSessionCompletionHandler)(NSHTTPURLResponse *response, - NSData *data, - NSString *sessionID, - NSError *error); -typedef void (^FIRNetworkSystemCompletionHandler)(void); - -/// The protocol that uses NSURLSession for iOS >= 7.0 to handle requests and responses. -@interface FIRNetworkURLSession - : NSObject - -/// Indicates whether the background network is enabled. Default value is NO. -@property(nonatomic, getter=isBackgroundNetworkEnabled) BOOL backgroundNetworkEnabled; - -/// The logger delegate to log message, errors or warnings that occur during the network operations. -@property(nonatomic, weak) id loggerDelegate; - -/// Calls the system provided completion handler after the background session is finished. -+ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID - completionHandler:(FIRNetworkSystemCompletionHandler)completionHandler; - -/// Initializes with logger delegate. -- (instancetype)initWithNetworkLoggerDelegate:(id)networkLoggerDelegate - NS_DESIGNATED_INITIALIZER; - -- (instancetype)init NS_UNAVAILABLE; - -/// Sends an asynchronous POST request and calls the provided completion handler when the request -/// completes or when errors occur, and returns an ID of the session/connection. -- (NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request - completionHandler:(FIRNetworkURLSessionCompletionHandler)handler; - -/// Sends an asynchronous GET request and calls the provided completion handler when the request -/// completes or when errors occur, and returns an ID of the session. -- (NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request - completionHandler:(FIRNetworkURLSessionCompletionHandler)handler; - -@end diff --git a/Firebase/Core/Private/FIRReachabilityChecker+Internal.h b/Firebase/Core/Private/FIRReachabilityChecker+Internal.h deleted file mode 100644 index f82d103..0000000 --- a/Firebase/Core/Private/FIRReachabilityChecker+Internal.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2017 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 "FIRReachabilityChecker.h" - -typedef SCNetworkReachabilityRef (*FIRReachabilityCreateWithNameFn)(CFAllocatorRef allocator, - const char *host); - -typedef Boolean (*FIRReachabilitySetCallbackFn)(SCNetworkReachabilityRef target, - SCNetworkReachabilityCallBack callback, - SCNetworkReachabilityContext *context); -typedef Boolean (*FIRReachabilityScheduleWithRunLoopFn)(SCNetworkReachabilityRef target, - CFRunLoopRef runLoop, - CFStringRef runLoopMode); -typedef Boolean (*FIRReachabilityUnscheduleFromRunLoopFn)(SCNetworkReachabilityRef target, - CFRunLoopRef runLoop, - CFStringRef runLoopMode); - -typedef void (*FIRReachabilityReleaseFn)(CFTypeRef cf); - -struct FIRReachabilityApi { - FIRReachabilityCreateWithNameFn createWithNameFn; - FIRReachabilitySetCallbackFn setCallbackFn; - FIRReachabilityScheduleWithRunLoopFn scheduleWithRunLoopFn; - FIRReachabilityUnscheduleFromRunLoopFn unscheduleFromRunLoopFn; - FIRReachabilityReleaseFn releaseFn; -}; - -@interface FIRReachabilityChecker (Internal) - -- (const struct FIRReachabilityApi *)reachabilityApi; -- (void)setReachabilityApi:(const struct FIRReachabilityApi *)reachabilityApi; - -@end diff --git a/Firebase/Core/Private/FIRReachabilityChecker.h b/Firebase/Core/Private/FIRReachabilityChecker.h deleted file mode 100644 index 3a6a531..0000000 --- a/Firebase/Core/Private/FIRReachabilityChecker.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2017 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 -#import - -/// Reachability Status -typedef enum { - kFIRReachabilityUnknown, ///< Have not yet checked or been notified whether host is reachable. - kFIRReachabilityNotReachable, ///< Host is not reachable. - kFIRReachabilityViaWifi, ///< Host is reachable via Wifi. - kFIRReachabilityViaCellular, ///< Host is reachable via cellular. -} FIRReachabilityStatus; - -const NSString *FIRReachabilityStatusString(FIRReachabilityStatus status); - -@class FIRReachabilityChecker; -@protocol FIRNetworkLoggerDelegate; - -/// Google Analytics iOS Reachability Checker. -@protocol FIRReachabilityDelegate -@required -/// Called when network status has changed. -- (void)reachability:(FIRReachabilityChecker *)reachability - statusChanged:(FIRReachabilityStatus)status; -@end - -/// Google Analytics iOS Network Status Checker. -@interface FIRReachabilityChecker : NSObject - -/// The last known reachability status, or FIRReachabilityStatusUnknown if the -/// checker is not active. -@property(nonatomic, readonly) FIRReachabilityStatus reachabilityStatus; -/// The host to which reachability status is to be checked. -@property(nonatomic, copy, readonly) NSString *host; -/// The delegate to be notified of reachability status changes. -@property(nonatomic, weak) id reachabilityDelegate; -/// The delegate to be notified to log messages. -@property(nonatomic, weak) id loggerDelegate; -/// `YES` if the reachability checker is active, `NO` otherwise. -@property(nonatomic, readonly) BOOL isActive; - -/// Initialize the reachability checker. Note that you must call start to begin checking for and -/// receiving notifications about network status changes. -/// -/// @param reachabilityDelegate The delegate to be notified when reachability status to host -/// changes. -/// -/// @param loggerDelegate The delegate to send log messages to. -/// -/// @param host The name of the host. -/// -- (instancetype)initWithReachabilityDelegate:(id)reachabilityDelegate - loggerDelegate:(id)loggerDelegate - withHost:(NSString *)host; - -- (instancetype)init NS_UNAVAILABLE; - -/// Start checking for reachability to the specified host. This has no effect if the status -/// checker is already checking for connectivity. -/// -/// @return `YES` if initiating status checking was successful or the status checking has already -/// been initiated, `NO` otherwise. -- (BOOL)start; - -/// Stop checking for reachability to the specified host. This has no effect if the status -/// checker is not checking for connectivity. -- (void)stop; - -@end diff --git a/Firebase/Core/Private/FIRVersion.h b/Firebase/Core/Private/FIRVersion.h index cec0994..226efb1 100644 --- a/Firebase/Core/Private/FIRVersion.h +++ b/Firebase/Core/Private/FIRVersion.h @@ -17,7 +17,7 @@ #import /** The version of the Firebase SDK. */ -FOUNDATION_EXPORT const unsigned char *const FIRVersionString; +FOUNDATION_EXPORT const char *const FIRVersionString; /** The version of the FirebaseCore Component. */ -FOUNDATION_EXPORT const unsigned char *const FIRCoreVersionString; +FOUNDATION_EXPORT const char *const FIRCoreVersionString; diff --git a/Firebase/Core/Public/FIRLoggerLevel.h b/Firebase/Core/Public/FIRLoggerLevel.h index 8b6579f..e17e338 100644 --- a/Firebase/Core/Public/FIRLoggerLevel.h +++ b/Firebase/Core/Public/FIRLoggerLevel.h @@ -14,6 +14,9 @@ * limitations under the License. */ +// Note that importing GULLoggerLevel.h will lead to a non-modular header +// import error. + /** * The log levels used by internal logging. */ diff --git a/Firebase/Core/third_party/FIRAppEnvironmentUtil.h b/Firebase/Core/third_party/FIRAppEnvironmentUtil.h deleted file mode 100644 index 09ee504..0000000 --- a/Firebase/Core/third_party/FIRAppEnvironmentUtil.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2017 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 - -@interface FIRAppEnvironmentUtil : NSObject - -/// Indicates whether the app is from Apple Store or not. Returns NO if the app is on simulator, -/// development environment or sideloaded. -+ (BOOL)isFromAppStore; - -/// Indicates whether the app is a Testflight app. Returns YES if the app has sandbox receipt. -/// Returns NO otherwise. -+ (BOOL)isAppStoreReceiptSandbox; - -/// Indicates whether the app is on simulator or not at runtime depending on the device -/// architecture. -+ (BOOL)isSimulator; - -/// The current device model. Returns an empty string if device model cannot be retrieved. -+ (NSString *)deviceModel; - -/// The current operating system version. Returns an empty string if the system version cannot be -/// retrieved. -+ (NSString *)systemVersion; - -/// Indicates whether it is running inside an extension or an app. -+ (BOOL)isAppExtension; - -@end diff --git a/Firebase/Core/third_party/FIRAppEnvironmentUtil.m b/Firebase/Core/third_party/FIRAppEnvironmentUtil.m deleted file mode 100644 index be4e971..0000000 --- a/Firebase/Core/third_party/FIRAppEnvironmentUtil.m +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2017 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 - -#import "FIRAppEnvironmentUtil.h" - -#import -#import -#import - -/// The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from -/// the iPhoneOS or Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just -/// provide the definitions here. -#if TARGET_OS_SIMULATOR && !defined(LC_ENCRYPTION_INFO) -#define LC_ENCRYPTION_INFO 0x21 -struct encryption_info_command { - uint32_t cmd; - uint32_t cmdsize; - uint32_t cryptoff; - uint32_t cryptsize; - uint32_t cryptid; -}; -#endif - -@implementation FIRAppEnvironmentUtil - -/// A key for the Info.plist to enable or disable checking if the App Store is running in a sandbox. -/// This will affect your data integrity when using Firebase Analytics, as it will disable some -/// necessary checks. -static NSString *const kFIRAppStoreReceiptURLCheckEnabledKey = - @"FirebaseAppStoreReceiptURLCheckEnabled"; - -/// The file name of the sandbox receipt. This is available on iOS >= 8.0 -static NSString *const kFIRAIdentitySandboxReceiptFileName = @"sandboxReceipt"; - -/// The following copyright from Landon J. Fuller applies to the isAppEncrypted function. -/// -/// Copyright (c) 2017 Landon J. Fuller -/// All rights reserved. -/// -/// Permission is hereby granted, free of charge, to any person obtaining a copy of this software -/// and associated documentation files (the "Software"), to deal in the Software without -/// restriction, including without limitation the rights to use, copy, modify, merge, publish, -/// distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the -/// Software is furnished to do so, subject to the following conditions: -/// -/// The above copyright notice and this permission notice shall be included in all copies or -/// substantial portions of the Software. -/// -/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING -/// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -/// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -/// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -/// -/// Comment from iPhone Dev Wiki -/// Crack Prevention: -/// App Store binaries are signed by both their developer and Apple. This encrypts the binary so -/// that decryption keys are needed in order to make the binary readable. When iOS executes the -/// binary, the decryption keys are used to decrypt the binary into a readable state where it is -/// then loaded into memory and executed. iOS can tell the encryption status of a binary via the -/// cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If cryptid is a non-zero -/// value then the binary is encrypted. -/// -/// 'Cracking' works by letting the kernel decrypt the binary then siphoning the decrypted data into -/// a new binary file, resigning, and repackaging. This will only work on jailbroken devices as -/// codesignature validation has been removed. Resigning takes place because while the codesignature -/// doesn't have to be valid thanks to the jailbreak, it does have to be in place unless you have -/// AppSync or similar to disable codesignature checks. -/// -/// More information at Landon Fuller's blog -static BOOL isAppEncrypted() { - const struct mach_header *executableHeader = NULL; - for (uint32_t i = 0; i < _dyld_image_count(); i++) { - const struct mach_header *header = _dyld_get_image_header(i); - if (header && header->filetype == MH_EXECUTE) { - executableHeader = header; - break; - } - } - - if (!executableHeader) { - return NO; - } - - BOOL is64bit = (executableHeader->magic == MH_MAGIC_64); - uintptr_t cursor = (uintptr_t)executableHeader + - (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header)); - const struct segment_command *segmentCommand = NULL; - uint32_t i = 0; - - while (i++ < executableHeader->ncmds) { - segmentCommand = (struct segment_command *)cursor; - - if (!segmentCommand) { - continue; - } - - if ((!is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO) || - (is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO_64)) { - if (is64bit) { - struct encryption_info_command_64 *cryptCmd = - (struct encryption_info_command_64 *)segmentCommand; - return cryptCmd && cryptCmd->cryptid != 0; - } else { - struct encryption_info_command *cryptCmd = (struct encryption_info_command *)segmentCommand; - return cryptCmd && cryptCmd->cryptid != 0; - } - } - cursor += segmentCommand->cmdsize; - } - - return NO; -} - -+ (BOOL)isFromAppStore { - static dispatch_once_t isEncryptedOnce; - static BOOL isEncrypted = NO; - - dispatch_once(&isEncryptedOnce, ^{ - isEncrypted = isAppEncrypted(); - }); - - if ([FIRAppEnvironmentUtil isSimulator]) { - return NO; - } - - // If an app contain the sandboxReceipt file, it means its coming from TestFlight - // This must be checked before the SCInfo Folder check below since TestFlight apps may - // also have an SCInfo folder. - if ([FIRAppEnvironmentUtil isAppStoreReceiptSandbox]) { - return NO; - } - - if ([FIRAppEnvironmentUtil hasSCInfoFolder]) { - // When iTunes downloads a .ipa, it also gets a customized .sinf file which is added to the - // main SC_Info directory. - return YES; - } - - // For iOS >= 8.0, iTunesMetadata.plist is moved outside of the sandbox. Any attempt to read - // the iTunesMetadata.plist outside of the sandbox will be rejected by Apple. - // If the app does not contain the embedded.mobileprovision which is stripped out by Apple when - // the app is submitted to store, then it is highly likely that it is from Apple Store. - return isEncrypted && ![FIRAppEnvironmentUtil hasEmbeddedMobileProvision]; -} - -+ (BOOL)isAppStoreReceiptSandbox { - // Since checking the App Store's receipt URL can be memory intensive, check the option in the - // Info.plist if developers opted out of this check. - id enableSandboxCheck = - [[NSBundle mainBundle] objectForInfoDictionaryKey:kFIRAppStoreReceiptURLCheckEnabledKey]; - if (enableSandboxCheck && [enableSandboxCheck isKindOfClass:[NSNumber class]] && - ![enableSandboxCheck boolValue]) { - return NO; - } - - NSURL *appStoreReceiptURL = [NSBundle mainBundle].appStoreReceiptURL; - NSString *appStoreReceiptFileName = appStoreReceiptURL.lastPathComponent; - return [appStoreReceiptFileName isEqualToString:kFIRAIdentitySandboxReceiptFileName]; -} - -+ (BOOL)hasEmbeddedMobileProvision { -#if TARGET_OS_IOS || TARGET_OS_TV - return [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"].length > 0; -#elif TARGET_OS_OSX - return NO; -#endif -} - -+ (BOOL)isSimulator { -#if TARGET_OS_IOS || TARGET_OS_TV - NSString *platform = [FIRAppEnvironmentUtil deviceModel]; - return [platform isEqual:@"x86_64"] || [platform isEqual:@"i386"]; -#elif TARGET_OS_OSX - return NO; -#endif -} - -+ (NSString *)deviceModel { - static dispatch_once_t once; - static NSString *deviceModel; - - dispatch_once(&once, ^{ - struct utsname systemInfo; - if (uname(&systemInfo) == 0) { - deviceModel = [NSString stringWithUTF8String:systemInfo.machine]; - } - }); - return deviceModel; -} - -+ (NSString *)systemVersion { - // Assemble the systemVersion, excluding the patch version if it's 0. - NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion; - NSMutableString *versionString = [[NSMutableString alloc] - initWithFormat:@"%ld.%ld", (long)osVersion.majorVersion, (long)osVersion.minorVersion]; - if (osVersion.patchVersion != 0) { - [versionString appendFormat:@".%ld", (long)osVersion.patchVersion]; - } - - return versionString; -} - -+ (BOOL)isAppExtension { -#if TARGET_OS_IOS || TARGET_OS_TV - // Documented by Apple - BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; - return appExtension; -#elif TARGET_OS_OSX - return NO; -#endif -} - -#pragma mark - Helper methods - -+ (BOOL)hasSCInfoFolder { -#if TARGET_OS_IOS || TARGET_OS_TV - NSString *bundlePath = [NSBundle mainBundle].bundlePath; - NSString *scInfoPath = [bundlePath stringByAppendingPathComponent:@"SC_Info"]; - return [[NSFileManager defaultManager] fileExistsAtPath:scInfoPath]; -#elif TARGET_OS_OSX - return NO; -#endif -} - -@end -- cgit v1.2.3