12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331 |
- /* Copyright 2014 Google Inc. All rights reserved.
- *
- * 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.
- */
-
- // GTMSessionFetcher is a wrapper around NSURLSession for http operations.
- //
- // What does this offer on top of of NSURLSession?
- //
- // - Block-style callbacks for useful functionality like progress rather
- // than delegate methods.
- // - Out-of-process uploads and downloads using NSURLSession, including
- // management of fetches after relaunch.
- // - Integration with GTMAppAuth for invisible management and refresh of
- // authorization tokens.
- // - Pretty-printed http logging.
- // - Cookies handling that does not interfere with or get interfered with
- // by WebKit cookies or on Mac by Safari and other apps.
- // - Credentials handling for the http operation.
- // - Rate-limiting and cookie grouping when fetchers are created with
- // GTMSessionFetcherService.
- //
- // If the bodyData or bodyFileURL property is set, then a POST request is assumed.
- //
- // Each fetcher is assumed to be for a one-shot fetch request; don't reuse the object
- // for a second fetch.
- //
- // The fetcher will be self-retained as long as a connection is pending.
- //
- // To keep user activity private, URLs must have an https scheme (unless the property
- // allowedInsecureSchemes is set to permit the scheme.)
- //
- // Callbacks will be released when the fetch completes or is stopped, so there is no need
- // to use weak self references in the callback blocks.
- //
- // Sample usage:
- //
- // _fetcherService = [[GTMSessionFetcherService alloc] init];
- //
- // GTMSessionFetcher *myFetcher = [_fetcherService fetcherWithURLString:myURLString];
- // myFetcher.retryEnabled = YES;
- // myFetcher.comment = @"First profile image";
- //
- // // Optionally specify a file URL or NSData for the request body to upload.
- // myFetcher.bodyData = [postString dataUsingEncoding:NSUTF8StringEncoding];
- //
- // [myFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
- // if (error != nil) {
- // // Server status code or network error.
- // //
- // // If the domain is kGTMSessionFetcherStatusDomain then the error code
- // // is a failure status from the server.
- // } else {
- // // Fetch succeeded.
- // }
- // }];
- //
- // There is also a beginFetch call that takes a pointer and selector for the completion handler;
- // a pointer and selector is a better style when the callback is a substantial, separate method.
- //
- // NOTE: Fetches may retrieve data from the server even though the server
- // returned an error, so the criteria for success is a non-nil error.
- // The completion handler is called when the server status is >= 300 with an NSError
- // having domain kGTMSessionFetcherStatusDomain and code set to the server status.
- //
- // Status codes are at <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>
- //
- //
- // Background session support:
- //
- // Out-of-process uploads and downloads may be created by setting the fetcher's
- // useBackgroundSession property. Data to be uploaded should be provided via
- // the uploadFileURL property; the download destination should be specified with
- // the destinationFileURL. NOTE: Background upload files should be in a location
- // that will be valid even after the device is restarted, so the file should not
- // be uploaded from a system temporary or cache directory.
- //
- // Background session transfers are slower, and should typically be used only
- // for very large downloads or uploads (hundreds of megabytes).
- //
- // When background sessions are used in iOS apps, the application delegate must
- // pass through the parameters from UIApplicationDelegate's
- // application:handleEventsForBackgroundURLSession:completionHandler: to the
- // fetcher class.
- //
- // When the application has been relaunched, it may also create a new fetcher
- // instance to handle completion of the transfers.
- //
- // - (void)application:(UIApplication *)application
- // handleEventsForBackgroundURLSession:(NSString *)identifier
- // completionHandler:(void (^)())completionHandler {
- // // Application was re-launched on completing an out-of-process download.
- //
- // // Pass the URLSession info related to this re-launch to the fetcher class.
- // [GTMSessionFetcher application:application
- // handleEventsForBackgroundURLSession:identifier
- // completionHandler:completionHandler];
- //
- // // Get a fetcher related to this re-launch and re-hook up a completionHandler to it.
- // GTMSessionFetcher *fetcher = [GTMSessionFetcher fetcherWithSessionIdentifier:identifier];
- // NSURL *destinationFileURL = fetcher.destinationFileURL;
- // fetcher.completionHandler = ^(NSData *data, NSError *error) {
- // [self downloadCompletedToFile:destinationFileURL error:error];
- // };
- // }
- //
- //
- // Threading and queue support:
- //
- // Networking always happens on a background thread; there is no advantage to
- // changing thread or queue to create or start a fetcher.
- //
- // Callbacks are run on the main thread; alternatively, the app may set the
- // fetcher's callbackQueue to a dispatch queue.
- //
- // Once the fetcher's beginFetch method has been called, the fetcher's methods and
- // properties may be accessed from any thread.
- //
- // Downloading to disk:
- //
- // To have downloaded data saved directly to disk, specify a file URL for the
- // destinationFileURL property.
- //
- // HTTP methods and headers:
- //
- // Alternative HTTP methods, like PUT, and custom headers can be specified by
- // creating the fetcher with an appropriate NSMutableURLRequest.
- //
- //
- // Caching:
- //
- // The fetcher avoids caching. That is best for API requests, but may hurt
- // repeat fetches of static data. Apps may enable a persistent disk cache by
- // customizing the config:
- //
- // fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher,
- // NSURLSessionConfiguration *config) {
- // config.URLCache = [NSURLCache sharedURLCache];
- // };
- //
- // Or use the standard system config to share cookie storage with web views
- // and to enable disk caching:
- //
- // fetcher.configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
- //
- //
- // Cookies:
- //
- // There are three supported mechanisms for remembering cookies between fetches.
- //
- // By default, a standalone GTMSessionFetcher uses a mutable array held
- // statically to track cookies for all instantiated fetchers. This avoids
- // cookies being set by servers for the application from interfering with
- // Safari and WebKit cookie settings, and vice versa.
- // The fetcher cookies are lost when the application quits.
- //
- // To rely instead on WebKit's global NSHTTPCookieStorage, set the fetcher's
- // cookieStorage property:
- // myFetcher.cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
- //
- // To share cookies with other apps, use the method introduced in iOS 9/OS X 10.11:
- // myFetcher.cookieStorage =
- // [NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:kMyCompanyContainedID];
- //
- // To ignore existing cookies and only have cookies related to the single fetch
- // be applied, make a temporary cookie storage object:
- // myFetcher.cookieStorage = [[GTMSessionCookieStorage alloc] init];
- //
- // Note: cookies set while following redirects will be sent to the server, as
- // the redirects are followed by the fetcher.
- //
- // To completely disable cookies, similar to setting cookieStorageMethod to
- // kGTMHTTPFetcherCookieStorageMethodNone, adjust the session configuration
- // appropriately in the fetcher or fetcher service:
- // fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher,
- // NSURLSessionConfiguration *config) {
- // config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
- // config.HTTPShouldSetCookies = NO;
- // };
- //
- // If the fetcher is created from a GTMSessionFetcherService object
- // then the cookie storage mechanism is set to use the cookie storage in the
- // service object rather than the static storage. Disabling cookies in the
- // session configuration set on a service object will disable cookies for all
- // fetchers created from that GTMSessionFetcherService object, since the session
- // configuration is propagated to the fetcher.
- //
- //
- // Monitoring data transfers.
- //
- // The fetcher supports a variety of properties for progress monitoring
- // progress with callback blocks.
- // GTMSessionFetcherSendProgressBlock sendProgressBlock
- // GTMSessionFetcherReceivedProgressBlock receivedProgressBlock
- // GTMSessionFetcherDownloadProgressBlock downloadProgressBlock
- //
- // If supplied by the server, the anticipated total download size is available
- // as [[myFetcher response] expectedContentLength] (and may be -1 for unknown
- // download sizes.)
- //
- //
- // Automatic retrying of fetches
- //
- // The fetcher can optionally create a timer and reattempt certain kinds of
- // fetch failures (status codes 408, request timeout; 502, gateway failure;
- // 503, service unavailable; 504, gateway timeout; networking errors
- // NSURLErrorTimedOut and NSURLErrorNetworkConnectionLost.) The user may
- // set a retry selector to customize the type of errors which will be retried.
- //
- // Retries are done in an exponential-backoff fashion (that is, after 1 second,
- // 2, 4, 8, and so on.)
- //
- // Enabling automatic retries looks like this:
- // myFetcher.retryEnabled = YES;
- //
- // With retries enabled, the completion callbacks are called only
- // when no more retries will be attempted. Calling the fetcher's stopFetching
- // method will terminate the retry timer, without the finished or failure
- // selectors being invoked.
- //
- // Optionally, the client may set the maximum retry interval:
- // myFetcher.maxRetryInterval = 60.0; // in seconds; default is 60 seconds
- // // for downloads, 600 for uploads
- //
- // Servers should never send a 400 or 500 status for errors that are retryable
- // by clients, as those values indicate permanent failures. In nearly all
- // cases, the default standard retry behavior is correct for clients, and no
- // custom client retry behavior is needed or appropriate. Servers that send
- // non-retryable status codes and expect the client to retry the request are
- // faulty.
- //
- // Still, the client may provide a block to determine if a status code or other
- // error should be retried. The block returns YES to set the retry timer or NO
- // to fail without additional fetch attempts.
- //
- // The retry method may return the |suggestedWillRetry| argument to get the
- // default retry behavior. Server status codes are present in the
- // error argument, and have the domain kGTMSessionFetcherStatusDomain. The
- // user's method may look something like this:
- //
- // myFetcher.retryBlock = ^(BOOL suggestedWillRetry, NSError *error,
- // GTMSessionFetcherRetryResponse response) {
- // // Perhaps examine error.domain and error.code, or fetcher.retryCount
- // //
- // // Respond with YES to start the retry timer, NO to proceed to the failure
- // // callback, or suggestedWillRetry to get default behavior for the
- // // current error domain and code values.
- // response(suggestedWillRetry);
- // };
-
-
- #import <Foundation/Foundation.h>
-
- #if TARGET_OS_IPHONE
- #import <UIKit/UIKit.h>
- #endif
- #if TARGET_OS_WATCH
- #import <WatchKit/WatchKit.h>
- #endif
-
- // By default it is stripped from non DEBUG builds. Developers can override
- // this in their project settings.
- #ifndef STRIP_GTM_FETCH_LOGGING
- #if !DEBUG
- #define STRIP_GTM_FETCH_LOGGING 1
- #else
- #define STRIP_GTM_FETCH_LOGGING 0
- #endif
- #endif
-
- // Logs in debug builds.
- #ifndef GTMSESSION_LOG_DEBUG
- #if DEBUG
- #define GTMSESSION_LOG_DEBUG(...) NSLog(__VA_ARGS__)
- #else
- #define GTMSESSION_LOG_DEBUG(...) do { } while (0)
- #endif
- #endif
-
- // Asserts in debug builds (or logs in debug builds if GTMSESSION_ASSERT_AS_LOG
- // or NS_BLOCK_ASSERTIONS are defined.)
- #ifndef GTMSESSION_ASSERT_DEBUG
- #if DEBUG && !defined(NS_BLOCK_ASSERTIONS) && !GTMSESSION_ASSERT_AS_LOG
- #undef GTMSESSION_ASSERT_AS_LOG
- #define GTMSESSION_ASSERT_AS_LOG 1
- #endif
-
- #if DEBUG && !GTMSESSION_ASSERT_AS_LOG
- #define GTMSESSION_ASSERT_DEBUG(...) NSAssert(__VA_ARGS__)
- #elif DEBUG
- #define GTMSESSION_ASSERT_DEBUG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); }
- #else
- #define GTMSESSION_ASSERT_DEBUG(pred, ...) do { } while (0)
- #endif
- #endif
-
- // Asserts in debug builds, logs in release builds (or logs in debug builds if
- // GTMSESSION_ASSERT_AS_LOG is defined.)
- #ifndef GTMSESSION_ASSERT_DEBUG_OR_LOG
- #if DEBUG && !GTMSESSION_ASSERT_AS_LOG
- #define GTMSESSION_ASSERT_DEBUG_OR_LOG(...) NSAssert(__VA_ARGS__)
- #else
- #define GTMSESSION_ASSERT_DEBUG_OR_LOG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); }
- #endif
- #endif
-
- // Macro useful for examining messages from NSURLSession during debugging.
- #if 0
- #define GTM_LOG_SESSION_DELEGATE(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__)
- #else
- #define GTM_LOG_SESSION_DELEGATE(...)
- #endif
-
- #ifndef GTM_NULLABLE
- #if __has_feature(nullability) // Available starting in Xcode 6.3
- #define GTM_NULLABLE_TYPE __nullable
- #define GTM_NONNULL_TYPE __nonnull
- #define GTM_NULLABLE nullable
- #define GTM_NONNULL_DECL nonnull // GTM_NONNULL is used by GTMDefines.h
- #define GTM_NULL_RESETTABLE null_resettable
-
- #define GTM_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
- #define GTM_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
- #else
- #define GTM_NULLABLE_TYPE
- #define GTM_NONNULL_TYPE
- #define GTM_NULLABLE
- #define GTM_NONNULL_DECL
- #define GTM_NULL_RESETTABLE
- #define GTM_ASSUME_NONNULL_BEGIN
- #define GTM_ASSUME_NONNULL_END
- #endif // __has_feature(nullability)
- #endif // GTM_NULLABLE
-
- #if (TARGET_OS_TV \
- || TARGET_OS_WATCH \
- || (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12) \
- || (TARGET_OS_IPHONE && defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0))
- #define GTMSESSION_DEPRECATE_ON_2016_SDKS(_MSG) __attribute__((deprecated("" _MSG)))
- #else
- #define GTMSESSION_DEPRECATE_ON_2016_SDKS(_MSG)
- #endif
-
- #ifndef GTM_DECLARE_GENERICS
- #if __has_feature(objc_generics)
- #define GTM_DECLARE_GENERICS 1
- #else
- #define GTM_DECLARE_GENERICS 0
- #endif
- #endif
-
- #ifndef GTM_NSArrayOf
- #if GTM_DECLARE_GENERICS
- #define GTM_NSArrayOf(value) NSArray<value>
- #define GTM_NSDictionaryOf(key, value) NSDictionary<key, value>
- #else
- #define GTM_NSArrayOf(value) NSArray
- #define GTM_NSDictionaryOf(key, value) NSDictionary
- #endif // __has_feature(objc_generics)
- #endif // GTM_NSArrayOf
-
- // For iOS, the fetcher can declare itself a background task to allow fetches
- // to finish when the app leaves the foreground.
- //
- // (This is unrelated to providing a background configuration, which allows
- // out-of-process uploads and downloads.)
- //
- // To disallow use of background tasks during fetches, the target should define
- // GTM_BACKGROUND_TASK_FETCHING to 0, or alternatively may set the
- // skipBackgroundTask property to YES.
- #if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !defined(GTM_BACKGROUND_TASK_FETCHING)
- #define GTM_BACKGROUND_TASK_FETCHING 1
- #endif
-
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- #if (TARGET_OS_TV \
- || TARGET_OS_WATCH \
- || (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \
- || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0))
- #ifndef GTM_USE_SESSION_FETCHER
- #define GTM_USE_SESSION_FETCHER 1
- #endif
- #endif
-
- #if !defined(GTMBridgeFetcher)
- // These bridge macros should be identical in GTMHTTPFetcher.h and GTMSessionFetcher.h
- #if GTM_USE_SESSION_FETCHER
- // Macros to new fetcher class.
- #define GTMBridgeFetcher GTMSessionFetcher
- #define GTMBridgeFetcherService GTMSessionFetcherService
- #define GTMBridgeFetcherServiceProtocol GTMSessionFetcherServiceProtocol
- #define GTMBridgeAssertValidSelector GTMSessionFetcherAssertValidSelector
- #define GTMBridgeCookieStorage GTMSessionCookieStorage
- #define GTMBridgeCleanedUserAgentString GTMFetcherCleanedUserAgentString
- #define GTMBridgeSystemVersionString GTMFetcherSystemVersionString
- #define GTMBridgeApplicationIdentifier GTMFetcherApplicationIdentifier
- #define kGTMBridgeFetcherStatusDomain kGTMSessionFetcherStatusDomain
- #define kGTMBridgeFetcherStatusBadRequest GTMSessionFetcherStatusBadRequest
- #else
- // Macros to old fetcher class.
- #define GTMBridgeFetcher GTMHTTPFetcher
- #define GTMBridgeFetcherService GTMHTTPFetcherService
- #define GTMBridgeFetcherServiceProtocol GTMHTTPFetcherServiceProtocol
- #define GTMBridgeAssertValidSelector GTMAssertSelectorNilOrImplementedWithArgs
- #define GTMBridgeCookieStorage GTMCookieStorage
- #define GTMBridgeCleanedUserAgentString GTMCleanedUserAgentString
- #define GTMBridgeSystemVersionString GTMSystemVersionString
- #define GTMBridgeApplicationIdentifier GTMApplicationIdentifier
- #define kGTMBridgeFetcherStatusDomain kGTMHTTPFetcherStatusDomain
- #define kGTMBridgeFetcherStatusBadRequest kGTMHTTPFetcherStatusBadRequest
- #endif // GTM_USE_SESSION_FETCHER
- #endif
-
- // When creating background sessions to perform out-of-process uploads and
- // downloads, on app launch any background sessions must be reconnected in
- // order to receive events that occurred while the app was not running.
- //
- // The fetcher will automatically attempt to recreate the sessions on app
- // start, but doing so reads from NSUserDefaults. This may have launch-time
- // performance impacts.
- //
- // To avoid launch performance impacts, on iPhone/iPad with iOS 13+ the
- // GTMSessionFetcher class will register for the app launch notification and
- // perform the reconnect then.
- //
- // Apps targeting Mac or older iOS SDKs can opt into the new behavior by defining
- // GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH=1.
- //
- // Apps targeting new SDKs can force the old behavior by defining
- // GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH = 0.
- #ifndef GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH
- // Default to the on-launch behavior for iOS 13+.
- #if TARGET_OS_IOS && defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
- #define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 1
- #else
- #define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 0
- #endif
- #endif
-
- GTM_ASSUME_NONNULL_BEGIN
-
- // Notifications
- //
- // Fetch started and stopped, and fetch retry delay started and stopped.
- extern NSString *const kGTMSessionFetcherStartedNotification;
- extern NSString *const kGTMSessionFetcherStoppedNotification;
- extern NSString *const kGTMSessionFetcherRetryDelayStartedNotification;
- extern NSString *const kGTMSessionFetcherRetryDelayStoppedNotification;
-
- // Completion handler notification. This is intended for use by code capturing
- // and replaying fetch requests and results for testing. For fetches where
- // destinationFileURL or accumulateDataBlock is set for the fetcher, the data
- // will be nil for successful fetches.
- //
- // This notification is posted on the main thread.
- extern NSString *const kGTMSessionFetcherCompletionInvokedNotification;
- extern NSString *const kGTMSessionFetcherCompletionDataKey;
- extern NSString *const kGTMSessionFetcherCompletionErrorKey;
-
- // Constants for NSErrors created by the fetcher (excluding server status errors,
- // and error objects originating in the OS.)
- extern NSString *const kGTMSessionFetcherErrorDomain;
-
- // The fetcher turns server error status values (3XX, 4XX, 5XX) into NSErrors
- // with domain kGTMSessionFetcherStatusDomain.
- //
- // Any server response body data accompanying the status error is added to the
- // userInfo dictionary with key kGTMSessionFetcherStatusDataKey.
- extern NSString *const kGTMSessionFetcherStatusDomain;
- extern NSString *const kGTMSessionFetcherStatusDataKey;
- extern NSString *const kGTMSessionFetcherStatusDataContentTypeKey;
-
- // When a fetch fails with an error, these keys are included in the error userInfo
- // dictionary if retries were attempted.
- extern NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey;
- extern NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey;
-
- // Background session support requires access to NSUserDefaults.
- // If [NSUserDefaults standardUserDefaults] doesn't yield the correct NSUserDefaults for your usage,
- // ie for an App Extension, then implement this class/method to return the correct NSUserDefaults.
- // https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW6
- @interface GTMSessionFetcherUserDefaultsFactory : NSObject
-
- + (NSUserDefaults *)fetcherUserDefaults;
-
- @end
-
- #ifdef __cplusplus
- }
- #endif
-
- typedef NS_ENUM(NSInteger, GTMSessionFetcherError) {
- GTMSessionFetcherErrorDownloadFailed = -1,
- GTMSessionFetcherErrorUploadChunkUnavailable = -2,
- GTMSessionFetcherErrorBackgroundExpiration = -3,
- GTMSessionFetcherErrorBackgroundFetchFailed = -4,
- GTMSessionFetcherErrorInsecureRequest = -5,
- GTMSessionFetcherErrorTaskCreationFailed = -6,
- };
-
- typedef NS_ENUM(NSInteger, GTMSessionFetcherStatus) {
- // Standard http status codes.
- GTMSessionFetcherStatusNotModified = 304,
- GTMSessionFetcherStatusBadRequest = 400,
- GTMSessionFetcherStatusUnauthorized = 401,
- GTMSessionFetcherStatusForbidden = 403,
- GTMSessionFetcherStatusPreconditionFailed = 412
- };
-
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- @class GTMSessionCookieStorage;
- @class GTMSessionFetcher;
-
- // The configuration block is for modifying the NSURLSessionConfiguration only.
- // DO NOT change any fetcher properties in the configuration block.
- typedef void (^GTMSessionFetcherConfigurationBlock)(GTMSessionFetcher *fetcher,
- NSURLSessionConfiguration *configuration);
- typedef void (^GTMSessionFetcherSystemCompletionHandler)(void);
- typedef void (^GTMSessionFetcherCompletionHandler)(NSData * GTM_NULLABLE_TYPE data,
- NSError * GTM_NULLABLE_TYPE error);
- typedef void (^GTMSessionFetcherBodyStreamProviderResponse)(NSInputStream *bodyStream);
- typedef void (^GTMSessionFetcherBodyStreamProvider)(GTMSessionFetcherBodyStreamProviderResponse response);
- typedef void (^GTMSessionFetcherDidReceiveResponseDispositionBlock)(NSURLSessionResponseDisposition disposition);
- typedef void (^GTMSessionFetcherDidReceiveResponseBlock)(NSURLResponse *response,
- GTMSessionFetcherDidReceiveResponseDispositionBlock dispositionBlock);
- typedef void (^GTMSessionFetcherChallengeDispositionBlock)(NSURLSessionAuthChallengeDisposition disposition,
- NSURLCredential * GTM_NULLABLE_TYPE credential);
- typedef void (^GTMSessionFetcherChallengeBlock)(GTMSessionFetcher *fetcher,
- NSURLAuthenticationChallenge *challenge,
- GTMSessionFetcherChallengeDispositionBlock dispositionBlock);
- typedef void (^GTMSessionFetcherWillRedirectResponse)(NSURLRequest * GTM_NULLABLE_TYPE redirectedRequest);
- typedef void (^GTMSessionFetcherWillRedirectBlock)(NSHTTPURLResponse *redirectResponse,
- NSURLRequest *redirectRequest,
- GTMSessionFetcherWillRedirectResponse response);
- typedef void (^GTMSessionFetcherAccumulateDataBlock)(NSData * GTM_NULLABLE_TYPE buffer);
- typedef void (^GTMSessionFetcherSimulateByteTransferBlock)(NSData * GTM_NULLABLE_TYPE buffer,
- int64_t bytesWritten,
- int64_t totalBytesWritten,
- int64_t totalBytesExpectedToWrite);
- typedef void (^GTMSessionFetcherReceivedProgressBlock)(int64_t bytesWritten,
- int64_t totalBytesWritten);
- typedef void (^GTMSessionFetcherDownloadProgressBlock)(int64_t bytesWritten,
- int64_t totalBytesWritten,
- int64_t totalBytesExpectedToWrite);
- typedef void (^GTMSessionFetcherSendProgressBlock)(int64_t bytesSent,
- int64_t totalBytesSent,
- int64_t totalBytesExpectedToSend);
- typedef void (^GTMSessionFetcherWillCacheURLResponseResponse)(NSCachedURLResponse * GTM_NULLABLE_TYPE cachedResponse);
- typedef void (^GTMSessionFetcherWillCacheURLResponseBlock)(NSCachedURLResponse *proposedResponse,
- GTMSessionFetcherWillCacheURLResponseResponse responseBlock);
- typedef void (^GTMSessionFetcherRetryResponse)(BOOL shouldRetry);
- typedef void (^GTMSessionFetcherRetryBlock)(BOOL suggestedWillRetry,
- NSError * GTM_NULLABLE_TYPE error,
- GTMSessionFetcherRetryResponse response);
-
- typedef void (^GTMSessionFetcherTestResponse)(NSHTTPURLResponse * GTM_NULLABLE_TYPE response,
- NSData * GTM_NULLABLE_TYPE data,
- NSError * GTM_NULLABLE_TYPE error);
- typedef void (^GTMSessionFetcherTestBlock)(GTMSessionFetcher *fetcherToTest,
- GTMSessionFetcherTestResponse testResponse);
-
- void GTMSessionFetcherAssertValidSelector(id GTM_NULLABLE_TYPE obj, SEL GTM_NULLABLE_TYPE sel, ...);
-
- // Utility functions for applications self-identifying to servers via a
- // user-agent header
-
- // The "standard" user agent includes the application identifier, taken from the bundle,
- // followed by a space and the system version string. Pass nil to use +mainBundle as the source
- // of the bundle identifier.
- //
- // Applications may use this as a starting point for their own user agent strings, perhaps
- // with additional sections appended. Use GTMFetcherCleanedUserAgentString() below to
- // clean up any string being added to the user agent.
- NSString *GTMFetcherStandardUserAgentString(NSBundle * GTM_NULLABLE_TYPE bundle);
-
- // Make a generic name and version for the current application, like
- // com.example.MyApp/1.2.3 relying on the bundle identifier and the
- // CFBundleShortVersionString or CFBundleVersion.
- //
- // The bundle ID may be overridden as the base identifier string by
- // adding to the bundle's Info.plist a "GTMUserAgentID" key.
- //
- // If no bundle ID or override is available, the process name preceded
- // by "proc_" is used.
- NSString *GTMFetcherApplicationIdentifier(NSBundle * GTM_NULLABLE_TYPE bundle);
-
- // Make an identifier like "MacOSX/10.7.1" or "iPod_Touch/4.1 hw/iPod1_1"
- NSString *GTMFetcherSystemVersionString(void);
-
- // Make a parseable user-agent identifier from the given string, replacing whitespace
- // and commas with underscores, and removing other characters that may interfere
- // with parsing of the full user-agent string.
- //
- // For example, @"[My App]" would become @"My_App"
- NSString *GTMFetcherCleanedUserAgentString(NSString *str);
-
- // Grab the data from an input stream. Since streams cannot be assumed to be rewindable,
- // this may be destructive; the caller can try to rewind the stream (by setting the
- // NSStreamFileCurrentOffsetKey property) or can just use the NSData to make a new
- // NSInputStream. This function is intended to facilitate testing rather than be used in
- // production.
- //
- // This function operates synchronously on the current thread. Depending on how the
- // input stream is implemented, it may be appropriate to dispatch to a different
- // queue before calling this function.
- //
- // Failure is indicated by a returned data value of nil.
- NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError);
-
- #ifdef __cplusplus
- } // extern "C"
- #endif
-
-
- #if !GTM_USE_SESSION_FETCHER
- @protocol GTMHTTPFetcherServiceProtocol;
- #endif
-
- // This protocol allows abstract references to the fetcher service, primarily for
- // fetchers (which may be compiled without the fetcher service class present.)
- //
- // Apps should not need to use this protocol.
- @protocol GTMSessionFetcherServiceProtocol <NSObject>
- // This protocol allows us to call into the service without requiring
- // GTMSessionFetcherService sources in this project
-
- @property(atomic, strong) dispatch_queue_t callbackQueue;
-
- - (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher;
- - (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher;
- - (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher;
- - (void)fetcherDidStop:(GTMSessionFetcher *)fetcher;
-
- - (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request;
- - (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher;
-
- @property(atomic, assign) BOOL reuseSession;
- - (GTM_NULLABLE NSURLSession *)session;
- - (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation;
- - (GTM_NULLABLE id<NSURLSessionDelegate>)sessionDelegate;
- - (GTM_NULLABLE NSDate *)stoppedAllFetchersDate;
-
- // Methods for compatibility with the old GTMHTTPFetcher.
- @property(atomic, readonly, strong, GTM_NULLABLE) NSOperationQueue *delegateQueue;
-
- @end // @protocol GTMSessionFetcherServiceProtocol
-
- #ifndef GTM_FETCHER_AUTHORIZATION_PROTOCOL
- #define GTM_FETCHER_AUTHORIZATION_PROTOCOL 1
- @protocol GTMFetcherAuthorizationProtocol <NSObject>
- @required
- // This protocol allows us to call the authorizer without requiring its sources
- // in this project.
- - (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request
- delegate:(id)delegate
- didFinishSelector:(SEL)sel;
-
- - (void)stopAuthorization;
-
- - (void)stopAuthorizationForRequest:(NSURLRequest *)request;
-
- - (BOOL)isAuthorizingRequest:(NSURLRequest *)request;
-
- - (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
-
- @property(atomic, strong, readonly, GTM_NULLABLE) NSString *userEmail;
-
- @optional
-
- // Indicate if authorization may be attempted. Even if this succeeds,
- // authorization may fail if the user's permissions have been revoked.
- @property(atomic, readonly) BOOL canAuthorize;
-
- // For development only, allow authorization of non-SSL requests, allowing
- // transmission of the bearer token unencrypted.
- @property(atomic, assign) BOOL shouldAuthorizeAllRequests;
-
- - (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request
- completionHandler:(void (^)(NSError * GTM_NULLABLE_TYPE error))handler;
-
- #if GTM_USE_SESSION_FETCHER
- @property(atomic, weak, GTM_NULLABLE) id<GTMSessionFetcherServiceProtocol> fetcherService;
- #else
- @property(atomic, weak, GTM_NULLABLE) id<GTMHTTPFetcherServiceProtocol> fetcherService;
- #endif
-
- - (BOOL)primeForRefresh;
-
- @end
- #endif // GTM_FETCHER_AUTHORIZATION_PROTOCOL
-
- #if GTM_BACKGROUND_TASK_FETCHING
- // A protocol for an alternative target for messages from GTMSessionFetcher to UIApplication.
- // Set the target using +[GTMSessionFetcher setSubstituteUIApplication:]
- @protocol GTMUIApplicationProtocol <NSObject>
- - (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName
- expirationHandler:(void(^ __nullable)(void))handler;
- - (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier;
- @end
- #endif
-
- #pragma mark -
-
- // GTMSessionFetcher objects are used for async retrieval of an http get or post
- //
- // See additional comments at the beginning of this file
- @interface GTMSessionFetcher : NSObject <NSURLSessionDelegate>
-
- // Create a fetcher
- //
- // fetcherWithRequest will return an autoreleased fetcher, but if
- // the connection is successfully created, the connection should retain the
- // fetcher for the life of the connection as well. So the caller doesn't have
- // to retain the fetcher explicitly unless they want to be able to cancel it.
- + (instancetype)fetcherWithRequest:(GTM_NULLABLE NSURLRequest *)request;
-
- // Convenience methods that make a request, like +fetcherWithRequest
- + (instancetype)fetcherWithURL:(NSURL *)requestURL;
- + (instancetype)fetcherWithURLString:(NSString *)requestURLString;
-
- // Methods for creating fetchers to continue previous fetches.
- + (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData;
- + (GTM_NULLABLE instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier;
-
- // Returns an array of currently active fetchers for background sessions,
- // both restarted and newly created ones.
- + (GTM_NSArrayOf(GTMSessionFetcher *) *)fetchersForBackgroundSessions;
-
- // Designated initializer.
- //
- // Applications should create fetchers with a "fetcherWith..." method on a fetcher
- // service or a class method, not with this initializer.
- //
- // The configuration should typically be nil. Applications needing to customize
- // the configuration may do so by setting the configurationBlock property.
- - (instancetype)initWithRequest:(GTM_NULLABLE NSURLRequest *)request
- configuration:(GTM_NULLABLE NSURLSessionConfiguration *)configuration;
-
- // The fetcher's request. This may not be set after beginFetch has been invoked. The request
- // may change due to redirects.
- @property(atomic, strong, GTM_NULLABLE) NSURLRequest *request;
-
- // Set a header field value on the request. Header field value changes will not
- // affect a fetch after the fetch has begun.
- - (void)setRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field;
-
- // Data used for resuming a download task.
- @property(atomic, readonly, GTM_NULLABLE) NSData *downloadResumeData;
-
- // The configuration; this must be set before the fetch begins. If no configuration is
- // set or inherited from the fetcher service, then the fetcher uses an ephemeral config.
- //
- // NOTE: This property should typically be nil. Applications needing to customize
- // the configuration should do so by setting the configurationBlock property.
- // That allows the fetcher to pick an appropriate base configuration, with the
- // application setting only the configuration properties it needs to customize.
- @property(atomic, strong, GTM_NULLABLE) NSURLSessionConfiguration *configuration;
-
- // A block the client may use to customize the configuration used to create the session.
- //
- // This is called synchronously, either on the thread that begins the fetch or, during a retry,
- // on the main thread. The configuration block may be called repeatedly if multiple fetchers are
- // created.
- //
- // The configuration block is for modifying the NSURLSessionConfiguration only.
- // DO NOT change any fetcher properties in the configuration block. Fetcher properties
- // may be set in the fetcher service prior to fetcher creation, or on the fetcher prior
- // to invoking beginFetch.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherConfigurationBlock configurationBlock;
-
- // A session is created as needed by the fetcher. A fetcher service object
- // may maintain sessions for multiple fetches to the same host.
- @property(atomic, strong, GTM_NULLABLE) NSURLSession *session;
-
- // The task in flight.
- @property(atomic, readonly, GTM_NULLABLE) NSURLSessionTask *sessionTask;
-
- // The background session identifier.
- @property(atomic, readonly, GTM_NULLABLE) NSString *sessionIdentifier;
-
- // Indicates a fetcher created to finish a background session task.
- @property(atomic, readonly) BOOL wasCreatedFromBackgroundSession;
-
- // Additional user-supplied data to encode into the session identifier. Since session identifier
- // length limits are unspecified, this should be kept small. Key names beginning with an underscore
- // are reserved for use by the fetcher.
- @property(atomic, strong, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *sessionUserInfo;
-
- // The human-readable description to be assigned to the task.
- @property(atomic, copy, GTM_NULLABLE) NSString *taskDescription;
-
- // The priority assigned to the task, if any. Use NSURLSessionTaskPriorityLow,
- // NSURLSessionTaskPriorityDefault, or NSURLSessionTaskPriorityHigh.
- @property(atomic, assign) float taskPriority;
-
- // The fetcher encodes information used to resume a session in the session identifier.
- // This method, intended for internal use returns the encoded information. The sessionUserInfo
- // dictionary is stored as identifier metadata.
- - (GTM_NULLABLE GTM_NSDictionaryOf(NSString *, NSString *) *)sessionIdentifierMetadata;
-
- #if TARGET_OS_IPHONE && !TARGET_OS_WATCH
- // The app should pass to this method the completion handler passed in the app delegate method
- // application:handleEventsForBackgroundURLSession:completionHandler:
- + (void)application:(UIApplication *)application
- handleEventsForBackgroundURLSession:(NSString *)identifier
- completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler;
- #endif
-
- // Indicate that a newly created session should be a background session.
- // A new session identifier will be created by the fetcher.
- //
- // Warning: The only thing background sessions are for is rare download
- // of huge, batched files of data. And even just for those, there's a lot
- // of pain and hackery needed to get transfers to actually happen reliably
- // with background sessions.
- //
- // Don't try to upload or download in many background sessions, since the system
- // will impose an exponentially increasing time penalty to prevent the app from
- // getting too much background execution time.
- //
- // References:
- //
- // "Moving to Fewer, Larger Transfers"
- // https://forums.developer.apple.com/thread/14853
- //
- // "NSURLSession’s Resume Rate Limiter"
- // https://forums.developer.apple.com/thread/14854
- //
- // "Background Session Task state persistence"
- // https://forums.developer.apple.com/thread/11554
- //
- @property(atomic, assign) BOOL useBackgroundSession;
-
- // Indicates if the fetcher was started using a background session.
- @property(atomic, readonly, getter=isUsingBackgroundSession) BOOL usingBackgroundSession;
-
- // Indicates if uploads should use an upload task. This is always set for file or stream-provider
- // bodies, but may be set explicitly for NSData bodies.
- @property(atomic, assign) BOOL useUploadTask;
-
- // Indicates that the fetcher is using a session that may be shared with other fetchers.
- @property(atomic, readonly) BOOL canShareSession;
-
- // By default, the fetcher allows only secure (https) schemes unless this
- // property is set, or the GTM_ALLOW_INSECURE_REQUESTS build flag is set.
- //
- // For example, during debugging when fetching from a development server that lacks SSL support,
- // this may be set to @[ @"http" ], or when the fetcher is used to retrieve local files,
- // this may be set to @[ @"file" ].
- //
- // This should be left as nil for release builds to avoid creating the opportunity for
- // leaking private user behavior and data. If a server is providing insecure URLs
- // for fetching by the client app, report the problem as server security & privacy bug.
- //
- // For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when
- // the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist.
- @property(atomic, copy, GTM_NULLABLE) GTM_NSArrayOf(NSString *) *allowedInsecureSchemes;
-
- // By default, the fetcher prohibits localhost requests unless this property is set,
- // or the GTM_ALLOW_INSECURE_REQUESTS build flag is set.
- //
- // For localhost requests, the URL scheme is not checked when this property is set.
- //
- // For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when
- // the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist.
- @property(atomic, assign) BOOL allowLocalhostRequest;
-
- // By default, the fetcher requires valid server certs. This may be bypassed
- // temporarily for development against a test server with an invalid cert.
- @property(atomic, assign) BOOL allowInvalidServerCertificates;
-
- // Cookie storage object for this fetcher. If nil, the fetcher will use a static cookie
- // storage instance shared among fetchers. If this fetcher was created by a fetcher service
- // object, it will be set to use the service object's cookie storage. See Cookies section above for
- // the full discussion.
- //
- // Because as of Jan 2014 standalone instances of NSHTTPCookieStorage do not actually
- // store any cookies (Radar 15735276) we use our own subclass, GTMSessionCookieStorage,
- // to hold cookies in memory.
- @property(atomic, strong, GTM_NULLABLE) NSHTTPCookieStorage *cookieStorage;
-
- // Setting the credential is optional; it is used if the connection receives
- // an authentication challenge.
- @property(atomic, strong, GTM_NULLABLE) NSURLCredential *credential;
-
- // Setting the proxy credential is optional; it is used if the connection
- // receives an authentication challenge from a proxy.
- @property(atomic, strong, GTM_NULLABLE) NSURLCredential *proxyCredential;
-
- // If body data, body file URL, or body stream provider is not set, then a GET request
- // method is assumed.
- @property(atomic, strong, GTM_NULLABLE) NSData *bodyData;
-
- // File to use as the request body. This forces use of an upload task.
- @property(atomic, strong, GTM_NULLABLE) NSURL *bodyFileURL;
-
- // Length of body to send, expected or actual.
- @property(atomic, readonly) int64_t bodyLength;
-
- // The body stream provider may be called repeatedly to provide a body.
- // Setting a body stream provider forces use of an upload task.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherBodyStreamProvider bodyStreamProvider;
-
- // Object to add authorization to the request, if needed.
- //
- // This may not be changed once beginFetch has been invoked.
- @property(atomic, strong, GTM_NULLABLE) id<GTMFetcherAuthorizationProtocol> authorizer;
-
- // The service object that created and monitors this fetcher, if any.
- @property(atomic, strong) id<GTMSessionFetcherServiceProtocol> service;
-
- // The host, if any, used to classify this fetcher in the fetcher service.
- @property(atomic, copy, GTM_NULLABLE) NSString *serviceHost;
-
- // The priority, if any, used for starting fetchers in the fetcher service.
- //
- // Lower values are higher priority; the default is 0, and values may
- // be negative or positive. This priority affects only the start order of
- // fetchers that are being delayed by a fetcher service when the running fetchers
- // exceeds the service's maxRunningFetchersPerHost. A priority of NSIntegerMin will
- // exempt this fetcher from delay.
- @property(atomic, assign) NSInteger servicePriority;
-
- // The delegate's optional didReceiveResponse block may be used to inspect or alter
- // the session task response.
- //
- // This is called on the callback queue.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock;
-
- // The delegate's optional challenge block may be used to inspect or alter
- // the session task challenge.
- //
- // If this block is not set, the fetcher's default behavior for the NSURLSessionTask
- // didReceiveChallenge: delegate method is to use the fetcher's respondToChallenge: method
- // which relies on the fetcher's credential and proxyCredential properties.
- //
- // Warning: This may be called repeatedly if the challenge fails. Check
- // challenge.previousFailureCount to identify repeated invocations.
- //
- // This is called on the callback queue.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherChallengeBlock challengeBlock;
-
- // The delegate's optional willRedirect block may be used to inspect or alter
- // the redirection.
- //
- // This is called on the callback queue.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillRedirectBlock willRedirectBlock;
-
- // The optional send progress block reports body bytes uploaded.
- //
- // This is called on the callback queue.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherSendProgressBlock sendProgressBlock;
-
- // The optional accumulate block may be set by clients wishing to accumulate data
- // themselves rather than let the fetcher append each buffer to an NSData.
- //
- // When this is called with nil data (such as on redirect) the client
- // should empty its accumulation buffer.
- //
- // This is called on the callback queue.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherAccumulateDataBlock accumulateDataBlock;
-
- // The optional received progress block may be used to monitor data
- // received from a data task.
- //
- // This is called on the callback queue.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherReceivedProgressBlock receivedProgressBlock;
-
- // The delegate's optional downloadProgress block may be used to monitor download
- // progress in writing to disk.
- //
- // This is called on the callback queue.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDownloadProgressBlock downloadProgressBlock;
-
- // The delegate's optional willCacheURLResponse block may be used to alter the cached
- // NSURLResponse. The user may prevent caching by passing nil to the block's response.
- //
- // This is called on the callback queue.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock;
-
- // Enable retrying; see comments at the top of this file. Setting
- // retryEnabled=YES resets the min and max retry intervals.
- @property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled;
-
- // Retry block is optional for retries.
- //
- // If present, this block should call the response block with YES to cause a retry or NO to end the
- // fetch.
- // See comments at the top of this file.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherRetryBlock retryBlock;
-
- // Retry intervals must be strictly less than maxRetryInterval, else
- // they will be limited to maxRetryInterval and no further retries will
- // be attempted. Setting maxRetryInterval to 0.0 will reset it to the
- // default value, 60 seconds for downloads and 600 seconds for uploads.
- @property(atomic, assign) NSTimeInterval maxRetryInterval;
-
- // Starting retry interval. Setting minRetryInterval to 0.0 will reset it
- // to a random value between 1.0 and 2.0 seconds. Clients should normally not
- // set this except for unit testing.
- @property(atomic, assign) NSTimeInterval minRetryInterval;
-
- // Multiplier used to increase the interval between retries, typically 2.0.
- // Clients should not need to set this.
- @property(atomic, assign) double retryFactor;
-
- // Number of retries attempted.
- @property(atomic, readonly) NSUInteger retryCount;
-
- // Interval delay to precede next retry.
- @property(atomic, readonly) NSTimeInterval nextRetryInterval;
-
- #if GTM_BACKGROUND_TASK_FETCHING
- // Skip use of a UIBackgroundTask, thus requiring fetches to complete when the app is in the
- // foreground.
- //
- // Targets should define GTM_BACKGROUND_TASK_FETCHING to 0 to avoid use of a UIBackgroundTask
- // on iOS to allow fetches to complete in the background. This property is available when
- // it's not practical to set the preprocessor define.
- @property(atomic, assign) BOOL skipBackgroundTask;
- #endif // GTM_BACKGROUND_TASK_FETCHING
-
- // Begin fetching the request
- //
- // The delegate may optionally implement the callback or pass nil for the selector or handler.
- //
- // The delegate and all callback blocks are retained between the beginFetch call until after the
- // finish callback, or until the fetch is stopped.
- //
- // An error is passed to the callback for server statuses 300 or
- // higher, with the status stored as the error object's code.
- //
- // finishedSEL has a signature like:
- // - (void)fetcher:(GTMSessionFetcher *)fetcher
- // finishedWithData:(NSData *)data
- // error:(NSError *)error;
- //
- // If the application has specified a destinationFileURL or an accumulateDataBlock
- // for the fetcher, the data parameter passed to the callback will be nil.
-
- - (void)beginFetchWithDelegate:(GTM_NULLABLE id)delegate
- didFinishSelector:(GTM_NULLABLE SEL)finishedSEL;
-
- - (void)beginFetchWithCompletionHandler:(GTM_NULLABLE GTMSessionFetcherCompletionHandler)handler;
-
- // Returns YES if this fetcher is in the process of fetching a URL.
- @property(atomic, readonly, getter=isFetching) BOOL fetching;
-
- // Cancel the fetch of the request that's currently in progress. The completion handler
- // will not be called.
- - (void)stopFetching;
-
- // A block to be called when the fetch completes.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherCompletionHandler completionHandler;
-
- // A block to be called if download resume data becomes available.
- @property(atomic, strong, GTM_NULLABLE) void (^resumeDataBlock)(NSData *);
-
- // Return the status code from the server response.
- @property(atomic, readonly) NSInteger statusCode;
-
- // Return the http headers from the response.
- @property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *responseHeaders;
-
- // The response, once it's been received.
- @property(atomic, strong, readonly, GTM_NULLABLE) NSURLResponse *response;
-
- // Bytes downloaded so far.
- @property(atomic, readonly) int64_t downloadedLength;
-
- // Buffer of currently-downloaded data, if available.
- @property(atomic, readonly, strong, GTM_NULLABLE) NSData *downloadedData;
-
- // Local path to which the downloaded file will be moved.
- //
- // If a file already exists at the path, it will be overwritten.
- // Will create the enclosing folders if they are not present.
- @property(atomic, strong, GTM_NULLABLE) NSURL *destinationFileURL;
-
- // The time this fetcher originally began fetching. This is useful as a time
- // barrier for ignoring irrelevant fetch notifications or callbacks.
- @property(atomic, strong, readonly, GTM_NULLABLE) NSDate *initialBeginFetchDate;
-
- // userData is retained solely for the convenience of the client.
- @property(atomic, strong, GTM_NULLABLE) id userData;
-
- // Stored property values are retained solely for the convenience of the client.
- @property(atomic, copy, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, id) *properties;
-
- - (void)setProperty:(GTM_NULLABLE id)obj forKey:(NSString *)key; // Pass nil for obj to remove the property.
- - (GTM_NULLABLE id)propertyForKey:(NSString *)key;
-
- - (void)addPropertiesFromDictionary:(GTM_NSDictionaryOf(NSString *, id) *)dict;
-
- // Comments are useful for logging, so are strongly recommended for each fetcher.
- @property(atomic, copy, GTM_NULLABLE) NSString *comment;
-
- - (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
-
- // Log of request and response, if logging is enabled
- @property(atomic, copy, GTM_NULLABLE) NSString *log;
-
- // Callbacks are run on this queue. If none is supplied, the main queue is used.
- @property(atomic, strong, GTM_NULL_RESETTABLE) dispatch_queue_t callbackQueue;
-
- // The queue used internally by the session to invoke its delegate methods in the fetcher.
- //
- // Application callbacks are always called by the fetcher on the callbackQueue above,
- // not on this queue. Apps should generally not change this queue.
- //
- // The default delegate queue is the main queue.
- //
- // This value is ignored after the session has been created, so this
- // property should be set in the fetcher service rather in the fetcher as it applies
- // to a shared session.
- @property(atomic, strong, GTM_NULL_RESETTABLE) NSOperationQueue *sessionDelegateQueue;
-
- // Spin the run loop or sleep the thread, discarding events, until the fetch has completed.
- //
- // This is only for use in testing or in tools without a user interface.
- //
- // Note: Synchronous fetches should never be used by shipping apps; they are
- // sufficient reason for rejection from the app store.
- //
- // Returns NO if timed out.
- - (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds;
-
- // Test block is optional for testing.
- //
- // If present, this block will cause the fetcher to skip starting the session, and instead
- // use the test block response values when calling the completion handler and delegate code.
- //
- // Test code can set this on the fetcher or on the fetcher service. For testing libraries
- // that use a fetcher without exposing either the fetcher or the fetcher service, the global
- // method setGlobalTestBlock: will set the block for all fetchers that do not have a test
- // block set.
- //
- // The test code can pass nil for all response parameters to indicate that the fetch
- // should proceed.
- //
- // Applications can exclude test block support by setting GTM_DISABLE_FETCHER_TEST_BLOCK.
- @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherTestBlock testBlock;
-
- + (void)setGlobalTestBlock:(GTM_NULLABLE GTMSessionFetcherTestBlock)block;
-
- // When using the testBlock, |testBlockAccumulateDataChunkCount| is the desired number of chunks to
- // divide the response data into if the client has streaming enabled. The data will be divided up to
- // |testBlockAccumulateDataChunkCount| chunks; however, the exact amount may vary depending on the
- // size of the response data (e.g. a 1-byte response can only be divided into one chunk).
- @property(atomic, readwrite) NSUInteger testBlockAccumulateDataChunkCount;
-
- #if GTM_BACKGROUND_TASK_FETCHING
- // For testing or to override UIApplication invocations, apps may specify an alternative
- // target for messages to UIApplication.
- + (void)setSubstituteUIApplication:(nullable id<GTMUIApplicationProtocol>)substituteUIApplication;
- + (nullable id<GTMUIApplicationProtocol>)substituteUIApplication;
- #endif // GTM_BACKGROUND_TASK_FETCHING
-
- // Exposed for testing.
- + (GTMSessionCookieStorage *)staticCookieStorage;
- + (BOOL)appAllowsInsecureRequests;
-
- #if STRIP_GTM_FETCH_LOGGING
- // If logging is stripped, provide a stub for the main method
- // for controlling logging.
- + (void)setLoggingEnabled:(BOOL)flag;
- + (BOOL)isLoggingEnabled;
-
- #else
-
- // These methods let an application log specific body text, such as the text description of a binary
- // request or response. The application should set the fetcher to defer response body logging until
- // the response has been received and the log response body has been set by the app. For example:
- //
- // fetcher.logRequestBody = [binaryObject stringDescription];
- // fetcher.deferResponseBodyLogging = YES;
- // [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
- // if (error == nil) {
- // fetcher.logResponseBody = [[[MyThing alloc] initWithData:data] stringDescription];
- // }
- // fetcher.deferResponseBodyLogging = NO;
- // }];
-
- @property(atomic, copy, GTM_NULLABLE) NSString *logRequestBody;
- @property(atomic, assign) BOOL deferResponseBodyLogging;
- @property(atomic, copy, GTM_NULLABLE) NSString *logResponseBody;
-
- // Internal logging support.
- @property(atomic, readonly) NSData *loggedStreamData;
- @property(atomic, assign) BOOL hasLoggedError;
- @property(atomic, strong, GTM_NULLABLE) NSURL *redirectedFromURL;
- - (void)appendLoggedStreamData:(NSData *)dataToAdd;
- - (void)clearLoggedStreamData;
-
- #endif // STRIP_GTM_FETCH_LOGGING
-
- @end
-
- @interface GTMSessionFetcher (BackwardsCompatibilityOnly)
- // Clients using GTMSessionFetcher should set the cookie storage explicitly themselves.
- // This method is just for compatibility with the old GTMHTTPFetcher class.
- - (void)setCookieStorageMethod:(NSInteger)method;
- @end
-
- // Until we can just instantiate NSHTTPCookieStorage for local use, we'll
- // implement all the public methods ourselves. This stores cookies only in
- // memory. Additional methods are provided for testing.
- //
- // iOS 9/OS X 10.11 added +[NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:]
- // which may also be used to create cookie storage.
- @interface GTMSessionCookieStorage : NSHTTPCookieStorage
-
- // Add the array off cookies to the storage, replacing duplicates.
- // Also removes expired cookies from the storage.
- - (void)setCookies:(GTM_NULLABLE GTM_NSArrayOf(NSHTTPCookie *) *)cookies;
-
- - (void)removeAllCookies;
-
- @end
-
- // Macros to monitor synchronization blocks in debug builds.
- // These report problems using GTMSessionCheckDebug.
- //
- // GTMSessionMonitorSynchronized Start monitoring a top-level-only
- // @sync scope.
- // GTMSessionMonitorRecursiveSynchronized Start monitoring a top-level or
- // recursive @sync scope.
- // GTMSessionCheckSynchronized Verify that the current execution
- // is inside a @sync scope.
- // GTMSessionCheckNotSynchronized Verify that the current execution
- // is not inside a @sync scope.
- //
- // Example usage:
- //
- // - (void)myExternalMethod {
- // @synchronized(self) {
- // GTMSessionMonitorSynchronized(self)
- //
- // - (void)myInternalMethod {
- // GTMSessionCheckSynchronized(self);
- //
- // - (void)callMyCallbacks {
- // GTMSessionCheckNotSynchronized(self);
- //
- // GTMSessionCheckNotSynchronized is available for verifying the code isn't
- // in a deadlockable @sync state when posting notifications and invoking
- // callbacks. Don't use GTMSessionCheckNotSynchronized immediately before a
- // @sync scope; the normal recursiveness check of GTMSessionMonitorSynchronized
- // can catch those.
-
- #ifdef __OBJC__
- // If asserts are entirely no-ops, the synchronization monitor is just a bunch
- // of counting code that doesn't report exceptional circumstances in any way.
- // Only build the synchronization monitor code if NS_BLOCK_ASSERTIONS is not
- // defined or asserts are being logged instead.
- #if DEBUG && (!defined(NS_BLOCK_ASSERTIONS) || GTMSESSION_ASSERT_AS_LOG)
- #define __GTMSessionMonitorSynchronizedVariableInner(varname, counter) \
- varname ## counter
- #define __GTMSessionMonitorSynchronizedVariable(varname, counter) \
- __GTMSessionMonitorSynchronizedVariableInner(varname, counter)
-
- #define GTMSessionMonitorSynchronized(obj) \
- NS_VALID_UNTIL_END_OF_SCOPE id \
- __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
- [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
- allowRecursive:NO \
- functionName:__func__]
-
- #define GTMSessionMonitorRecursiveSynchronized(obj) \
- NS_VALID_UNTIL_END_OF_SCOPE id \
- __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
- [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
- allowRecursive:YES \
- functionName:__func__]
-
- #define GTMSessionCheckSynchronized(obj) { \
- GTMSESSION_ASSERT_DEBUG( \
- [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
- @"GTMSessionCheckSynchronized(" #obj ") failed: not sync'd" \
- @" on " #obj " in %s. Call stack:\n%@", \
- __func__, [NSThread callStackSymbols]); \
- }
-
- #define GTMSessionCheckNotSynchronized(obj) { \
- GTMSESSION_ASSERT_DEBUG( \
- ![GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
- @"GTMSessionCheckNotSynchronized(" #obj ") failed: was sync'd" \
- @" on " #obj " in %s by %@. Call stack:\n%@", __func__, \
- [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
- [NSThread callStackSymbols]); \
- }
-
- // GTMSessionSyncMonitorInternal is a private class that keeps track of the
- // beginning and end of synchronized scopes.
- //
- // This class should not be used directly, but only via the
- // GTMSessionMonitorSynchronized macro.
- @interface GTMSessionSyncMonitorInternal : NSObject
- - (instancetype)initWithSynchronizationObject:(id)object
- allowRecursive:(BOOL)allowRecursive
- functionName:(const char *)functionName;
- // Return the names of the functions that hold sync on the object, or nil if none.
- + (NSArray *)functionsHoldingSynchronizationOnObject:(id)object;
- @end
-
- #else
- #define GTMSessionMonitorSynchronized(obj) do { } while (0)
- #define GTMSessionMonitorRecursiveSynchronized(obj) do { } while (0)
- #define GTMSessionCheckSynchronized(obj) do { } while (0)
- #define GTMSessionCheckNotSynchronized(obj) do { } while (0)
- #endif // !DEBUG
- #endif // __OBJC__
-
-
- GTM_ASSUME_NONNULL_END
|