You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1332 lines
60 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. /* Copyright 2014 Google Inc. All rights reserved.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. // GTMSessionFetcher is a wrapper around NSURLSession for http operations.
  16. //
  17. // What does this offer on top of of NSURLSession?
  18. //
  19. // - Block-style callbacks for useful functionality like progress rather
  20. // than delegate methods.
  21. // - Out-of-process uploads and downloads using NSURLSession, including
  22. // management of fetches after relaunch.
  23. // - Integration with GTMAppAuth for invisible management and refresh of
  24. // authorization tokens.
  25. // - Pretty-printed http logging.
  26. // - Cookies handling that does not interfere with or get interfered with
  27. // by WebKit cookies or on Mac by Safari and other apps.
  28. // - Credentials handling for the http operation.
  29. // - Rate-limiting and cookie grouping when fetchers are created with
  30. // GTMSessionFetcherService.
  31. //
  32. // If the bodyData or bodyFileURL property is set, then a POST request is assumed.
  33. //
  34. // Each fetcher is assumed to be for a one-shot fetch request; don't reuse the object
  35. // for a second fetch.
  36. //
  37. // The fetcher will be self-retained as long as a connection is pending.
  38. //
  39. // To keep user activity private, URLs must have an https scheme (unless the property
  40. // allowedInsecureSchemes is set to permit the scheme.)
  41. //
  42. // Callbacks will be released when the fetch completes or is stopped, so there is no need
  43. // to use weak self references in the callback blocks.
  44. //
  45. // Sample usage:
  46. //
  47. // _fetcherService = [[GTMSessionFetcherService alloc] init];
  48. //
  49. // GTMSessionFetcher *myFetcher = [_fetcherService fetcherWithURLString:myURLString];
  50. // myFetcher.retryEnabled = YES;
  51. // myFetcher.comment = @"First profile image";
  52. //
  53. // // Optionally specify a file URL or NSData for the request body to upload.
  54. // myFetcher.bodyData = [postString dataUsingEncoding:NSUTF8StringEncoding];
  55. //
  56. // [myFetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
  57. // if (error != nil) {
  58. // // Server status code or network error.
  59. // //
  60. // // If the domain is kGTMSessionFetcherStatusDomain then the error code
  61. // // is a failure status from the server.
  62. // } else {
  63. // // Fetch succeeded.
  64. // }
  65. // }];
  66. //
  67. // There is also a beginFetch call that takes a pointer and selector for the completion handler;
  68. // a pointer and selector is a better style when the callback is a substantial, separate method.
  69. //
  70. // NOTE: Fetches may retrieve data from the server even though the server
  71. // returned an error, so the criteria for success is a non-nil error.
  72. // The completion handler is called when the server status is >= 300 with an NSError
  73. // having domain kGTMSessionFetcherStatusDomain and code set to the server status.
  74. //
  75. // Status codes are at <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>
  76. //
  77. //
  78. // Background session support:
  79. //
  80. // Out-of-process uploads and downloads may be created by setting the fetcher's
  81. // useBackgroundSession property. Data to be uploaded should be provided via
  82. // the uploadFileURL property; the download destination should be specified with
  83. // the destinationFileURL. NOTE: Background upload files should be in a location
  84. // that will be valid even after the device is restarted, so the file should not
  85. // be uploaded from a system temporary or cache directory.
  86. //
  87. // Background session transfers are slower, and should typically be used only
  88. // for very large downloads or uploads (hundreds of megabytes).
  89. //
  90. // When background sessions are used in iOS apps, the application delegate must
  91. // pass through the parameters from UIApplicationDelegate's
  92. // application:handleEventsForBackgroundURLSession:completionHandler: to the
  93. // fetcher class.
  94. //
  95. // When the application has been relaunched, it may also create a new fetcher
  96. // instance to handle completion of the transfers.
  97. //
  98. // - (void)application:(UIApplication *)application
  99. // handleEventsForBackgroundURLSession:(NSString *)identifier
  100. // completionHandler:(void (^)())completionHandler {
  101. // // Application was re-launched on completing an out-of-process download.
  102. //
  103. // // Pass the URLSession info related to this re-launch to the fetcher class.
  104. // [GTMSessionFetcher application:application
  105. // handleEventsForBackgroundURLSession:identifier
  106. // completionHandler:completionHandler];
  107. //
  108. // // Get a fetcher related to this re-launch and re-hook up a completionHandler to it.
  109. // GTMSessionFetcher *fetcher = [GTMSessionFetcher fetcherWithSessionIdentifier:identifier];
  110. // NSURL *destinationFileURL = fetcher.destinationFileURL;
  111. // fetcher.completionHandler = ^(NSData *data, NSError *error) {
  112. // [self downloadCompletedToFile:destinationFileURL error:error];
  113. // };
  114. // }
  115. //
  116. //
  117. // Threading and queue support:
  118. //
  119. // Networking always happens on a background thread; there is no advantage to
  120. // changing thread or queue to create or start a fetcher.
  121. //
  122. // Callbacks are run on the main thread; alternatively, the app may set the
  123. // fetcher's callbackQueue to a dispatch queue.
  124. //
  125. // Once the fetcher's beginFetch method has been called, the fetcher's methods and
  126. // properties may be accessed from any thread.
  127. //
  128. // Downloading to disk:
  129. //
  130. // To have downloaded data saved directly to disk, specify a file URL for the
  131. // destinationFileURL property.
  132. //
  133. // HTTP methods and headers:
  134. //
  135. // Alternative HTTP methods, like PUT, and custom headers can be specified by
  136. // creating the fetcher with an appropriate NSMutableURLRequest.
  137. //
  138. //
  139. // Caching:
  140. //
  141. // The fetcher avoids caching. That is best for API requests, but may hurt
  142. // repeat fetches of static data. Apps may enable a persistent disk cache by
  143. // customizing the config:
  144. //
  145. // fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher,
  146. // NSURLSessionConfiguration *config) {
  147. // config.URLCache = [NSURLCache sharedURLCache];
  148. // };
  149. //
  150. // Or use the standard system config to share cookie storage with web views
  151. // and to enable disk caching:
  152. //
  153. // fetcher.configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
  154. //
  155. //
  156. // Cookies:
  157. //
  158. // There are three supported mechanisms for remembering cookies between fetches.
  159. //
  160. // By default, a standalone GTMSessionFetcher uses a mutable array held
  161. // statically to track cookies for all instantiated fetchers. This avoids
  162. // cookies being set by servers for the application from interfering with
  163. // Safari and WebKit cookie settings, and vice versa.
  164. // The fetcher cookies are lost when the application quits.
  165. //
  166. // To rely instead on WebKit's global NSHTTPCookieStorage, set the fetcher's
  167. // cookieStorage property:
  168. // myFetcher.cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
  169. //
  170. // To share cookies with other apps, use the method introduced in iOS 9/OS X 10.11:
  171. // myFetcher.cookieStorage =
  172. // [NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:kMyCompanyContainedID];
  173. //
  174. // To ignore existing cookies and only have cookies related to the single fetch
  175. // be applied, make a temporary cookie storage object:
  176. // myFetcher.cookieStorage = [[GTMSessionCookieStorage alloc] init];
  177. //
  178. // Note: cookies set while following redirects will be sent to the server, as
  179. // the redirects are followed by the fetcher.
  180. //
  181. // To completely disable cookies, similar to setting cookieStorageMethod to
  182. // kGTMHTTPFetcherCookieStorageMethodNone, adjust the session configuration
  183. // appropriately in the fetcher or fetcher service:
  184. // fetcher.configurationBlock = ^(GTMSessionFetcher *configFetcher,
  185. // NSURLSessionConfiguration *config) {
  186. // config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;
  187. // config.HTTPShouldSetCookies = NO;
  188. // };
  189. //
  190. // If the fetcher is created from a GTMSessionFetcherService object
  191. // then the cookie storage mechanism is set to use the cookie storage in the
  192. // service object rather than the static storage. Disabling cookies in the
  193. // session configuration set on a service object will disable cookies for all
  194. // fetchers created from that GTMSessionFetcherService object, since the session
  195. // configuration is propagated to the fetcher.
  196. //
  197. //
  198. // Monitoring data transfers.
  199. //
  200. // The fetcher supports a variety of properties for progress monitoring
  201. // progress with callback blocks.
  202. // GTMSessionFetcherSendProgressBlock sendProgressBlock
  203. // GTMSessionFetcherReceivedProgressBlock receivedProgressBlock
  204. // GTMSessionFetcherDownloadProgressBlock downloadProgressBlock
  205. //
  206. // If supplied by the server, the anticipated total download size is available
  207. // as [[myFetcher response] expectedContentLength] (and may be -1 for unknown
  208. // download sizes.)
  209. //
  210. //
  211. // Automatic retrying of fetches
  212. //
  213. // The fetcher can optionally create a timer and reattempt certain kinds of
  214. // fetch failures (status codes 408, request timeout; 502, gateway failure;
  215. // 503, service unavailable; 504, gateway timeout; networking errors
  216. // NSURLErrorTimedOut and NSURLErrorNetworkConnectionLost.) The user may
  217. // set a retry selector to customize the type of errors which will be retried.
  218. //
  219. // Retries are done in an exponential-backoff fashion (that is, after 1 second,
  220. // 2, 4, 8, and so on.)
  221. //
  222. // Enabling automatic retries looks like this:
  223. // myFetcher.retryEnabled = YES;
  224. //
  225. // With retries enabled, the completion callbacks are called only
  226. // when no more retries will be attempted. Calling the fetcher's stopFetching
  227. // method will terminate the retry timer, without the finished or failure
  228. // selectors being invoked.
  229. //
  230. // Optionally, the client may set the maximum retry interval:
  231. // myFetcher.maxRetryInterval = 60.0; // in seconds; default is 60 seconds
  232. // // for downloads, 600 for uploads
  233. //
  234. // Servers should never send a 400 or 500 status for errors that are retryable
  235. // by clients, as those values indicate permanent failures. In nearly all
  236. // cases, the default standard retry behavior is correct for clients, and no
  237. // custom client retry behavior is needed or appropriate. Servers that send
  238. // non-retryable status codes and expect the client to retry the request are
  239. // faulty.
  240. //
  241. // Still, the client may provide a block to determine if a status code or other
  242. // error should be retried. The block returns YES to set the retry timer or NO
  243. // to fail without additional fetch attempts.
  244. //
  245. // The retry method may return the |suggestedWillRetry| argument to get the
  246. // default retry behavior. Server status codes are present in the
  247. // error argument, and have the domain kGTMSessionFetcherStatusDomain. The
  248. // user's method may look something like this:
  249. //
  250. // myFetcher.retryBlock = ^(BOOL suggestedWillRetry, NSError *error,
  251. // GTMSessionFetcherRetryResponse response) {
  252. // // Perhaps examine error.domain and error.code, or fetcher.retryCount
  253. // //
  254. // // Respond with YES to start the retry timer, NO to proceed to the failure
  255. // // callback, or suggestedWillRetry to get default behavior for the
  256. // // current error domain and code values.
  257. // response(suggestedWillRetry);
  258. // };
  259. #import <Foundation/Foundation.h>
  260. #if TARGET_OS_IPHONE
  261. #import <UIKit/UIKit.h>
  262. #endif
  263. #if TARGET_OS_WATCH
  264. #import <WatchKit/WatchKit.h>
  265. #endif
  266. // By default it is stripped from non DEBUG builds. Developers can override
  267. // this in their project settings.
  268. #ifndef STRIP_GTM_FETCH_LOGGING
  269. #if !DEBUG
  270. #define STRIP_GTM_FETCH_LOGGING 1
  271. #else
  272. #define STRIP_GTM_FETCH_LOGGING 0
  273. #endif
  274. #endif
  275. // Logs in debug builds.
  276. #ifndef GTMSESSION_LOG_DEBUG
  277. #if DEBUG
  278. #define GTMSESSION_LOG_DEBUG(...) NSLog(__VA_ARGS__)
  279. #else
  280. #define GTMSESSION_LOG_DEBUG(...) do { } while (0)
  281. #endif
  282. #endif
  283. // Asserts in debug builds (or logs in debug builds if GTMSESSION_ASSERT_AS_LOG
  284. // or NS_BLOCK_ASSERTIONS are defined.)
  285. #ifndef GTMSESSION_ASSERT_DEBUG
  286. #if DEBUG && !defined(NS_BLOCK_ASSERTIONS) && !GTMSESSION_ASSERT_AS_LOG
  287. #undef GTMSESSION_ASSERT_AS_LOG
  288. #define GTMSESSION_ASSERT_AS_LOG 1
  289. #endif
  290. #if DEBUG && !GTMSESSION_ASSERT_AS_LOG
  291. #define GTMSESSION_ASSERT_DEBUG(...) NSAssert(__VA_ARGS__)
  292. #elif DEBUG
  293. #define GTMSESSION_ASSERT_DEBUG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); }
  294. #else
  295. #define GTMSESSION_ASSERT_DEBUG(pred, ...) do { } while (0)
  296. #endif
  297. #endif
  298. // Asserts in debug builds, logs in release builds (or logs in debug builds if
  299. // GTMSESSION_ASSERT_AS_LOG is defined.)
  300. #ifndef GTMSESSION_ASSERT_DEBUG_OR_LOG
  301. #if DEBUG && !GTMSESSION_ASSERT_AS_LOG
  302. #define GTMSESSION_ASSERT_DEBUG_OR_LOG(...) NSAssert(__VA_ARGS__)
  303. #else
  304. #define GTMSESSION_ASSERT_DEBUG_OR_LOG(pred, ...) if (!(pred)) { NSLog(__VA_ARGS__); }
  305. #endif
  306. #endif
  307. // Macro useful for examining messages from NSURLSession during debugging.
  308. #if 0
  309. #define GTM_LOG_SESSION_DELEGATE(...) GTMSESSION_LOG_DEBUG(__VA_ARGS__)
  310. #else
  311. #define GTM_LOG_SESSION_DELEGATE(...)
  312. #endif
  313. #ifndef GTM_NULLABLE
  314. #if __has_feature(nullability) // Available starting in Xcode 6.3
  315. #define GTM_NULLABLE_TYPE __nullable
  316. #define GTM_NONNULL_TYPE __nonnull
  317. #define GTM_NULLABLE nullable
  318. #define GTM_NONNULL_DECL nonnull // GTM_NONNULL is used by GTMDefines.h
  319. #define GTM_NULL_RESETTABLE null_resettable
  320. #define GTM_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
  321. #define GTM_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
  322. #else
  323. #define GTM_NULLABLE_TYPE
  324. #define GTM_NONNULL_TYPE
  325. #define GTM_NULLABLE
  326. #define GTM_NONNULL_DECL
  327. #define GTM_NULL_RESETTABLE
  328. #define GTM_ASSUME_NONNULL_BEGIN
  329. #define GTM_ASSUME_NONNULL_END
  330. #endif // __has_feature(nullability)
  331. #endif // GTM_NULLABLE
  332. #ifndef GTM_DECLARE_GENERICS
  333. #if __has_feature(objc_generics)
  334. #define GTM_DECLARE_GENERICS 1
  335. #else
  336. #define GTM_DECLARE_GENERICS 0
  337. #endif
  338. #endif
  339. #ifndef GTM_NSArrayOf
  340. #if GTM_DECLARE_GENERICS
  341. #define GTM_NSArrayOf(value) NSArray<value>
  342. #define GTM_NSDictionaryOf(key, value) NSDictionary<key, value>
  343. #else
  344. #define GTM_NSArrayOf(value) NSArray
  345. #define GTM_NSDictionaryOf(key, value) NSDictionary
  346. #endif // __has_feature(objc_generics)
  347. #endif // GTM_NSArrayOf
  348. // For iOS, the fetcher can declare itself a background task to allow fetches
  349. // to finish when the app leaves the foreground.
  350. //
  351. // (This is unrelated to providing a background configuration, which allows
  352. // out-of-process uploads and downloads.)
  353. //
  354. // To disallow use of background tasks during fetches, the target should define
  355. // GTM_BACKGROUND_TASK_FETCHING to 0, or alternatively may set the
  356. // skipBackgroundTask property to YES.
  357. #if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !defined(GTM_BACKGROUND_TASK_FETCHING)
  358. #define GTM_BACKGROUND_TASK_FETCHING 1
  359. #endif
  360. #ifdef __cplusplus
  361. extern "C" {
  362. #endif
  363. #if (TARGET_OS_TV \
  364. || TARGET_OS_WATCH \
  365. || (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_11) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_11) \
  366. || (TARGET_OS_IPHONE && defined(__IPHONE_9_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0))
  367. #ifndef GTM_USE_SESSION_FETCHER
  368. #define GTM_USE_SESSION_FETCHER 1
  369. #endif
  370. #endif
  371. #if !defined(GTMBridgeFetcher)
  372. // These bridge macros should be identical in GTMHTTPFetcher.h and GTMSessionFetcher.h
  373. #if GTM_USE_SESSION_FETCHER
  374. // Macros to new fetcher class.
  375. #define GTMBridgeFetcher GTMSessionFetcher
  376. #define GTMBridgeFetcherService GTMSessionFetcherService
  377. #define GTMBridgeFetcherServiceProtocol GTMSessionFetcherServiceProtocol
  378. #define GTMBridgeAssertValidSelector GTMSessionFetcherAssertValidSelector
  379. #define GTMBridgeCookieStorage GTMSessionCookieStorage
  380. #define GTMBridgeCleanedUserAgentString GTMFetcherCleanedUserAgentString
  381. #define GTMBridgeSystemVersionString GTMFetcherSystemVersionString
  382. #define GTMBridgeApplicationIdentifier GTMFetcherApplicationIdentifier
  383. #define kGTMBridgeFetcherStatusDomain kGTMSessionFetcherStatusDomain
  384. #define kGTMBridgeFetcherStatusBadRequest GTMSessionFetcherStatusBadRequest
  385. #else
  386. // Macros to old fetcher class.
  387. #define GTMBridgeFetcher GTMHTTPFetcher
  388. #define GTMBridgeFetcherService GTMHTTPFetcherService
  389. #define GTMBridgeFetcherServiceProtocol GTMHTTPFetcherServiceProtocol
  390. #define GTMBridgeAssertValidSelector GTMAssertSelectorNilOrImplementedWithArgs
  391. #define GTMBridgeCookieStorage GTMCookieStorage
  392. #define GTMBridgeCleanedUserAgentString GTMCleanedUserAgentString
  393. #define GTMBridgeSystemVersionString GTMSystemVersionString
  394. #define GTMBridgeApplicationIdentifier GTMApplicationIdentifier
  395. #define kGTMBridgeFetcherStatusDomain kGTMHTTPFetcherStatusDomain
  396. #define kGTMBridgeFetcherStatusBadRequest kGTMHTTPFetcherStatusBadRequest
  397. #endif // GTM_USE_SESSION_FETCHER
  398. #endif
  399. // When creating background sessions to perform out-of-process uploads and
  400. // downloads, on app launch any background sessions must be reconnected in
  401. // order to receive events that occurred while the app was not running.
  402. //
  403. // The fetcher will automatically attempt to recreate the sessions on app
  404. // start, but doing so reads from NSUserDefaults. This may have launch-time
  405. // performance impacts.
  406. //
  407. // To avoid launch performance impacts, on iPhone/iPad with iOS 13+ the
  408. // GTMSessionFetcher class will register for the app launch notification and
  409. // perform the reconnect then.
  410. //
  411. // Apps targeting Mac or older iOS SDKs can opt into the new behavior by defining
  412. // GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH=1.
  413. //
  414. // Apps targeting new SDKs can force the old behavior by defining
  415. // GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH = 0.
  416. #ifndef GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH
  417. // Default to the on-launch behavior for iOS 13+.
  418. #if TARGET_OS_IOS && defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
  419. #define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 1
  420. #else
  421. #define GTMSESSION_RECONNECT_BACKGROUND_SESSIONS_ON_LAUNCH 0
  422. #endif
  423. #endif
  424. GTM_ASSUME_NONNULL_BEGIN
  425. // Notifications
  426. //
  427. // Fetch started and stopped, and fetch retry delay started and stopped.
  428. extern NSString *const kGTMSessionFetcherStartedNotification;
  429. extern NSString *const kGTMSessionFetcherStoppedNotification;
  430. extern NSString *const kGTMSessionFetcherRetryDelayStartedNotification;
  431. extern NSString *const kGTMSessionFetcherRetryDelayStoppedNotification;
  432. // Completion handler notification. This is intended for use by code capturing
  433. // and replaying fetch requests and results for testing. For fetches where
  434. // destinationFileURL or accumulateDataBlock is set for the fetcher, the data
  435. // will be nil for successful fetches.
  436. //
  437. // This notification is posted on the main thread.
  438. extern NSString *const kGTMSessionFetcherCompletionInvokedNotification;
  439. extern NSString *const kGTMSessionFetcherCompletionDataKey;
  440. extern NSString *const kGTMSessionFetcherCompletionErrorKey;
  441. // Constants for NSErrors created by the fetcher (excluding server status errors,
  442. // and error objects originating in the OS.)
  443. extern NSString *const kGTMSessionFetcherErrorDomain;
  444. // The fetcher turns server error status values (3XX, 4XX, 5XX) into NSErrors
  445. // with domain kGTMSessionFetcherStatusDomain.
  446. //
  447. // Any server response body data accompanying the status error is added to the
  448. // userInfo dictionary with key kGTMSessionFetcherStatusDataKey.
  449. extern NSString *const kGTMSessionFetcherStatusDomain;
  450. extern NSString *const kGTMSessionFetcherStatusDataKey;
  451. extern NSString *const kGTMSessionFetcherStatusDataContentTypeKey;
  452. // When a fetch fails with an error, these keys are included in the error userInfo
  453. // dictionary if retries were attempted.
  454. extern NSString *const kGTMSessionFetcherNumberOfRetriesDoneKey;
  455. extern NSString *const kGTMSessionFetcherElapsedIntervalWithRetriesKey;
  456. // Background session support requires access to NSUserDefaults.
  457. // If [NSUserDefaults standardUserDefaults] doesn't yield the correct NSUserDefaults for your usage,
  458. // ie for an App Extension, then implement this class/method to return the correct NSUserDefaults.
  459. // https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW6
  460. @interface GTMSessionFetcherUserDefaultsFactory : NSObject
  461. + (NSUserDefaults *)fetcherUserDefaults;
  462. @end
  463. #ifdef __cplusplus
  464. }
  465. #endif
  466. typedef NS_ENUM(NSInteger, GTMSessionFetcherError) {
  467. GTMSessionFetcherErrorDownloadFailed = -1,
  468. GTMSessionFetcherErrorUploadChunkUnavailable = -2,
  469. GTMSessionFetcherErrorBackgroundExpiration = -3,
  470. GTMSessionFetcherErrorBackgroundFetchFailed = -4,
  471. GTMSessionFetcherErrorInsecureRequest = -5,
  472. GTMSessionFetcherErrorTaskCreationFailed = -6,
  473. };
  474. typedef NS_ENUM(NSInteger, GTMSessionFetcherStatus) {
  475. // Standard http status codes.
  476. GTMSessionFetcherStatusNotModified = 304,
  477. GTMSessionFetcherStatusBadRequest = 400,
  478. GTMSessionFetcherStatusUnauthorized = 401,
  479. GTMSessionFetcherStatusForbidden = 403,
  480. GTMSessionFetcherStatusPreconditionFailed = 412
  481. };
  482. #ifdef __cplusplus
  483. extern "C" {
  484. #endif
  485. @class GTMSessionCookieStorage;
  486. @class GTMSessionFetcher;
  487. // The configuration block is for modifying the NSURLSessionConfiguration only.
  488. // DO NOT change any fetcher properties in the configuration block.
  489. typedef void (^GTMSessionFetcherConfigurationBlock)(GTMSessionFetcher *fetcher,
  490. NSURLSessionConfiguration *configuration);
  491. typedef void (^GTMSessionFetcherSystemCompletionHandler)(void);
  492. typedef void (^GTMSessionFetcherCompletionHandler)(NSData * GTM_NULLABLE_TYPE data,
  493. NSError * GTM_NULLABLE_TYPE error);
  494. typedef void (^GTMSessionFetcherBodyStreamProviderResponse)(NSInputStream *bodyStream);
  495. typedef void (^GTMSessionFetcherBodyStreamProvider)(GTMSessionFetcherBodyStreamProviderResponse response);
  496. typedef void (^GTMSessionFetcherDidReceiveResponseDispositionBlock)(NSURLSessionResponseDisposition disposition);
  497. typedef void (^GTMSessionFetcherDidReceiveResponseBlock)(NSURLResponse *response,
  498. GTMSessionFetcherDidReceiveResponseDispositionBlock dispositionBlock);
  499. typedef void (^GTMSessionFetcherChallengeDispositionBlock)(NSURLSessionAuthChallengeDisposition disposition,
  500. NSURLCredential * GTM_NULLABLE_TYPE credential);
  501. typedef void (^GTMSessionFetcherChallengeBlock)(GTMSessionFetcher *fetcher,
  502. NSURLAuthenticationChallenge *challenge,
  503. GTMSessionFetcherChallengeDispositionBlock dispositionBlock);
  504. typedef void (^GTMSessionFetcherWillRedirectResponse)(NSURLRequest * GTM_NULLABLE_TYPE redirectedRequest);
  505. typedef void (^GTMSessionFetcherWillRedirectBlock)(NSHTTPURLResponse *redirectResponse,
  506. NSURLRequest *redirectRequest,
  507. GTMSessionFetcherWillRedirectResponse response);
  508. typedef void (^GTMSessionFetcherAccumulateDataBlock)(NSData * GTM_NULLABLE_TYPE buffer);
  509. typedef void (^GTMSessionFetcherSimulateByteTransferBlock)(NSData * GTM_NULLABLE_TYPE buffer,
  510. int64_t bytesWritten,
  511. int64_t totalBytesWritten,
  512. int64_t totalBytesExpectedToWrite);
  513. typedef void (^GTMSessionFetcherReceivedProgressBlock)(int64_t bytesWritten,
  514. int64_t totalBytesWritten);
  515. typedef void (^GTMSessionFetcherDownloadProgressBlock)(int64_t bytesWritten,
  516. int64_t totalBytesWritten,
  517. int64_t totalBytesExpectedToWrite);
  518. typedef void (^GTMSessionFetcherSendProgressBlock)(int64_t bytesSent,
  519. int64_t totalBytesSent,
  520. int64_t totalBytesExpectedToSend);
  521. typedef void (^GTMSessionFetcherWillCacheURLResponseResponse)(NSCachedURLResponse * GTM_NULLABLE_TYPE cachedResponse);
  522. typedef void (^GTMSessionFetcherWillCacheURLResponseBlock)(NSCachedURLResponse *proposedResponse,
  523. GTMSessionFetcherWillCacheURLResponseResponse responseBlock);
  524. typedef void (^GTMSessionFetcherRetryResponse)(BOOL shouldRetry);
  525. typedef void (^GTMSessionFetcherRetryBlock)(BOOL suggestedWillRetry,
  526. NSError * GTM_NULLABLE_TYPE error,
  527. GTMSessionFetcherRetryResponse response);
  528. API_AVAILABLE(ios(10.0), macosx(10.12), tvos(10.0), watchos(3.0))
  529. typedef void (^GTMSessionFetcherMetricsCollectionBlock)(NSURLSessionTaskMetrics *metrics);
  530. typedef void (^GTMSessionFetcherTestResponse)(NSHTTPURLResponse * GTM_NULLABLE_TYPE response,
  531. NSData * GTM_NULLABLE_TYPE data,
  532. NSError * GTM_NULLABLE_TYPE error);
  533. typedef void (^GTMSessionFetcherTestBlock)(GTMSessionFetcher *fetcherToTest,
  534. GTMSessionFetcherTestResponse testResponse);
  535. void GTMSessionFetcherAssertValidSelector(id GTM_NULLABLE_TYPE obj, SEL GTM_NULLABLE_TYPE sel, ...);
  536. // Utility functions for applications self-identifying to servers via a
  537. // user-agent header
  538. // The "standard" user agent includes the application identifier, taken from the bundle,
  539. // followed by a space and the system version string. Pass nil to use +mainBundle as the source
  540. // of the bundle identifier.
  541. //
  542. // Applications may use this as a starting point for their own user agent strings, perhaps
  543. // with additional sections appended. Use GTMFetcherCleanedUserAgentString() below to
  544. // clean up any string being added to the user agent.
  545. NSString *GTMFetcherStandardUserAgentString(NSBundle * GTM_NULLABLE_TYPE bundle);
  546. // Make a generic name and version for the current application, like
  547. // com.example.MyApp/1.2.3 relying on the bundle identifier and the
  548. // CFBundleShortVersionString or CFBundleVersion.
  549. //
  550. // The bundle ID may be overridden as the base identifier string by
  551. // adding to the bundle's Info.plist a "GTMUserAgentID" key.
  552. //
  553. // If no bundle ID or override is available, the process name preceded
  554. // by "proc_" is used.
  555. NSString *GTMFetcherApplicationIdentifier(NSBundle * GTM_NULLABLE_TYPE bundle);
  556. // Make an identifier like "MacOSX/10.7.1" or "iPod_Touch/4.1 hw/iPod1_1"
  557. NSString *GTMFetcherSystemVersionString(void);
  558. // Make a parseable user-agent identifier from the given string, replacing whitespace
  559. // and commas with underscores, and removing other characters that may interfere
  560. // with parsing of the full user-agent string.
  561. //
  562. // For example, @"[My App]" would become @"My_App"
  563. NSString *GTMFetcherCleanedUserAgentString(NSString *str);
  564. // Grab the data from an input stream. Since streams cannot be assumed to be rewindable,
  565. // this may be destructive; the caller can try to rewind the stream (by setting the
  566. // NSStreamFileCurrentOffsetKey property) or can just use the NSData to make a new
  567. // NSInputStream. This function is intended to facilitate testing rather than be used in
  568. // production.
  569. //
  570. // This function operates synchronously on the current thread. Depending on how the
  571. // input stream is implemented, it may be appropriate to dispatch to a different
  572. // queue before calling this function.
  573. //
  574. // Failure is indicated by a returned data value of nil.
  575. NSData * GTM_NULLABLE_TYPE GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError);
  576. #ifdef __cplusplus
  577. } // extern "C"
  578. #endif
  579. #if !GTM_USE_SESSION_FETCHER
  580. @protocol GTMHTTPFetcherServiceProtocol;
  581. #endif
  582. // This protocol allows abstract references to the fetcher service, primarily for
  583. // fetchers (which may be compiled without the fetcher service class present.)
  584. //
  585. // Apps should not need to use this protocol.
  586. @protocol GTMSessionFetcherServiceProtocol <NSObject>
  587. // This protocol allows us to call into the service without requiring
  588. // GTMSessionFetcherService sources in this project
  589. @property(atomic, strong) dispatch_queue_t callbackQueue;
  590. - (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher;
  591. - (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher;
  592. - (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher;
  593. - (void)fetcherDidStop:(GTMSessionFetcher *)fetcher;
  594. - (GTMSessionFetcher *)fetcherWithRequest:(NSURLRequest *)request;
  595. - (BOOL)isDelayingFetcher:(GTMSessionFetcher *)fetcher;
  596. @property(atomic, assign) BOOL reuseSession;
  597. - (GTM_NULLABLE NSURLSession *)session;
  598. - (GTM_NULLABLE NSURLSession *)sessionForFetcherCreation;
  599. - (GTM_NULLABLE id<NSURLSessionDelegate>)sessionDelegate;
  600. - (GTM_NULLABLE NSDate *)stoppedAllFetchersDate;
  601. // Methods for compatibility with the old GTMHTTPFetcher.
  602. @property(atomic, readonly, strong, GTM_NULLABLE) NSOperationQueue *delegateQueue;
  603. @end // @protocol GTMSessionFetcherServiceProtocol
  604. #ifndef GTM_FETCHER_AUTHORIZATION_PROTOCOL
  605. #define GTM_FETCHER_AUTHORIZATION_PROTOCOL 1
  606. @protocol GTMFetcherAuthorizationProtocol <NSObject>
  607. @required
  608. // This protocol allows us to call the authorizer without requiring its sources
  609. // in this project.
  610. - (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request
  611. delegate:(id)delegate
  612. didFinishSelector:(SEL)sel;
  613. - (void)stopAuthorization;
  614. - (void)stopAuthorizationForRequest:(NSURLRequest *)request;
  615. - (BOOL)isAuthorizingRequest:(NSURLRequest *)request;
  616. - (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
  617. @property(atomic, strong, readonly, GTM_NULLABLE) NSString *userEmail;
  618. @optional
  619. // Indicate if authorization may be attempted. Even if this succeeds,
  620. // authorization may fail if the user's permissions have been revoked.
  621. @property(atomic, readonly) BOOL canAuthorize;
  622. // For development only, allow authorization of non-SSL requests, allowing
  623. // transmission of the bearer token unencrypted.
  624. @property(atomic, assign) BOOL shouldAuthorizeAllRequests;
  625. - (void)authorizeRequest:(GTM_NULLABLE NSMutableURLRequest *)request
  626. completionHandler:(void (^)(NSError * GTM_NULLABLE_TYPE error))handler;
  627. #if GTM_USE_SESSION_FETCHER
  628. @property(atomic, weak, GTM_NULLABLE) id<GTMSessionFetcherServiceProtocol> fetcherService;
  629. #else
  630. @property(atomic, weak, GTM_NULLABLE) id<GTMHTTPFetcherServiceProtocol> fetcherService;
  631. #endif
  632. - (BOOL)primeForRefresh;
  633. @end
  634. #endif // GTM_FETCHER_AUTHORIZATION_PROTOCOL
  635. #if GTM_BACKGROUND_TASK_FETCHING
  636. // A protocol for an alternative target for messages from GTMSessionFetcher to UIApplication.
  637. // Set the target using +[GTMSessionFetcher setSubstituteUIApplication:]
  638. @protocol GTMUIApplicationProtocol <NSObject>
  639. - (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName
  640. expirationHandler:(void(^ __nullable)(void))handler;
  641. - (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier;
  642. @end
  643. #endif
  644. #pragma mark -
  645. // GTMSessionFetcher objects are used for async retrieval of an http get or post
  646. //
  647. // See additional comments at the beginning of this file
  648. @interface GTMSessionFetcher : NSObject <NSURLSessionDelegate>
  649. // Create a fetcher
  650. //
  651. // fetcherWithRequest will return an autoreleased fetcher, but if
  652. // the connection is successfully created, the connection should retain the
  653. // fetcher for the life of the connection as well. So the caller doesn't have
  654. // to retain the fetcher explicitly unless they want to be able to cancel it.
  655. + (instancetype)fetcherWithRequest:(GTM_NULLABLE NSURLRequest *)request;
  656. // Convenience methods that make a request, like +fetcherWithRequest
  657. + (instancetype)fetcherWithURL:(NSURL *)requestURL;
  658. + (instancetype)fetcherWithURLString:(NSString *)requestURLString;
  659. // Methods for creating fetchers to continue previous fetches.
  660. + (instancetype)fetcherWithDownloadResumeData:(NSData *)resumeData;
  661. + (GTM_NULLABLE instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier;
  662. // Returns an array of currently active fetchers for background sessions,
  663. // both restarted and newly created ones.
  664. + (GTM_NSArrayOf(GTMSessionFetcher *) *)fetchersForBackgroundSessions;
  665. // Designated initializer.
  666. //
  667. // Applications should create fetchers with a "fetcherWith..." method on a fetcher
  668. // service or a class method, not with this initializer.
  669. //
  670. // The configuration should typically be nil. Applications needing to customize
  671. // the configuration may do so by setting the configurationBlock property.
  672. - (instancetype)initWithRequest:(GTM_NULLABLE NSURLRequest *)request
  673. configuration:(GTM_NULLABLE NSURLSessionConfiguration *)configuration;
  674. // The fetcher's request. This may not be set after beginFetch has been invoked. The request
  675. // may change due to redirects.
  676. @property(atomic, strong, GTM_NULLABLE) NSURLRequest *request;
  677. // Set a header field value on the request. Header field value changes will not
  678. // affect a fetch after the fetch has begun.
  679. - (void)setRequestValue:(GTM_NULLABLE NSString *)value forHTTPHeaderField:(NSString *)field;
  680. // Data used for resuming a download task.
  681. @property(atomic, readonly, GTM_NULLABLE) NSData *downloadResumeData;
  682. // The configuration; this must be set before the fetch begins. If no configuration is
  683. // set or inherited from the fetcher service, then the fetcher uses an ephemeral config.
  684. //
  685. // NOTE: This property should typically be nil. Applications needing to customize
  686. // the configuration should do so by setting the configurationBlock property.
  687. // That allows the fetcher to pick an appropriate base configuration, with the
  688. // application setting only the configuration properties it needs to customize.
  689. @property(atomic, strong, GTM_NULLABLE) NSURLSessionConfiguration *configuration;
  690. // A block the client may use to customize the configuration used to create the session.
  691. //
  692. // This is called synchronously, either on the thread that begins the fetch or, during a retry,
  693. // on the main thread. The configuration block may be called repeatedly if multiple fetchers are
  694. // created.
  695. //
  696. // The configuration block is for modifying the NSURLSessionConfiguration only.
  697. // DO NOT change any fetcher properties in the configuration block. Fetcher properties
  698. // may be set in the fetcher service prior to fetcher creation, or on the fetcher prior
  699. // to invoking beginFetch.
  700. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherConfigurationBlock configurationBlock;
  701. // A session is created as needed by the fetcher. A fetcher service object
  702. // may maintain sessions for multiple fetches to the same host.
  703. @property(atomic, strong, GTM_NULLABLE) NSURLSession *session;
  704. // The task in flight.
  705. @property(atomic, readonly, GTM_NULLABLE) NSURLSessionTask *sessionTask;
  706. // The background session identifier.
  707. @property(atomic, readonly, GTM_NULLABLE) NSString *sessionIdentifier;
  708. // Indicates a fetcher created to finish a background session task.
  709. @property(atomic, readonly) BOOL wasCreatedFromBackgroundSession;
  710. // Additional user-supplied data to encode into the session identifier. Since session identifier
  711. // length limits are unspecified, this should be kept small. Key names beginning with an underscore
  712. // are reserved for use by the fetcher.
  713. @property(atomic, strong, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *sessionUserInfo;
  714. // The human-readable description to be assigned to the task.
  715. @property(atomic, copy, GTM_NULLABLE) NSString *taskDescription;
  716. // The priority assigned to the task, if any. Use NSURLSessionTaskPriorityLow,
  717. // NSURLSessionTaskPriorityDefault, or NSURLSessionTaskPriorityHigh.
  718. @property(atomic, assign) float taskPriority;
  719. // The fetcher encodes information used to resume a session in the session identifier.
  720. // This method, intended for internal use returns the encoded information. The sessionUserInfo
  721. // dictionary is stored as identifier metadata.
  722. - (GTM_NULLABLE GTM_NSDictionaryOf(NSString *, NSString *) *)sessionIdentifierMetadata;
  723. #if TARGET_OS_IPHONE && !TARGET_OS_WATCH
  724. // The app should pass to this method the completion handler passed in the app delegate method
  725. // application:handleEventsForBackgroundURLSession:completionHandler:
  726. + (void)application:(UIApplication *)application
  727. handleEventsForBackgroundURLSession:(NSString *)identifier
  728. completionHandler:(GTMSessionFetcherSystemCompletionHandler)completionHandler;
  729. #endif
  730. // Indicate that a newly created session should be a background session.
  731. // A new session identifier will be created by the fetcher.
  732. //
  733. // Warning: The only thing background sessions are for is rare download
  734. // of huge, batched files of data. And even just for those, there's a lot
  735. // of pain and hackery needed to get transfers to actually happen reliably
  736. // with background sessions.
  737. //
  738. // Don't try to upload or download in many background sessions, since the system
  739. // will impose an exponentially increasing time penalty to prevent the app from
  740. // getting too much background execution time.
  741. //
  742. // References:
  743. //
  744. // "Moving to Fewer, Larger Transfers"
  745. // https://forums.developer.apple.com/thread/14853
  746. //
  747. // "NSURLSession’s Resume Rate Limiter"
  748. // https://forums.developer.apple.com/thread/14854
  749. //
  750. // "Background Session Task state persistence"
  751. // https://forums.developer.apple.com/thread/11554
  752. //
  753. @property(atomic, assign) BOOL useBackgroundSession;
  754. // Indicates if the fetcher was started using a background session.
  755. @property(atomic, readonly, getter=isUsingBackgroundSession) BOOL usingBackgroundSession;
  756. // Indicates if uploads should use an upload task. This is always set for file or stream-provider
  757. // bodies, but may be set explicitly for NSData bodies.
  758. @property(atomic, assign) BOOL useUploadTask;
  759. // Indicates that the fetcher is using a session that may be shared with other fetchers.
  760. @property(atomic, readonly) BOOL canShareSession;
  761. // By default, the fetcher allows only secure (https) schemes unless this
  762. // property is set, or the GTM_ALLOW_INSECURE_REQUESTS build flag is set.
  763. //
  764. // For example, during debugging when fetching from a development server that lacks SSL support,
  765. // this may be set to @[ @"http" ], or when the fetcher is used to retrieve local files,
  766. // this may be set to @[ @"file" ].
  767. //
  768. // This should be left as nil for release builds to avoid creating the opportunity for
  769. // leaking private user behavior and data. If a server is providing insecure URLs
  770. // for fetching by the client app, report the problem as server security & privacy bug.
  771. //
  772. // For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when
  773. // the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist.
  774. @property(atomic, copy, GTM_NULLABLE) GTM_NSArrayOf(NSString *) *allowedInsecureSchemes;
  775. // By default, the fetcher prohibits localhost requests unless this property is set,
  776. // or the GTM_ALLOW_INSECURE_REQUESTS build flag is set.
  777. //
  778. // For localhost requests, the URL scheme is not checked when this property is set.
  779. //
  780. // For builds with the iOS 9/OS X 10.11 and later SDKs, this property is required only when
  781. // the app specifies NSAppTransportSecurity/NSAllowsArbitraryLoads in the main bundle's Info.plist.
  782. @property(atomic, assign) BOOL allowLocalhostRequest;
  783. // By default, the fetcher requires valid server certs. This may be bypassed
  784. // temporarily for development against a test server with an invalid cert.
  785. @property(atomic, assign) BOOL allowInvalidServerCertificates;
  786. // Cookie storage object for this fetcher. If nil, the fetcher will use a static cookie
  787. // storage instance shared among fetchers. If this fetcher was created by a fetcher service
  788. // object, it will be set to use the service object's cookie storage. See Cookies section above for
  789. // the full discussion.
  790. //
  791. // Because as of Jan 2014 standalone instances of NSHTTPCookieStorage do not actually
  792. // store any cookies (Radar 15735276) we use our own subclass, GTMSessionCookieStorage,
  793. // to hold cookies in memory.
  794. @property(atomic, strong, GTM_NULLABLE) NSHTTPCookieStorage *cookieStorage;
  795. // Setting the credential is optional; it is used if the connection receives
  796. // an authentication challenge.
  797. @property(atomic, strong, GTM_NULLABLE) NSURLCredential *credential;
  798. // Setting the proxy credential is optional; it is used if the connection
  799. // receives an authentication challenge from a proxy.
  800. @property(atomic, strong, GTM_NULLABLE) NSURLCredential *proxyCredential;
  801. // If body data, body file URL, or body stream provider is not set, then a GET request
  802. // method is assumed.
  803. @property(atomic, strong, GTM_NULLABLE) NSData *bodyData;
  804. // File to use as the request body. This forces use of an upload task.
  805. @property(atomic, strong, GTM_NULLABLE) NSURL *bodyFileURL;
  806. // Length of body to send, expected or actual.
  807. @property(atomic, readonly) int64_t bodyLength;
  808. // The body stream provider may be called repeatedly to provide a body.
  809. // Setting a body stream provider forces use of an upload task.
  810. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherBodyStreamProvider bodyStreamProvider;
  811. // Object to add authorization to the request, if needed.
  812. //
  813. // This may not be changed once beginFetch has been invoked.
  814. @property(atomic, strong, GTM_NULLABLE) id<GTMFetcherAuthorizationProtocol> authorizer;
  815. // The service object that created and monitors this fetcher, if any.
  816. @property(atomic, strong) id<GTMSessionFetcherServiceProtocol> service;
  817. // The host, if any, used to classify this fetcher in the fetcher service.
  818. @property(atomic, copy, GTM_NULLABLE) NSString *serviceHost;
  819. // The priority, if any, used for starting fetchers in the fetcher service.
  820. //
  821. // Lower values are higher priority; the default is 0, and values may
  822. // be negative or positive. This priority affects only the start order of
  823. // fetchers that are being delayed by a fetcher service when the running fetchers
  824. // exceeds the service's maxRunningFetchersPerHost. A priority of NSIntegerMin will
  825. // exempt this fetcher from delay.
  826. @property(atomic, assign) NSInteger servicePriority;
  827. // The delegate's optional didReceiveResponse block may be used to inspect or alter
  828. // the session task response.
  829. //
  830. // This is called on the callback queue.
  831. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDidReceiveResponseBlock didReceiveResponseBlock;
  832. // The delegate's optional challenge block may be used to inspect or alter
  833. // the session task challenge.
  834. //
  835. // If this block is not set, the fetcher's default behavior for the NSURLSessionTask
  836. // didReceiveChallenge: delegate method is to use the fetcher's respondToChallenge: method
  837. // which relies on the fetcher's credential and proxyCredential properties.
  838. //
  839. // Warning: This may be called repeatedly if the challenge fails. Check
  840. // challenge.previousFailureCount to identify repeated invocations.
  841. //
  842. // This is called on the callback queue.
  843. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherChallengeBlock challengeBlock;
  844. // The delegate's optional willRedirect block may be used to inspect or alter
  845. // the redirection.
  846. //
  847. // This is called on the callback queue.
  848. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillRedirectBlock willRedirectBlock;
  849. // The optional send progress block reports body bytes uploaded.
  850. //
  851. // This is called on the callback queue.
  852. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherSendProgressBlock sendProgressBlock;
  853. // The optional accumulate block may be set by clients wishing to accumulate data
  854. // themselves rather than let the fetcher append each buffer to an NSData.
  855. //
  856. // When this is called with nil data (such as on redirect) the client
  857. // should empty its accumulation buffer.
  858. //
  859. // This is called on the callback queue.
  860. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherAccumulateDataBlock accumulateDataBlock;
  861. // The optional received progress block may be used to monitor data
  862. // received from a data task.
  863. //
  864. // This is called on the callback queue.
  865. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherReceivedProgressBlock receivedProgressBlock;
  866. // The delegate's optional downloadProgress block may be used to monitor download
  867. // progress in writing to disk.
  868. //
  869. // This is called on the callback queue.
  870. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherDownloadProgressBlock downloadProgressBlock;
  871. // The delegate's optional willCacheURLResponse block may be used to alter the cached
  872. // NSURLResponse. The user may prevent caching by passing nil to the block's response.
  873. //
  874. // This is called on the callback queue.
  875. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherWillCacheURLResponseBlock willCacheURLResponseBlock;
  876. // Enable retrying; see comments at the top of this file. Setting
  877. // retryEnabled=YES resets the min and max retry intervals.
  878. @property(atomic, assign, getter=isRetryEnabled) BOOL retryEnabled;
  879. // Retry block is optional for retries.
  880. //
  881. // If present, this block should call the response block with YES to cause a retry or NO to end the
  882. // fetch.
  883. // See comments at the top of this file.
  884. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherRetryBlock retryBlock;
  885. // The optional block for collecting the metrics of the present session.
  886. //
  887. // This is called on the callback queue.
  888. @property(atomic, copy, GTM_NULLABLE)
  889. GTMSessionFetcherMetricsCollectionBlock metricsCollectionBlock API_AVAILABLE(
  890. ios(10.0), macosx(10.12), tvos(10.0), watchos(3.0));
  891. // Retry intervals must be strictly less than maxRetryInterval, else
  892. // they will be limited to maxRetryInterval and no further retries will
  893. // be attempted. Setting maxRetryInterval to 0.0 will reset it to the
  894. // default value, 60 seconds for downloads and 600 seconds for uploads.
  895. @property(atomic, assign) NSTimeInterval maxRetryInterval;
  896. // Starting retry interval. Setting minRetryInterval to 0.0 will reset it
  897. // to a random value between 1.0 and 2.0 seconds. Clients should normally not
  898. // set this except for unit testing.
  899. @property(atomic, assign) NSTimeInterval minRetryInterval;
  900. // Multiplier used to increase the interval between retries, typically 2.0.
  901. // Clients should not need to set this.
  902. @property(atomic, assign) double retryFactor;
  903. // Number of retries attempted.
  904. @property(atomic, readonly) NSUInteger retryCount;
  905. // Interval delay to precede next retry.
  906. @property(atomic, readonly) NSTimeInterval nextRetryInterval;
  907. #if GTM_BACKGROUND_TASK_FETCHING
  908. // Skip use of a UIBackgroundTask, thus requiring fetches to complete when the app is in the
  909. // foreground.
  910. //
  911. // Targets should define GTM_BACKGROUND_TASK_FETCHING to 0 to avoid use of a UIBackgroundTask
  912. // on iOS to allow fetches to complete in the background. This property is available when
  913. // it's not practical to set the preprocessor define.
  914. @property(atomic, assign) BOOL skipBackgroundTask;
  915. #endif // GTM_BACKGROUND_TASK_FETCHING
  916. // Begin fetching the request
  917. //
  918. // The delegate may optionally implement the callback or pass nil for the selector or handler.
  919. //
  920. // The delegate and all callback blocks are retained between the beginFetch call until after the
  921. // finish callback, or until the fetch is stopped.
  922. //
  923. // An error is passed to the callback for server statuses 300 or
  924. // higher, with the status stored as the error object's code.
  925. //
  926. // finishedSEL has a signature like:
  927. // - (void)fetcher:(GTMSessionFetcher *)fetcher
  928. // finishedWithData:(NSData *)data
  929. // error:(NSError *)error;
  930. //
  931. // If the application has specified a destinationFileURL or an accumulateDataBlock
  932. // for the fetcher, the data parameter passed to the callback will be nil.
  933. - (void)beginFetchWithDelegate:(GTM_NULLABLE id)delegate
  934. didFinishSelector:(GTM_NULLABLE SEL)finishedSEL;
  935. - (void)beginFetchWithCompletionHandler:(GTM_NULLABLE GTMSessionFetcherCompletionHandler)handler;
  936. // Returns YES if this fetcher is in the process of fetching a URL.
  937. @property(atomic, readonly, getter=isFetching) BOOL fetching;
  938. // Cancel the fetch of the request that's currently in progress. The completion handler
  939. // will not be called.
  940. - (void)stopFetching;
  941. // A block to be called when the fetch completes.
  942. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherCompletionHandler completionHandler;
  943. // A block to be called if download resume data becomes available.
  944. @property(atomic, strong, GTM_NULLABLE) void (^resumeDataBlock)(NSData *);
  945. // Return the status code from the server response.
  946. @property(atomic, readonly) NSInteger statusCode;
  947. // Return the http headers from the response.
  948. @property(atomic, strong, readonly, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, NSString *) *responseHeaders;
  949. // The response, once it's been received.
  950. @property(atomic, strong, readonly, GTM_NULLABLE) NSURLResponse *response;
  951. // Bytes downloaded so far.
  952. @property(atomic, readonly) int64_t downloadedLength;
  953. // Buffer of currently-downloaded data, if available.
  954. @property(atomic, readonly, strong, GTM_NULLABLE) NSData *downloadedData;
  955. // Local path to which the downloaded file will be moved.
  956. //
  957. // If a file already exists at the path, it will be overwritten.
  958. // Will create the enclosing folders if they are not present.
  959. @property(atomic, strong, GTM_NULLABLE) NSURL *destinationFileURL;
  960. // The time this fetcher originally began fetching. This is useful as a time
  961. // barrier for ignoring irrelevant fetch notifications or callbacks.
  962. @property(atomic, strong, readonly, GTM_NULLABLE) NSDate *initialBeginFetchDate;
  963. // userData is retained solely for the convenience of the client.
  964. @property(atomic, strong, GTM_NULLABLE) id userData;
  965. // Stored property values are retained solely for the convenience of the client.
  966. @property(atomic, copy, GTM_NULLABLE) GTM_NSDictionaryOf(NSString *, id) *properties;
  967. - (void)setProperty:(GTM_NULLABLE id)obj forKey:(NSString *)key; // Pass nil for obj to remove the property.
  968. - (GTM_NULLABLE id)propertyForKey:(NSString *)key;
  969. - (void)addPropertiesFromDictionary:(GTM_NSDictionaryOf(NSString *, id) *)dict;
  970. // Comments are useful for logging, so are strongly recommended for each fetcher.
  971. @property(atomic, copy, GTM_NULLABLE) NSString *comment;
  972. - (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
  973. // Log of request and response, if logging is enabled
  974. @property(atomic, copy, GTM_NULLABLE) NSString *log;
  975. // Callbacks are run on this queue. If none is supplied, the main queue is used.
  976. @property(atomic, strong, GTM_NULL_RESETTABLE) dispatch_queue_t callbackQueue;
  977. // The queue used internally by the session to invoke its delegate methods in the fetcher.
  978. //
  979. // Application callbacks are always called by the fetcher on the callbackQueue above,
  980. // not on this queue. Apps should generally not change this queue.
  981. //
  982. // The default delegate queue is the main queue.
  983. //
  984. // This value is ignored after the session has been created, so this
  985. // property should be set in the fetcher service rather in the fetcher as it applies
  986. // to a shared session.
  987. @property(atomic, strong, GTM_NULL_RESETTABLE) NSOperationQueue *sessionDelegateQueue;
  988. // Spin the run loop or sleep the thread, discarding events, until the fetch has completed.
  989. //
  990. // This is only for use in testing or in tools without a user interface.
  991. //
  992. // Note: Synchronous fetches should never be used by shipping apps; they are
  993. // sufficient reason for rejection from the app store.
  994. //
  995. // Returns NO if timed out.
  996. - (BOOL)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds;
  997. // Test block is optional for testing.
  998. //
  999. // If present, this block will cause the fetcher to skip starting the session, and instead
  1000. // use the test block response values when calling the completion handler and delegate code.
  1001. //
  1002. // Test code can set this on the fetcher or on the fetcher service. For testing libraries
  1003. // that use a fetcher without exposing either the fetcher or the fetcher service, the global
  1004. // method setGlobalTestBlock: will set the block for all fetchers that do not have a test
  1005. // block set.
  1006. //
  1007. // The test code can pass nil for all response parameters to indicate that the fetch
  1008. // should proceed.
  1009. //
  1010. // Applications can exclude test block support by setting GTM_DISABLE_FETCHER_TEST_BLOCK.
  1011. @property(atomic, copy, GTM_NULLABLE) GTMSessionFetcherTestBlock testBlock;
  1012. + (void)setGlobalTestBlock:(GTM_NULLABLE GTMSessionFetcherTestBlock)block;
  1013. // When using the testBlock, |testBlockAccumulateDataChunkCount| is the desired number of chunks to
  1014. // divide the response data into if the client has streaming enabled. The data will be divided up to
  1015. // |testBlockAccumulateDataChunkCount| chunks; however, the exact amount may vary depending on the
  1016. // size of the response data (e.g. a 1-byte response can only be divided into one chunk).
  1017. @property(atomic, readwrite) NSUInteger testBlockAccumulateDataChunkCount;
  1018. #if GTM_BACKGROUND_TASK_FETCHING
  1019. // For testing or to override UIApplication invocations, apps may specify an alternative
  1020. // target for messages to UIApplication.
  1021. + (void)setSubstituteUIApplication:(nullable id<GTMUIApplicationProtocol>)substituteUIApplication;
  1022. + (nullable id<GTMUIApplicationProtocol>)substituteUIApplication;
  1023. #endif // GTM_BACKGROUND_TASK_FETCHING
  1024. // Exposed for testing.
  1025. + (GTMSessionCookieStorage *)staticCookieStorage;
  1026. + (BOOL)appAllowsInsecureRequests;
  1027. #if STRIP_GTM_FETCH_LOGGING
  1028. // If logging is stripped, provide a stub for the main method
  1029. // for controlling logging.
  1030. + (void)setLoggingEnabled:(BOOL)flag;
  1031. + (BOOL)isLoggingEnabled;
  1032. #else
  1033. // These methods let an application log specific body text, such as the text description of a binary
  1034. // request or response. The application should set the fetcher to defer response body logging until
  1035. // the response has been received and the log response body has been set by the app. For example:
  1036. //
  1037. // fetcher.logRequestBody = [binaryObject stringDescription];
  1038. // fetcher.deferResponseBodyLogging = YES;
  1039. // [fetcher beginFetchWithCompletionHandler:^(NSData *data, NSError *error) {
  1040. // if (error == nil) {
  1041. // fetcher.logResponseBody = [[[MyThing alloc] initWithData:data] stringDescription];
  1042. // }
  1043. // fetcher.deferResponseBodyLogging = NO;
  1044. // }];
  1045. @property(atomic, copy, GTM_NULLABLE) NSString *logRequestBody;
  1046. @property(atomic, assign) BOOL deferResponseBodyLogging;
  1047. @property(atomic, copy, GTM_NULLABLE) NSString *logResponseBody;
  1048. // Internal logging support.
  1049. @property(atomic, readonly) NSData *loggedStreamData;
  1050. @property(atomic, assign) BOOL hasLoggedError;
  1051. @property(atomic, strong, GTM_NULLABLE) NSURL *redirectedFromURL;
  1052. - (void)appendLoggedStreamData:(NSData *)dataToAdd;
  1053. - (void)clearLoggedStreamData;
  1054. #endif // STRIP_GTM_FETCH_LOGGING
  1055. @end
  1056. @interface GTMSessionFetcher (BackwardsCompatibilityOnly)
  1057. // Clients using GTMSessionFetcher should set the cookie storage explicitly themselves.
  1058. // This method is just for compatibility with the old GTMHTTPFetcher class.
  1059. - (void)setCookieStorageMethod:(NSInteger)method;
  1060. @end
  1061. // Until we can just instantiate NSHTTPCookieStorage for local use, we'll
  1062. // implement all the public methods ourselves. This stores cookies only in
  1063. // memory. Additional methods are provided for testing.
  1064. //
  1065. // iOS 9/OS X 10.11 added +[NSHTTPCookieStorage sharedCookieStorageForGroupContainerIdentifier:]
  1066. // which may also be used to create cookie storage.
  1067. @interface GTMSessionCookieStorage : NSHTTPCookieStorage
  1068. // Add the array off cookies to the storage, replacing duplicates.
  1069. // Also removes expired cookies from the storage.
  1070. - (void)setCookies:(GTM_NULLABLE GTM_NSArrayOf(NSHTTPCookie *) *)cookies;
  1071. - (void)removeAllCookies;
  1072. @end
  1073. // Macros to monitor synchronization blocks in debug builds.
  1074. // These report problems using GTMSessionCheckDebug.
  1075. //
  1076. // GTMSessionMonitorSynchronized Start monitoring a top-level-only
  1077. // @sync scope.
  1078. // GTMSessionMonitorRecursiveSynchronized Start monitoring a top-level or
  1079. // recursive @sync scope.
  1080. // GTMSessionCheckSynchronized Verify that the current execution
  1081. // is inside a @sync scope.
  1082. // GTMSessionCheckNotSynchronized Verify that the current execution
  1083. // is not inside a @sync scope.
  1084. //
  1085. // Example usage:
  1086. //
  1087. // - (void)myExternalMethod {
  1088. // @synchronized(self) {
  1089. // GTMSessionMonitorSynchronized(self)
  1090. //
  1091. // - (void)myInternalMethod {
  1092. // GTMSessionCheckSynchronized(self);
  1093. //
  1094. // - (void)callMyCallbacks {
  1095. // GTMSessionCheckNotSynchronized(self);
  1096. //
  1097. // GTMSessionCheckNotSynchronized is available for verifying the code isn't
  1098. // in a deadlockable @sync state when posting notifications and invoking
  1099. // callbacks. Don't use GTMSessionCheckNotSynchronized immediately before a
  1100. // @sync scope; the normal recursiveness check of GTMSessionMonitorSynchronized
  1101. // can catch those.
  1102. #ifdef __OBJC__
  1103. // If asserts are entirely no-ops, the synchronization monitor is just a bunch
  1104. // of counting code that doesn't report exceptional circumstances in any way.
  1105. // Only build the synchronization monitor code if NS_BLOCK_ASSERTIONS is not
  1106. // defined or asserts are being logged instead.
  1107. #if DEBUG && (!defined(NS_BLOCK_ASSERTIONS) || GTMSESSION_ASSERT_AS_LOG)
  1108. #define __GTMSessionMonitorSynchronizedVariableInner(varname, counter) \
  1109. varname ## counter
  1110. #define __GTMSessionMonitorSynchronizedVariable(varname, counter) \
  1111. __GTMSessionMonitorSynchronizedVariableInner(varname, counter)
  1112. #define GTMSessionMonitorSynchronized(obj) \
  1113. NS_VALID_UNTIL_END_OF_SCOPE id \
  1114. __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
  1115. [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
  1116. allowRecursive:NO \
  1117. functionName:__func__]
  1118. #define GTMSessionMonitorRecursiveSynchronized(obj) \
  1119. NS_VALID_UNTIL_END_OF_SCOPE id \
  1120. __GTMSessionMonitorSynchronizedVariable(__monitor, __COUNTER__) = \
  1121. [[GTMSessionSyncMonitorInternal alloc] initWithSynchronizationObject:obj \
  1122. allowRecursive:YES \
  1123. functionName:__func__]
  1124. #define GTMSessionCheckSynchronized(obj) { \
  1125. GTMSESSION_ASSERT_DEBUG( \
  1126. [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
  1127. @"GTMSessionCheckSynchronized(" #obj ") failed: not sync'd" \
  1128. @" on " #obj " in %s. Call stack:\n%@", \
  1129. __func__, [NSThread callStackSymbols]); \
  1130. }
  1131. #define GTMSessionCheckNotSynchronized(obj) { \
  1132. GTMSESSION_ASSERT_DEBUG( \
  1133. ![GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
  1134. @"GTMSessionCheckNotSynchronized(" #obj ") failed: was sync'd" \
  1135. @" on " #obj " in %s by %@. Call stack:\n%@", __func__, \
  1136. [GTMSessionSyncMonitorInternal functionsHoldingSynchronizationOnObject:obj], \
  1137. [NSThread callStackSymbols]); \
  1138. }
  1139. // GTMSessionSyncMonitorInternal is a private class that keeps track of the
  1140. // beginning and end of synchronized scopes.
  1141. //
  1142. // This class should not be used directly, but only via the
  1143. // GTMSessionMonitorSynchronized macro.
  1144. @interface GTMSessionSyncMonitorInternal : NSObject
  1145. - (instancetype)initWithSynchronizationObject:(id)object
  1146. allowRecursive:(BOOL)allowRecursive
  1147. functionName:(const char *)functionName;
  1148. // Return the names of the functions that hold sync on the object, or nil if none.
  1149. + (NSArray *)functionsHoldingSynchronizationOnObject:(id)object;
  1150. @end
  1151. #else
  1152. #define GTMSessionMonitorSynchronized(obj) do { } while (0)
  1153. #define GTMSessionMonitorRecursiveSynchronized(obj) do { } while (0)
  1154. #define GTMSessionCheckSynchronized(obj) do { } while (0)
  1155. #define GTMSessionCheckNotSynchronized(obj) do { } while (0)
  1156. #endif // !DEBUG
  1157. #endif // __OBJC__
  1158. GTM_ASSUME_NONNULL_END