// // RKRequest.h // RestKit // // Created by Jeremy Ellison on 7/27/09. // Copyright (c) 2009-2012 RestKit. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #if TARGET_OS_IPHONE #import #endif #import #import #import "RKRequestSerializable.h" @class RKRequestCache; /** HTTP methods for requests */ typedef enum RKRequestMethod { RKRequestMethodInvalid = -1, RKRequestMethodGET, RKRequestMethodPOST, RKRequestMethodPUT, RKRequestMethodDELETE, RKRequestMethodHEAD } RKRequestMethod; NSString *RKRequestMethodNameFromType(RKRequestMethod); RKRequestMethod RKRequestMethodTypeFromName(NSString *); /** Cache policy for determining how to use RKCache */ typedef enum { /** Never use the cache */ RKRequestCachePolicyNone = 0, /** Load from the cache when we are offline */ RKRequestCachePolicyLoadIfOffline = 1 << 0, /** Load from the cache if we encounter an error */ RKRequestCachePolicyLoadOnError = 1 << 1, /** Load from the cache if we have data stored and the server returns a 304 (not modified) response */ RKRequestCachePolicyEtag = 1 << 2, /** Load from the cache if we have data stored */ RKRequestCachePolicyEnabled = 1 << 3, /** Load from the cache if we are within the timeout window */ RKRequestCachePolicyTimeout = 1 << 4, /** The default cache policy is etag and timeout support */ RKRequestCachePolicyDefault = RKRequestCachePolicyEtag | RKRequestCachePolicyTimeout } RKRequestCachePolicy; #if TARGET_OS_IPHONE /** Background Request Policy On iOS 4.x and higher, UIKit provides support for continuing activities for a limited amount of time in the background. RestKit provides simple support for continuing a request when in the background. */ typedef enum RKRequestBackgroundPolicy { /** Take no action with regards to backgrounding */ RKRequestBackgroundPolicyNone = 0, /** Cancel the request on transition to the background */ RKRequestBackgroundPolicyCancel, /** Continue the request in the background until time expires */ RKRequestBackgroundPolicyContinue, /** Stop the request and place it back on the queue. It will fire when the app reopens. */ RKRequestBackgroundPolicyRequeue } RKRequestBackgroundPolicy; #endif /** Authentication type for the request Based on the authentication type that is selected, authentication functionality is triggered and other options may be required. */ typedef enum { /** Disable the use of authentication */ RKRequestAuthenticationTypeNone = 0, /** Use NSURLConnection's HTTP AUTH auto-negotiation */ RKRequestAuthenticationTypeHTTP, /** Force the use of HTTP Basic authentication. This will supress AUTH challenges as RestKit will add an Authorization header establishing login via HTTP basic. This is an optimization that skips the challenge portion of the request. */ RKRequestAuthenticationTypeHTTPBasic, /** Enable the use of OAuth 1.0 authentication. OAuth1ConsumerKey, OAuth1ConsumerSecret, OAuth1AccessToken, and OAuth1AccessTokenSecret must be set when using this type. */ RKRequestAuthenticationTypeOAuth1, /** Enable the use of OAuth 2.0 authentication. OAuth2AccessToken must be set when using this type. */ RKRequestAuthenticationTypeOAuth2 } RKRequestAuthenticationType; @class RKRequest, RKResponse, RKRequestQueue, RKReachabilityObserver; @protocol RKRequestDelegate, RKConfigurationDelegate; ///----------------------------------------------------------------------------- /// @name Block Declarations ///----------------------------------------------------------------------------- typedef void(^RKRequestDidLoadResponseBlock)(RKResponse *response); typedef void(^RKRequestDidFailLoadWithErrorBlock)(NSError *error); /** Models the request portion of an HTTP request/response cycle. */ @interface RKRequest : NSObject { BOOL _sentSynchronously; NSURLConnection *_connection; id _delegate; NSTimer *_timeoutTimer; RKRequestCachePolicy _cachePolicy; RKRequestDidLoadResponseBlock _onDidLoadResponse; RKRequestDidFailLoadWithErrorBlock _onDidFailLoadWithError; #if TARGET_OS_IPHONE RKRequestBackgroundPolicy _backgroundPolicy; UIBackgroundTaskIdentifier _backgroundTaskIdentifier; #endif } ///----------------------------------------------------------------------------- /// @name Creating a Request ///----------------------------------------------------------------------------- /** Creates and returns a RKRequest object initialized to load content from a provided URL. @param URL The remote URL to load @return An autoreleased RKRequest object initialized with URL. */ + (RKRequest *)requestWithURL:(NSURL *)URL; /** Initializes a RKRequest object to load from a provided URL @param URL The remote URL to load @return An RKRequest object initialized with URL. */ - (id)initWithURL:(NSURL *)URL; /** Creates and returns a RKRequest object initialized to load content from a provided URL with a specified delegate. @bug **DEPRECATED** in v0.10.0: Use [RKRequest requestWithURL:] instead @param URL The remote URL to load @param delegate The delegate that will handle the response callbacks. @return An autoreleased RKRequest object initialized with URL. */ + (RKRequest *)requestWithURL:(NSURL *)URL delegate:(id)delegate DEPRECATED_ATTRIBUTE; /** Initializes a RKRequest object to load from a provided URL @bug **DEPRECATED** in v0.10.0: Use [RKRequest initWithURL:] instead @param URL The remote URL to load @param delegate The delegate that will handle the response callbacks. @return An RKRequest object initialized with URL. */ - (id)initWithURL:(NSURL *)URL delegate:(id)delegate DEPRECATED_ATTRIBUTE; ///----------------------------------------------------------------------------- /// @name Setting Properties ///----------------------------------------------------------------------------- /** The URL this request is loading */ @property (nonatomic, retain) NSURL *URL; /** The resourcePath portion of the request's URL */ @property (nonatomic, retain) NSString *resourcePath; /** The HTTP verb in which the request is sent **Default**: RKRequestMethodGET */ @property (nonatomic, assign) RKRequestMethod method; /** Returns HTTP method as a string used for this request. This should be set through the method property using an RKRequestMethod type. @see [RKRequest method] */ @property (nonatomic, readonly) NSString *HTTPMethod; /** A serializable collection of parameters sent as the HTTP body of the request */ @property (nonatomic, retain) NSObject *params; /** A dictionary of additional HTTP Headers to send with the request */ @property (nonatomic, retain) NSDictionary *additionalHTTPHeaders; /** The run loop mode under which the underlying NSURLConnection is performed *Default*: NSRunLoopCommonModes */ @property (nonatomic, copy) NSString *runLoopMode; /** * An opaque pointer to associate user defined data with the request. */ @property (nonatomic, retain) id userData; /** The underlying NSMutableURLRequest sent for this request */ @property (nonatomic, readonly) NSMutableURLRequest *URLRequest; /** The default value used to decode HTTP body content when HTTP headers received do not provide information on the content. This encoding will be used by the RKResponse when creating the body content */ @property (nonatomic, assign) NSStringEncoding defaultHTTPEncoding; ///----------------------------------------------------------------------------- /// @name Working with the HTTP Body ///----------------------------------------------------------------------------- /** Sets the request body using the provided NSDictionary after passing the NSDictionary through serialization using the currently configured parser for the provided MIMEType. @param body An NSDictionary of key/value pairs to be serialized and sent as the HTTP body. @param MIMEType The MIMEType for the parser to use for the dictionary. */ - (void)setBody:(NSDictionary *)body forMIMEType:(NSString *)MIMEType; /** The HTTP body as a NSData used for this request */ @property (nonatomic, retain) NSData *HTTPBody; /** The HTTP body as a string used for this request */ @property (nonatomic, retain) NSString *HTTPBodyString; ///----------------------------------------------------------------------------- /// @name Delegates ///----------------------------------------------------------------------------- /** The delegate to inform when the request is completed If the object implements the RKRequestDelegate protocol, it will receive request lifecycle event messages. */ @property (nonatomic, assign) id delegate; /** A delegate responsible for configuring the request. Centralizes common configuration data (such as HTTP headers, authentication information, etc) for re-use. RKClient and RKObjectManager conform to the RKConfigurationDelegate protocol. Request and object loader instances built through these objects will have a reference to their parent client/object manager assigned as the configuration delegate. **Default**: nil @see RKClient @see RKObjectManager */ @property (nonatomic, assign) id configurationDelegate; ///----------------------------------------------------------------------------- /// @name Handling Blocks ///----------------------------------------------------------------------------- /** A block to invoke when the receiver has loaded a response. @see [RKRequestDelegate request:didLoadResponse:] */ @property (nonatomic, copy) RKRequestDidLoadResponseBlock onDidLoadResponse; /** A block to invoke when the receuver has failed loading due to an error. @see [RKRequestDelegate request:didFailLoadWithError:] */ @property (nonatomic, copy) RKRequestDidFailLoadWithErrorBlock onDidFailLoadWithError; /** Whether this request should follow server redirects or not. @default YES */ @property (nonatomic, assign) BOOL followRedirect; #if TARGET_OS_IPHONE ///----------------------------------------------------------------------------- /// @name Background Tasks ///----------------------------------------------------------------------------- /** The policy to take on transition to the background (iOS 4.x and higher only) **Default:** RKRequestBackgroundPolicyCancel */ @property (nonatomic, assign) RKRequestBackgroundPolicy backgroundPolicy; /** Returns the identifier of the task that has been sent to the background. */ @property (nonatomic, readonly) UIBackgroundTaskIdentifier backgroundTaskIdentifier; #endif ///----------------------------------------------------------------------------- /// @name Authentication ///----------------------------------------------------------------------------- /** The type of authentication to use for this request. This must be assigned one of the following: - `RKRequestAuthenticationTypeNone`: Disable the use of authentication - `RKRequestAuthenticationTypeHTTP`: Use NSURLConnection's HTTP AUTH auto-negotiation - `RKRequestAuthenticationTypeHTTPBasic`: Force the use of HTTP Basic authentication. This will supress AUTH challenges as RestKit will add an Authorization header establishing login via HTTP basic. This is an optimization that skips the challenge portion of the request. - `RKRequestAuthenticationTypeOAuth1`: Enable the use of OAuth 1.0 authentication. OAuth1ConsumerKey, OAuth1ConsumerSecret, OAuth1AccessToken, and OAuth1AccessTokenSecret must be set. - `RKRequestAuthenticationTypeOAuth2`: Enable the use of OAuth 2.0 authentication. OAuth2AccessToken must be set. **Default**: RKRequestAuthenticationTypeNone */ @property (nonatomic, assign) RKRequestAuthenticationType authenticationType; /** The username to use for authentication via HTTP AUTH. Used to respond to an authentication challenge when authenticationType is RKRequestAuthenticationTypeHTTP or RKRequestAuthenticationTypeHTTPBasic. @see authenticationType */ @property (nonatomic, retain) NSString *username; /** The password to use for authentication via HTTP AUTH. Used to respond to an authentication challenge when authenticationType is RKRequestAuthenticationTypeHTTP or RKRequestAuthenticationTypeHTTPBasic. @see authenticationType */ @property (nonatomic, retain) NSString *password; ///----------------------------------------------------------------------------- /// @name OAuth1 Secrets ///----------------------------------------------------------------------------- /** The OAuth 1.0 consumer key Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1ConsumerKey; /** The OAuth 1.0 consumer secret Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1ConsumerSecret; /** The OAuth 1.0 access token Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1AccessToken; /** The OAuth 1.0 access token secret Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth1 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth1AccessTokenSecret; ///----------------------------------------------------------------------------- /// @name OAuth2 Secrets ///----------------------------------------------------------------------------- /** The OAuth 2.0 access token Used to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth2 @see authenticationType */ @property (nonatomic, retain) NSString *OAuth2AccessToken; /** The OAuth 2.0 refresh token Used to retrieve a new access token before expiration and to build an Authorization header when authenticationType is RKRequestAuthenticationTypeOAuth2 @bug **NOT IMPLEMENTED**: This functionality is not yet implemented. @see authenticationType */ @property (nonatomic, retain) NSString *OAuth2RefreshToken; ///----------------------------------------------------------------------------- /// @name Caching ///----------------------------------------------------------------------------- /** Returns the cache key for getting/setting the cache entry for this request in the cache. The cacheKey is an MD5 value computed by hashing a combination of the destination URL, the HTTP verb, and the request body (when possible). */ @property (nonatomic, readonly) NSString *cacheKey; /** The cache policy used when storing this request into the request cache */ @property (nonatomic, assign) RKRequestCachePolicy cachePolicy; /** The request cache to store and load responses for this request. Generally configured by the RKClient instance that minted this request This must be assigned one of the following: - `RKRequestCachePolicyNone`: Never use the cache. - `RKRequestCachePolicyLoadIfOffline`: Load from the cache when offline. - `RKRequestCachePolicyLoadOnError`: Load from the cache if an error is encountered. - `RKRequestCachePolicyEtag`: Load from the cache if there is data stored and the server returns a 304 (Not Modified) response. - `RKRequestCachePolicyEnabled`: Load from the cache whenever data has been stored. - `RKRequestCachePolicyTimeout`: Load from the cache if the cacheTimeoutInterval is reached before the server responds. */ @property (nonatomic, retain) RKRequestCache *cache; /** Returns YES if the request is cacheable Only GET requests are considered cacheable (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html). */ - (BOOL)isCacheable; /** The timeout interval within which the request should not be sent and the cached response should be used. Used if the cache policy includes RKRequestCachePolicyTimeout. */ @property (nonatomic, assign) NSTimeInterval cacheTimeoutInterval; ///----------------------------------------------------------------------------- /// @name Handling SSL Validation ///----------------------------------------------------------------------------- /** Flag for disabling SSL certificate validation. When YES, SSL certificates will not be validated. *Default*: NO @warning **WARNING**: This is a potential security exposure and should be used **ONLY while debugging** in a controlled environment. */ @property (nonatomic, assign) BOOL disableCertificateValidation; /** A set of additional certificates to be used in evaluating server SSL certificates. */ @property (nonatomic, retain) NSSet *additionalRootCertificates; ///----------------------------------------------------------------------------- /// @name Sending and Managing the Request ///----------------------------------------------------------------------------- /** Setup the NSURLRequest. The request must be prepared right before dispatching. @return A boolean for the success of the URL preparation. */ - (BOOL)prepareURLRequest; /** The request queue that this request belongs to */ @property (nonatomic, assign) RKRequestQueue *queue; /** Send the request asynchronously. It will be added to the queue and dispatched as soon as possible. */ - (void)send; /** Immediately dispatch a request asynchronously, skipping the request queue. */ - (void)sendAsynchronously; /** Send the request synchronously and return a hydrated response object. @return An RKResponse object with the result of the request. */ - (RKResponse *)sendSynchronously; /** Returns a Boolean value indicating whether the request has been cancelled. @return YES if the request was sent a cancel message, otherwise NO. */ @property(nonatomic, assign, readonly, getter=isCancelled) BOOL cancelled; /** Cancels the underlying URL connection. This will call the requestDidCancel: delegate method if your delegate responds to it. This does not subsequently set the the request's delegate to nil. However, it's good practice to cancel the RKRequest and immediately set the delegate property to nil within the delegate's dealloc method. @see NSURLConnection:cancel */ - (void)cancel; /** The reachability observer to consult for network status. Used for performing offline cache loads. Generally configured by the RKClient instance that minted this request. */ @property (nonatomic, retain) RKReachabilityObserver *reachabilityObserver; ///----------------------------------------------------------------------------- /// @name Resetting the State ///----------------------------------------------------------------------------- /** Resets the state of an RKRequest so that it can be re-sent. */ - (void)reset; ///----------------------------------------------------------------------------- /// @name Callbacks ///----------------------------------------------------------------------------- /** Callback performed to notify the request that the underlying NSURLConnection has failed with an error. @param error An NSError object containing the RKRestKitError that triggered the callback. */ - (void)didFailLoadWithError:(NSError *)error; /** Callback performed to notify the request that the underlying NSURLConnection has completed with a response. @param response An RKResponse object with the result of the request. */ - (void)didFinishLoad:(RKResponse *)response; ///----------------------------------------------------------------------------- /// @name Timing Out the Request ///----------------------------------------------------------------------------- /** The timeout interval within which the request should be cancelled if no data has been received. The timeout timer is cancelled as soon as we start receiving data and are expecting the request to finish. **Default**: 120.0 seconds */ @property (nonatomic, assign) NSTimeInterval timeoutInterval; /** Creates a timeoutTimer to trigger the timeout method This is mainly used so we can test that the timer is only being created once. */ - (void)createTimeoutTimer; /** Cancels request due to connection timeout exceeded. This method is invoked by the timeoutTimer upon its expiration and will return an RKRequestConnectionTimeoutError via didFailLoadWithError: */ - (void)timeout; /** Invalidates the timeout timer. Called by RKResponse when the NSURLConnection begins receiving data. */ - (void)invalidateTimeoutTimer; ///----------------------------------------------------------------------------- /// @name Determining the Request Type and State ///----------------------------------------------------------------------------- /** Returns YES when this is a GET request */ - (BOOL)isGET; /** Returns YES when this is a POST request */ - (BOOL)isPOST; /** Returns YES when this is a PUT request */ - (BOOL)isPUT; /** Returns YES when this is a DELETE request */ - (BOOL)isDELETE; /** Returns YES when this is a HEAD request */ - (BOOL)isHEAD; /** Returns YES when this request is in-progress */ @property (nonatomic, assign, readonly, getter = isLoading) BOOL loading; /** Returns YES when this request has been completed */ @property (nonatomic, assign, readonly, getter = isLoaded) BOOL loaded; /** Returns YES when this request has not yet been sent */ - (BOOL)isUnsent; /** Returns YES when the request was sent to the specified resource path @param resourcePath A string of the resource path that we want to check against */ - (BOOL)wasSentToResourcePath:(NSString *)resourcePath; /** Returns YES when the receiver was sent to the specified resource path with a given request method. @param resourcePath A string of the resource path that we want to check against @param method The HTTP method to confirm the request was sent with. */ - (BOOL)wasSentToResourcePath:(NSString *)resourcePath method:(RKRequestMethod)method; @end /** Lifecycle events for an RKRequest object */ @protocol RKRequestDelegate @optional ///----------------------------------------------------------------------------- /// @name Observing Request Progress ///----------------------------------------------------------------------------- /** Tells the delegate the request is about to be prepared for sending to the remote host. @param request The RKRequest object that is about to be sent. */ - (void)requestWillPrepareForSend:(RKRequest *)request; /** Sent when a request has received a response from the remote host. @param request The RKRequest object that received a response. @param response The RKResponse object for the HTTP response that was received. */ - (void)request:(RKRequest *)request didReceiveResponse:(RKResponse *)response; /** Sent when a request has started loading @param request The RKRequest object that has begun loading. */ - (void)requestDidStartLoad:(RKRequest *)request; /** Sent when a request has uploaded data to the remote site @param request The RKRequest object that is handling the loading. @param bytesWritten An integer of the bytes of the chunk just sent to the remote site. @param totalBytesWritten An integer of the total bytes that have been sent to the remote site. @param totalBytesExpectedToWrite An integer of the total bytes that will be sent to the remote site. */ - (void)request:(RKRequest *)request didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite; /** Sent when request has received data from remote site @param request The RKRequest object that is handling the loading. @param bytesReceived An integer of the bytes of the chunk just received from the remote site. @param totalBytesReceived An integer of the total bytes that have been received from the remote site. @param totalBytesExpectedToReceive An integer of the total bytes that will be received from the remote site. */ - (void)request:(RKRequest *)request didReceiveData:(NSInteger)bytesReceived totalBytesReceived:(NSInteger)totalBytesReceived totalBytesExpectedToReceive:(NSInteger)totalBytesExpectedToReceive; ///----------------------------------------------------------------------------- /// @name Handling Successful Requests ///----------------------------------------------------------------------------- /** Sent when a request has finished loading @param request The RKRequest object that was handling the loading. @param response The RKResponse object containing the result of the request. */ - (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response; ///----------------------------------------------------------------------------- /// @name Handling Failed Requests ///----------------------------------------------------------------------------- /** Sent when a request has failed due to an error @param request The RKRequest object that was handling the loading. @param error An NSError object containing the RKRestKitError that triggered the callback. */ - (void)request:(RKRequest *)request didFailLoadWithError:(NSError *)error; /** Sent to the delegate when a request was cancelled @param request The RKRequest object that was cancelled. */ - (void)requestDidCancelLoad:(RKRequest *)request; /** Sent to the delegate when a request has timed out. This is sent when a backgrounded request expired before completion. @param request The RKRequest object that timed out. */ - (void)requestDidTimeout:(RKRequest *)request; @end