summaryrefslogtreecommitdiff
path: root/StoneIsland/platforms/ios/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h
diff options
context:
space:
mode:
Diffstat (limited to 'StoneIsland/platforms/ios/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h')
-rw-r--r--StoneIsland/platforms/ios/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h1332
1 files changed, 1332 insertions, 0 deletions
diff --git a/StoneIsland/platforms/ios/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h b/StoneIsland/platforms/ios/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h
new file mode 100644
index 00000000..0504aa75
--- /dev/null
+++ b/StoneIsland/platforms/ios/Pods/GTMSessionFetcher/Source/GTMSessionFetcher.h
@@ -0,0 +1,1332 @@
+/* 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
+
+#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);
+
+API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(3.0))
+typedef void (^GTMSessionFetcherMetricsCollectionBlock)(NSURLSessionTaskMetrics *metrics);
+
+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;
+
+// The optional block for collecting the metrics of the present session.
+//
+// This is called on the callback queue.
+@property(atomic, copy, GTM_NULLABLE)
+ GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock API_AVAILABLE(
+ ios(10.0), macosx(10.12), tvos(10.0), watchos(3.0));
+
+// 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