blob: bbc958e91c89421c419d27e6ccf8f030c272560b [file] [log] [blame]
/* Copyright (c) 2011 Google Inc.
*
* 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.
*/
//
// GTMHTTPFetcher.h
//
// This is essentially a wrapper around NSURLConnection for POSTs and GETs.
// If setPostData: is called, then POST is assumed.
//
// When would you use this instead of NSURLConnection?
//
// - When you just want the result from a GET, POST, or PUT
// - When you want the "standard" behavior for connections (redirection handling
// an so on)
// - When you want automatic retry on failures
// - When you want to avoid cookie collisions with Safari and other applications
// - When you are fetching resources with ETags and want to avoid the overhead
// of repeated fetches of unchanged data
// - When you need to set a credential for the http operation
//
// This is assumed to be a one-shot fetch request; don't reuse the object
// for a second fetch.
//
// The fetcher may be created auto-released, in which case it will release
// itself after the fetch completion callback. The fetcher is implicitly
// retained as long as a connection is pending.
//
// But if you may need to cancel the fetcher, retain it and have the delegate
// release the fetcher in the callbacks.
//
// Sample usage:
//
// NSURLRequest *request = [NSURLRequest requestWithURL:myURL];
// GTMHTTPFetcher* myFetcher = [GTMHTTPFetcher fetcherWithRequest:request];
//
// // optional upload body data
// [myFetcher setPostData:[postString dataUsingEncoding:NSUTF8StringEncoding]];
//
// [myFetcher beginFetchWithDelegate:self
// didFinishSelector:@selector(myFetcher:finishedWithData:error:)];
//
// Upon fetch completion, the callback selector is invoked; it should have
// this signature (you can use any callback method name you want so long as
// the signature matches this):
//
// - (void)myFetcher:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)retrievedData error:(NSError *)error;
//
// The block callback version looks like:
//
// [myFetcher beginFetchWithCompletionHandler:^(NSData *retrievedData, NSError *error) {
// if (error != nil) {
// // status code or network error
// } else {
// // succeeded
// }
// }];
//
// NOTE: Fetches may retrieve data from the server even though the server
// returned an error. The failure selector is called when the server
// status is >= 300, with an NSError having domain
// kGTMHTTPFetcherStatusDomain and code set to the server status.
//
// Status codes are at <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>
//
//
// Threading and queue support:
//
// Callbacks require either that the thread used to start the fetcher have a run
// loop spinning (typically the main thread), or that an NSOperationQueue be
// provided upon which the delegate callbacks will be called. Starting with
// iOS 6 and Mac OS X 10.7, clients may simply create an operation queue for
// callbacks on a background thread:
//
// NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
// [queue setMaxConcurrentOperationCount:1];
// fetcher.delegateQueue = queue;
//
// or specify the main queue for callbacks on the main thread:
//
// fetcher.delegateQueue = [NSOperationQueue mainQueue];
//
// The client may also re-dispatch from the callbacks and notifications to
// a known dispatch queue:
//
// [myFetcher beginFetchWithCompletionHandler:^(NSData *retrievedData, NSError *error) {
// if (error == nil) {
// dispatch_async(myDispatchQueue, ^{
// ...
// });
// }
// }];
//
//
//
// Downloading to disk:
//
// To have downloaded data saved directly to disk, specify either a path for the
// downloadPath property, or a file handle for the downloadFileHandle property.
// When downloading to disk, callbacks will be passed a nil for the NSData*
// arguments.
//
//
// HTTP methods and headers:
//
// Alternative HTTP methods, like PUT, and custom headers can be specified by
// creating the fetcher with an appropriate NSMutableURLRequest
//
//
// Proxies:
//
// Proxy handling is invisible so long as the system has a valid credential in
// the keychain, which is normally true (else most NSURL-based apps would have
// difficulty.) But when there is a proxy authetication error, the the fetcher
// will call the failedWithError: method with the NSURLChallenge in the error's
// userInfo. The error method can get the challenge info like this:
//
// NSURLAuthenticationChallenge *challenge
// = [[error userInfo] objectForKey:kGTMHTTPFetcherErrorChallengeKey];
// BOOL isProxyChallenge = [[challenge protectionSpace] isProxy];
//
// If a proxy error occurs, you can ask the user for the proxy username/password
// and call fetcher's setProxyCredential: to provide those for the
// next attempt to fetch.
//
//
// Cookies:
//
// There are three supported mechanisms for remembering cookies between fetches.
//
// By default, GTMHTTPFetcher uses a mutable array held statically to track
// cookies for all instantiated fetchers. This avoids server cookies being set
// by servers for the application from interfering with Safari cookie settings,
// and vice versa. The fetcher cookies are lost when the application quits.
//
// To rely instead on WebKit's global NSHTTPCookieStorage, call
// setCookieStorageMethod: with kGTMHTTPFetcherCookieStorageMethodSystemDefault.
//
// If the fetcher is created from a GTMHTTPFetcherService object
// then the cookie storage mechanism is set to use the cookie storage in the
// service object rather than the static storage.
//
//
// Fetching for periodic checks:
//
// The fetcher object tracks ETag headers from responses and
// provide an "If-None-Match" header. This allows the server to save
// bandwidth by providing a status message instead of repeated response
// data.
//
// To get this behavior, create the fetcher from an GTMHTTPFetcherService object
// and look for a fetch callback error with code 304
// (kGTMHTTPFetcherStatusNotModified) like this:
//
// - (void)myFetcher:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)data error:(NSError *)error {
// if ([error code] == kGTMHTTPFetcherStatusNotModified) {
// // |data| is empty; use the data from the previous finishedWithData: for this URL
// } else {
// // handle other server status code
// }
// }
//
//
// Monitoring received data
//
// The optional received data selector can be set with setReceivedDataSelector:
// and should have the signature
//
// - (void)myFetcher:(GTMHTTPFetcher *)fetcher receivedData:(NSData *)dataReceivedSoFar;
//
// The number bytes received so far is available as [fetcher downloadedLength].
// This number may go down if a redirect causes the download to begin again from
// a new server.
//
// 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; 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 setRetryEnabled:YES];
//
// With retries enabled, the success or failure 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 setMaxRetryInterval:60.0]; // in seconds; default is 60 seconds
// // for downloads, 600 for uploads
//
// Also optionally, the client may provide a callback selector to determine
// if a status code or other error should be retried.
// [myFetcher setRetrySelector:@selector(myFetcher:willRetry:forError:)];
//
// If set, the retry selector should have the signature:
// -(BOOL)fetcher:(GTMHTTPFetcher *)fetcher willRetry:(BOOL)suggestedWillRetry forError:(NSError *)error
// and return 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 kGTMHTTPFetcherStatusDomain. The
// user's method may look something like this:
//
// -(BOOL)myFetcher:(GTMHTTPFetcher *)fetcher willRetry:(BOOL)suggestedWillRetry forError:(NSError *)error {
//
// // perhaps examine [error domain] and [error code], or [fetcher retryCount]
// //
// // return 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.
// return suggestedWillRetry;
// }
#pragma once
#import <Foundation/Foundation.h>
#if defined(GTL_TARGET_NAMESPACE)
// we're using target namespace macros
#import "GTLDefines.h"
#elif defined(GDATA_TARGET_NAMESPACE)
#import "GDataDefines.h"
#else
#if TARGET_OS_IPHONE
#ifndef GTM_FOUNDATION_ONLY
#define GTM_FOUNDATION_ONLY 1
#endif
#ifndef GTM_IPHONE
#define GTM_IPHONE 1
#endif
#endif
#endif
#if TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 40000)
#define GTM_BACKGROUND_FETCHING 1
#endif
#ifndef GTM_ALLOW_INSECURE_REQUESTS
// For builds prior to the iOS 8/10.10 SDKs, default to ignoring insecure requests for backwards
// compatibility unless the project has smartly set GTM_ALLOW_INSECURE_REQUESTS explicitly.
#if (!TARGET_OS_IPHONE && defined(MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10) \
|| (TARGET_OS_IPHONE && defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0)
#define GTM_ALLOW_INSECURE_REQUESTS 0
#else
#define GTM_ALLOW_INSECURE_REQUESTS 1
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
// notifications
//
// fetch started and stopped, and fetch retry delay started and stopped
extern NSString *const kGTMHTTPFetcherStartedNotification;
extern NSString *const kGTMHTTPFetcherStoppedNotification;
extern NSString *const kGTMHTTPFetcherRetryDelayStartedNotification;
extern NSString *const kGTMHTTPFetcherRetryDelayStoppedNotification;
// callback constants
extern NSString *const kGTMHTTPFetcherErrorDomain;
extern NSString *const kGTMHTTPFetcherStatusDomain;
extern NSString *const kGTMHTTPFetcherErrorChallengeKey;
extern NSString *const kGTMHTTPFetcherStatusDataKey; // data returned with a kGTMHTTPFetcherStatusDomain error
#ifdef __cplusplus
}
#endif
enum {
kGTMHTTPFetcherErrorDownloadFailed = -1,
kGTMHTTPFetcherErrorAuthenticationChallengeFailed = -2,
kGTMHTTPFetcherErrorChunkUploadFailed = -3,
kGTMHTTPFetcherErrorFileHandleException = -4,
kGTMHTTPFetcherErrorBackgroundExpiration = -6,
// The code kGTMHTTPFetcherErrorAuthorizationFailed (-5) has been removed;
// look for status 401 instead.
kGTMHTTPFetcherStatusNotModified = 304,
kGTMHTTPFetcherStatusBadRequest = 400,
kGTMHTTPFetcherStatusUnauthorized = 401,
kGTMHTTPFetcherStatusForbidden = 403,
kGTMHTTPFetcherStatusPreconditionFailed = 412
};
// cookie storage methods
enum {
kGTMHTTPFetcherCookieStorageMethodStatic = 0,
kGTMHTTPFetcherCookieStorageMethodFetchHistory = 1,
kGTMHTTPFetcherCookieStorageMethodSystemDefault = 2,
kGTMHTTPFetcherCookieStorageMethodNone = 3
};
#ifdef __cplusplus
extern "C" {
#endif
void GTMAssertSelectorNilOrImplementedWithArgs(id obj, SEL sel, ...);
// Utility functions for applications self-identifying to servers via a
// user-agent header
// Make a proper app name without whitespace from the given string, removing
// whitespace and other characters that may be special parsed marks of
// the full user-agent string.
NSString *GTMCleanedUserAgentString(NSString *str);
// Make an identifier like "MacOSX/10.7.1" or "iPod_Touch/4.1 hw/iPod1_1"
NSString *GTMSystemVersionString(void);
// 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 *GTMApplicationIdentifier(NSBundle *bundle);
#ifdef __cplusplus
} // extern "C"
#endif
@class GTMHTTPFetcher;
@protocol GTMCookieStorageProtocol <NSObject>
// This protocol allows us to call into the service without requiring
// GTMCookieStorage sources in this project
//
// The public interface for cookie handling is the GTMCookieStorage class,
// accessible from a fetcher service object's fetchHistory or from the fetcher's
// +staticCookieStorage method.
- (NSArray *)cookiesForURL:(NSURL *)theURL;
- (void)setCookies:(NSArray *)newCookies;
@end
@protocol GTMHTTPFetchHistoryProtocol <NSObject>
// This protocol allows us to call the fetch history object without requiring
// GTMHTTPFetchHistory sources in this project
- (void)updateRequest:(NSMutableURLRequest *)request isHTTPGet:(BOOL)isHTTPGet;
- (BOOL)shouldCacheETaggedData;
- (NSData *)cachedDataForRequest:(NSURLRequest *)request;
- (id <GTMCookieStorageProtocol>)cookieStorage;
- (void)updateFetchHistoryWithRequest:(NSURLRequest *)request
response:(NSURLResponse *)response
downloadedData:(NSData *)downloadedData;
- (void)removeCachedDataForRequest:(NSURLRequest *)request;
@end
@protocol GTMHTTPFetcherServiceProtocol <NSObject>
// This protocol allows us to call into the service without requiring
// GTMHTTPFetcherService sources in this project
@property (retain) NSOperationQueue *delegateQueue;
- (BOOL)fetcherShouldBeginFetching:(GTMHTTPFetcher *)fetcher;
- (void)fetcherDidStop:(GTMHTTPFetcher *)fetcher;
- (GTMHTTPFetcher *)fetcherWithRequest:(NSURLRequest *)request;
- (BOOL)isDelayingFetcher:(GTMHTTPFetcher *)fetcher;
@end
@protocol GTMFetcherAuthorizationProtocol <NSObject>
@required
// This protocol allows us to call the authorizer without requiring its sources
// in this project.
- (void)authorizeRequest:(NSMutableURLRequest *)request
delegate:(id)delegate
didFinishSelector:(SEL)sel;
- (void)stopAuthorization;
- (void)stopAuthorizationForRequest:(NSURLRequest *)request;
- (BOOL)isAuthorizingRequest:(NSURLRequest *)request;
- (BOOL)isAuthorizedRequest:(NSURLRequest *)request;
@property (retain, readonly) 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 (readonly) BOOL canAuthorize;
// For development only, allow authorization of non-SSL requests, allowing
// transmission of the bearer token unencrypted.
@property (assign) BOOL shouldAuthorizeAllRequests;
#if NS_BLOCKS_AVAILABLE
- (void)authorizeRequest:(NSMutableURLRequest *)request
completionHandler:(void (^)(NSError *error))handler;
#endif
@property (assign) id <GTMHTTPFetcherServiceProtocol> fetcherService; // WEAK
- (BOOL)primeForRefresh;
@end
// GTMHTTPFetcher objects are used for async retrieval of an http get or post
//
// See additional comments at the beginning of this file
@interface GTMHTTPFetcher : NSObject {
@protected
NSMutableURLRequest *request_;
NSURLConnection *connection_;
NSMutableData *downloadedData_;
NSString *downloadPath_;
NSString *temporaryDownloadPath_;
NSFileHandle *downloadFileHandle_;
unsigned long long downloadedLength_;
NSArray *allowedInsecureSchemes_;
BOOL allowLocalhostRequest_;
NSURLCredential *credential_; // username & password
NSURLCredential *proxyCredential_; // credential supplied to proxy servers
NSData *postData_;
NSInputStream *postStream_;
NSMutableData *loggedStreamData_;
NSURLResponse *response_; // set in connection:didReceiveResponse:
id delegate_;
SEL finishedSel_; // should by implemented by delegate
SEL sentDataSel_; // optional, set with setSentDataSelector
SEL receivedDataSel_; // optional, set with setReceivedDataSelector
#if NS_BLOCKS_AVAILABLE
void (^completionBlock_)(NSData *, NSError *);
void (^receivedDataBlock_)(NSData *);
void (^sentDataBlock_)(NSInteger, NSInteger, NSInteger);
BOOL (^retryBlock_)(BOOL, NSError *);
#elif !__LP64__
// placeholders: for 32-bit builds, keep the size of the object's ivar section
// the same with and without blocks
id completionPlaceholder_;
id receivedDataPlaceholder_;
id sentDataPlaceholder_;
id retryPlaceholder_;
#endif
BOOL hasConnectionEnded_; // set if the connection need not be cancelled
BOOL isCancellingChallenge_; // set only when cancelling an auth challenge
BOOL isStopNotificationNeeded_; // set when start notification has been sent
BOOL shouldFetchInBackground_;
#if GTM_BACKGROUND_FETCHING
NSUInteger backgroundTaskIdentifer_; // UIBackgroundTaskIdentifier
#endif
id userData_; // retained, if set by caller
NSMutableDictionary *properties_; // more data retained for caller
NSArray *runLoopModes_; // optional
NSOperationQueue *delegateQueue_; // optional; available iOS 6/10.7 and later
id <GTMHTTPFetchHistoryProtocol> fetchHistory_; // if supplied by the caller, used for Last-Modified-Since checks and cookies
NSInteger cookieStorageMethod_; // constant from above
id <GTMCookieStorageProtocol> cookieStorage_;
id <GTMFetcherAuthorizationProtocol> authorizer_;
// the service object that created and monitors this fetcher, if any
id <GTMHTTPFetcherServiceProtocol> service_;
NSString *serviceHost_;
NSInteger servicePriority_;
NSThread *thread_;
BOOL isRetryEnabled_; // user wants auto-retry
SEL retrySel_; // optional; set with setRetrySelector
NSTimer *retryTimer_;
NSUInteger retryCount_;
NSTimeInterval maxRetryInterval_; // default 600 seconds
NSTimeInterval minRetryInterval_; // random between 1 and 2 seconds
NSTimeInterval retryFactor_; // default interval multiplier is 2
NSTimeInterval lastRetryInterval_;
NSDate *initialRequestDate_;
BOOL hasAttemptedAuthRefresh_;
NSString *comment_; // comment for log
NSString *log_;
#if !STRIP_GTM_FETCH_LOGGING
NSURL *redirectedFromURL_;
NSString *logRequestBody_;
NSString *logResponseBody_;
BOOL hasLoggedError_;
BOOL shouldDeferResponseBodyLogging_;
#endif
}
// 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.
+ (GTMHTTPFetcher *)fetcherWithRequest:(NSURLRequest *)request;
// Convenience methods that make a request, like +fetcherWithRequest
+ (GTMHTTPFetcher *)fetcherWithURL:(NSURL *)requestURL;
+ (GTMHTTPFetcher *)fetcherWithURLString:(NSString *)requestURLString;
// Designated initializer
- (id)initWithRequest:(NSURLRequest *)request;
// Fetcher request
//
// The underlying request is mutable and may be modified by the caller
@property (retain) NSMutableURLRequest *mutableRequest;
// 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.
@property(copy) NSArray *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.
@property(assign) BOOL allowLocalhostRequest;
// Setting the credential is optional; it is used if the connection receives
// an authentication challenge
@property (retain) NSURLCredential *credential;
// Setting the proxy credential is optional; it is used if the connection
// receives an authentication challenge from a proxy
@property (retain) NSURLCredential *proxyCredential;
// If post data or stream is not set, then a GET retrieval method is assumed
@property (retain) NSData *postData;
@property (retain) NSInputStream *postStream;
// The default cookie storage method is kGTMHTTPFetcherCookieStorageMethodStatic
// without a fetch history set, and kGTMHTTPFetcherCookieStorageMethodFetchHistory
// with a fetch history set
//
// Applications needing control of cookies across a sequence of fetches should
// create fetchers from a GTMHTTPFetcherService object (which encapsulates
// fetch history) for a well-defined cookie store
@property (assign) NSInteger cookieStorageMethod;
+ (id <GTMCookieStorageProtocol>)staticCookieStorage;
// Object to add authorization to the request, if needed
@property (retain) id <GTMFetcherAuthorizationProtocol> authorizer;
// The service object that created and monitors this fetcher, if any
@property (retain) id <GTMHTTPFetcherServiceProtocol> service;
// The host, if any, used to classify this fetcher in the fetcher service
@property (copy) 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.
@property (assign) NSInteger servicePriority;
// The thread used to run this fetcher in the fetcher service when no operation
// queue is provided.
@property (retain) NSThread *thread;
// The delegate is retained during the connection
@property (retain) id delegate;
// On iOS 4 and later, the fetch may optionally continue while the app is in the
// background until finished or stopped by OS expiration
//
// The default value is NO
//
// For Mac OS X, background fetches are always supported, and this property
// is ignored
@property (assign) BOOL shouldFetchInBackground;
// The delegate's optional sentData selector may be used to monitor upload
// progress. It should have a signature like:
// - (void)myFetcher:(GTMHTTPFetcher *)fetcher
// didSendBytes:(NSInteger)bytesSent
// totalBytesSent:(NSInteger)totalBytesSent
// totalBytesExpectedToSend:(NSInteger)totalBytesExpectedToSend;
//
// +doesSupportSentDataCallback indicates if this delegate method is supported
+ (BOOL)doesSupportSentDataCallback;
@property (assign) SEL sentDataSelector;
// The delegate's optional receivedData selector may be used to monitor download
// progress. It should have a signature like:
// - (void)myFetcher:(GTMHTTPFetcher *)fetcher
// receivedData:(NSData *)dataReceivedSoFar;
//
// The dataReceived argument will be nil when downloading to a path or to a
// file handle.
//
// Applications should not use this method to accumulate the received data;
// the callback method or block supplied to the beginFetch call will have
// the complete NSData received.
@property (assign) SEL receivedDataSelector;
#if NS_BLOCKS_AVAILABLE
// The full interface to the block is provided rather than just a typedef for
// its parameter list in order to get more useful code completion in the Xcode
// editor
@property (copy) void (^sentDataBlock)(NSInteger bytesSent, NSInteger totalBytesSent, NSInteger bytesExpectedToSend);
// The dataReceived argument will be nil when downloading to a path or to
// a file handle
@property (copy) void (^receivedDataBlock)(NSData *dataReceivedSoFar);
#endif
// retrying; see comments at the top of the file. Calling
// setRetryEnabled(YES) resets the min and max retry intervals.
@property (assign, getter=isRetryEnabled) BOOL retryEnabled;
// Retry selector or block is optional for retries.
//
// If present, it should have the signature:
// -(BOOL)fetcher:(GTMHTTPFetcher *)fetcher willRetry:(BOOL)suggestedWillRetry forError:(NSError *)error
// and return YES to cause a retry. See comments at the top of this file.
@property (assign) SEL retrySelector;
#if NS_BLOCKS_AVAILABLE
@property (copy) BOOL (^retryBlock)(BOOL suggestedWillRetry, NSError *error);
#endif
// 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, 600 seconds.
@property (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
// call this except for unit testing.
@property (assign) NSTimeInterval minRetryInterval;
// Multiplier used to increase the interval between retries, typically 2.0.
// Clients should not need to call this.
@property (assign) double retryFactor;
// Number of retries attempted
@property (readonly) NSUInteger retryCount;
// interval delay to precede next retry
@property (readonly) NSTimeInterval nextRetryInterval;
// Begin fetching the request
//
// The delegate can optionally implement the finished selectors or pass NULL
// for it.
//
// Returns YES if the fetch is initiated. The delegate is retained between
// the beginFetch call until after the finish callback.
//
// 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:(GTMHTTPFetcher *)fetcher finishedWithData:(NSData *)data error:(NSError *)error;
//
// If the application has specified a downloadPath or downloadFileHandle
// for the fetcher, the data parameter passed to the callback will be nil.
- (BOOL)beginFetchWithDelegate:(id)delegate
didFinishSelector:(SEL)finishedSEL;
#if NS_BLOCKS_AVAILABLE
- (BOOL)beginFetchWithCompletionHandler:(void (^)(NSData *data, NSError *error))handler;
#endif
// Returns YES if this is in the process of fetching a URL
- (BOOL)isFetching;
// Cancel the fetch of the request that's currently in progress
- (void)stopFetching;
// Return the status code from the server response
@property (readonly) NSInteger statusCode;
// Return the http headers from the response
@property (retain, readonly) NSDictionary *responseHeaders;
// The response, once it's been received
@property (retain) NSURLResponse *response;
// Bytes downloaded so far
@property (readonly) unsigned long long downloadedLength;
// Buffer of currently-downloaded data
@property (readonly, retain) NSData *downloadedData;
// Path in which to non-atomically create a file for storing the downloaded data
//
// The path must be set before fetching begins. The download file handle
// will be created for the path, and can be used to monitor progress. If a file
// already exists at the path, it will be overwritten.
@property (copy) NSString *downloadPath;
// If downloadFileHandle is set, data received is immediately appended to
// the file handle rather than being accumulated in the downloadedData property
//
// The file handle supplied must allow writing and support seekToFileOffset:,
// and must be set before fetching begins. Setting a download path will
// override the file handle property.
@property (retain) NSFileHandle *downloadFileHandle;
// The optional fetchHistory object is used for a sequence of fetchers to
// remember ETags, cache ETagged data, and store cookies. Typically, this
// is set by a GTMFetcherService object when it creates a fetcher.
//
// Side effect: setting fetch history implicitly calls setCookieStorageMethod:
@property (retain) id <GTMHTTPFetchHistoryProtocol> fetchHistory;
// userData is retained for the convenience of the caller
@property (retain) id userData;
// Stored property values are retained for the convenience of the caller
@property (copy) NSMutableDictionary *properties;
- (void)setProperty:(id)obj forKey:(NSString *)key; // pass nil obj to remove property
- (id)propertyForKey:(NSString *)key;
- (void)addPropertiesFromDictionary:(NSDictionary *)dict;
// Comments are useful for logging
@property (copy) NSString *comment;
- (void)setCommentWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
// Log of request and response, if logging is enabled
@property (copy) NSString *log;
// Callbacks can be invoked on an operation queue rather than via the run loop,
// starting on 10.7 and iOS 6. If a delegate queue is supplied. the run loop
// modes are ignored.
@property (retain) NSOperationQueue *delegateQueue;
// Using the fetcher while a modal dialog is displayed requires setting the
// run-loop modes to include NSModalPanelRunLoopMode
@property (retain) NSArray *runLoopModes;
// Users who wish to replace GTMHTTPFetcher's use of NSURLConnection
// can do so globally here. The replacement should be a subclass of
// NSURLConnection.
+ (Class)connectionClass;
+ (void)setConnectionClass:(Class)theClass;
//
// Newer synonym for postData.
//
@property (retain) NSData *bodyData;
// Spin the run loop, discarding events, until the fetch has completed
//
// This is only for use in testing or in tools without a user interface.
//
// Synchronous fetches should never be done by shipping apps; they are
// sufficient reason for rejection from the app store.
- (void)waitForCompletionWithTimeout:(NSTimeInterval)timeoutInSeconds;
#if STRIP_GTM_FETCH_LOGGING
// if logging is stripped, provide a stub for the main method
// for controlling logging
+ (void)setLoggingEnabled:(BOOL)flag;
#endif // STRIP_GTM_FETCH_LOGGING
@end