mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-05 22:40:21 +08:00
291 lines
9.7 KiB
Objective-C
291 lines
9.7 KiB
Objective-C
//
|
|
// RKRequest.m
|
|
// RestKit
|
|
//
|
|
// Created by Jeremy Ellison on 7/27/09.
|
|
// Copyright 2009 Two Toasters. All rights reserved.
|
|
//
|
|
|
|
#import "RKRequest.h"
|
|
#import "RKRequestQueue.h"
|
|
#import "RKResponse.h"
|
|
#import "NSDictionary+RKRequestSerialization.h"
|
|
#import "RKNotifications.h"
|
|
#import "RKClient.h"
|
|
#import "../Support/Support.h"
|
|
#import "RKURL.h"
|
|
#import <UIKit/UIKit.h>
|
|
|
|
@implementation RKRequest
|
|
|
|
@synthesize URL = _URL, URLRequest = _URLRequest, delegate = _delegate, additionalHTTPHeaders = _additionalHTTPHeaders,
|
|
params = _params, userData = _userData, username = _username, password = _password, method = _method,
|
|
authenticationScheme = _authenticationScheme;
|
|
|
|
+ (RKRequest*)requestWithURL:(NSURL*)URL delegate:(id)delegate {
|
|
return [[[RKRequest alloc] initWithURL:URL delegate:delegate] autorelease];
|
|
}
|
|
|
|
- (id)initWithURL:(NSURL*)URL {
|
|
self = [self init];
|
|
if (self) {
|
|
_URL = [URL retain];
|
|
_URLRequest = [[NSMutableURLRequest alloc] initWithURL:_URL];
|
|
_connection = nil;
|
|
_isLoading = NO;
|
|
_isLoaded = NO;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (id)initWithURL:(NSURL*)URL delegate:(id)delegate {
|
|
self = [self initWithURL:URL];
|
|
if (self) {
|
|
_delegate = delegate;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc {
|
|
self.delegate = nil;
|
|
[_connection cancel];
|
|
[_connection release];
|
|
_connection = nil;
|
|
[_userData release];
|
|
_userData = nil;
|
|
[_URL release];
|
|
_URL = nil;
|
|
[_URLRequest release];
|
|
_URLRequest = nil;
|
|
[_params release];
|
|
_params = nil;
|
|
[_additionalHTTPHeaders release];
|
|
_additionalHTTPHeaders = nil;
|
|
[_authenticationScheme release];
|
|
[_username release];
|
|
_username = nil;
|
|
[_password release];
|
|
_password = nil;
|
|
[super dealloc];
|
|
}
|
|
|
|
- (void)setRequestBody {
|
|
if (_params && (_method != RKRequestMethodGET)) {
|
|
// Prefer the use of a stream over a raw body
|
|
if ([_params respondsToSelector:@selector(HTTPBodyStream)]) {
|
|
[_URLRequest setHTTPBodyStream:[_params HTTPBodyStream]];
|
|
} else {
|
|
[_URLRequest setHTTPBody:[_params HTTPBody]];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)addHeadersToRequest {
|
|
NSString* header;
|
|
for (header in _additionalHTTPHeaders) {
|
|
[_URLRequest setValue:[_additionalHTTPHeaders valueForKey:header] forHTTPHeaderField:header];
|
|
}
|
|
|
|
if (_params != nil) {
|
|
// Temporarily support older RKRequestSerializable implementations
|
|
if ([_params respondsToSelector:@selector(HTTPHeaderValueForContentType)]) {
|
|
[_URLRequest setValue:[_params HTTPHeaderValueForContentType] forHTTPHeaderField:@"Content-Type"];
|
|
} else if ([_params respondsToSelector:@selector(ContentTypeHTTPHeader)]) {
|
|
[_URLRequest setValue:[_params performSelector:@selector(ContentTypeHTTPHeader)] forHTTPHeaderField:@"Content-Type"];
|
|
}
|
|
if ([_params respondsToSelector:@selector(HTTPHeaderValueForContentLength)]) {
|
|
[_URLRequest setValue:[NSString stringWithFormat:@"%d", [_params HTTPHeaderValueForContentLength]] forHTTPHeaderField:@"Content-Length"];
|
|
}
|
|
}
|
|
|
|
if (_username != nil && [_authenticationScheme isEqualToString:(NSString*)kCFHTTPAuthenticationSchemeBasic]) {
|
|
// Add authentication headers so we don't have to deal with an extra cycle for each message requiring basic auth.
|
|
CFHTTPMessageRef dummyRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)[self HTTPMethod], (CFURLRef)[self URL], kCFHTTPVersion1_1);
|
|
CFHTTPMessageAddAuthentication(dummyRequest, nil, (CFStringRef)_username, (CFStringRef)_password, kCFHTTPAuthenticationSchemeBasic, FALSE);
|
|
CFStringRef authorizationString = CFHTTPMessageCopyHeaderFieldValue(dummyRequest, CFSTR("Authorization"));
|
|
|
|
[_URLRequest setValue:(NSString *)authorizationString forHTTPHeaderField:@"Authorization"];
|
|
|
|
CFRelease(dummyRequest);
|
|
CFRelease(authorizationString);
|
|
}
|
|
|
|
NSLog(@"Headers: %@", [_URLRequest allHTTPHeaderFields]);
|
|
}
|
|
|
|
// Setup the NSURLRequest. The request must be prepared right before dispatching
|
|
- (void)prepareURLRequest {
|
|
[_URLRequest setHTTPMethod:[self HTTPMethod]];
|
|
[self setRequestBody];
|
|
[self addHeadersToRequest];
|
|
}
|
|
|
|
- (NSString*)HTTPMethod {
|
|
switch (_method) {
|
|
case RKRequestMethodGET:
|
|
return @"GET";
|
|
break;
|
|
case RKRequestMethodPOST:
|
|
return @"POST";
|
|
break;
|
|
case RKRequestMethodPUT:
|
|
return @"PUT";
|
|
break;
|
|
case RKRequestMethodDELETE:
|
|
return @"DELETE";
|
|
break;
|
|
default:
|
|
return nil;
|
|
break;
|
|
}
|
|
}
|
|
|
|
- (void)send {
|
|
[[RKRequestQueue sharedQueue] sendRequest:self];
|
|
}
|
|
|
|
- (void)fireAsynchronousRequest {
|
|
if ([[RKClient sharedClient] isNetworkAvailable]) {
|
|
[self prepareURLRequest];
|
|
NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding];
|
|
NSLog(@"Sending %@ request to URL %@. HTTP Body: %@", [self HTTPMethod], [[self URL] absoluteString], body);
|
|
[body release];
|
|
NSDate* sentAt = [NSDate date];
|
|
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", sentAt, @"sentAt", nil];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestSentNotification object:self userInfo:userInfo];
|
|
|
|
_isLoading = YES;
|
|
RKResponse* response = [[[RKResponse alloc] initWithRequest:self] autorelease];
|
|
_connection = [[NSURLConnection connectionWithRequest:_URLRequest delegate:response] retain];
|
|
} else {
|
|
NSString* errorMessage = [NSString stringWithFormat:@"The client is unable to contact the resource at %@", [[self URL] absoluteString]];
|
|
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
errorMessage, NSLocalizedDescriptionKey,
|
|
nil];
|
|
NSError* error = [NSError errorWithDomain:RKRestKitErrorDomain code:RKRequestBaseURLOfflineError userInfo:userInfo];
|
|
[self didFailLoadWithError:error];
|
|
}
|
|
}
|
|
|
|
- (RKResponse*)sendSynchronously {
|
|
NSURLResponse* URLResponse = nil;
|
|
NSError* error = nil;
|
|
NSData* payload = nil;
|
|
RKResponse* response = nil;
|
|
|
|
if ([[RKClient sharedClient] isNetworkAvailable]) {
|
|
[self prepareURLRequest];
|
|
NSString* body = [[NSString alloc] initWithData:[_URLRequest HTTPBody] encoding:NSUTF8StringEncoding];
|
|
NSLog(@"Sending synchronous %@ request to URL %@. HTTP Body: %@", [self HTTPMethod], [[self URL] absoluteString], body);
|
|
[body release];
|
|
NSDate* sentAt = [NSDate date];
|
|
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", sentAt, @"sentAt", nil];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestSentNotification object:self userInfo:userInfo];
|
|
|
|
_isLoading = YES;
|
|
payload = [NSURLConnection sendSynchronousRequest:_URLRequest returningResponse:&URLResponse error:&error];
|
|
response = [[[RKResponse alloc] initWithSynchronousRequest:self URLResponse:URLResponse body:payload error:error] autorelease];
|
|
|
|
if (error) {
|
|
[self didFailLoadWithError:error];
|
|
} else {
|
|
[self didFinishLoad:response];
|
|
}
|
|
} else {
|
|
NSString* errorMessage = [NSString stringWithFormat:@"The client is unable to contact the resource at %@", [[self URL] absoluteString]];
|
|
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
errorMessage, NSLocalizedDescriptionKey,
|
|
nil];
|
|
error = [NSError errorWithDomain:RKRestKitErrorDomain code:RKRequestBaseURLOfflineError userInfo:userInfo];
|
|
[self didFailLoadWithError:error];
|
|
|
|
// TODO: Is this needed here? Or can we just return a nil response and everyone will be happy??
|
|
response = [[[RKResponse alloc] initWithSynchronousRequest:self URLResponse:URLResponse body:payload error:error] autorelease];
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
- (void)cancel {
|
|
[_connection cancel];
|
|
[_connection release];
|
|
_connection = nil;
|
|
_isLoading = NO;
|
|
}
|
|
|
|
- (void)didFailLoadWithError:(NSError*)error {
|
|
_isLoading = NO;
|
|
|
|
if ([_delegate respondsToSelector:@selector(request:didFailLoadWithError:)]) {
|
|
[_delegate request:self didFailLoadWithError:error];
|
|
}
|
|
|
|
NSDate* receivedAt = [NSDate date];
|
|
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod",
|
|
[self URL], @"URL", receivedAt, @"receivedAt", error, @"error", nil];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kRKRequestFailedWithErrorNotification object:self userInfo:userInfo];
|
|
}
|
|
|
|
- (void)didFinishLoad:(RKResponse*)response {
|
|
_isLoading = NO;
|
|
_isLoaded = YES;
|
|
|
|
if ([_delegate respondsToSelector:@selector(request:didLoadResponse:)]) {
|
|
[_delegate request:self didLoadResponse:response];
|
|
}
|
|
|
|
NSDate* receivedAt = [NSDate date];
|
|
NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[self HTTPMethod], @"HTTPMethod", [self URL], @"URL", receivedAt, @"receivedAt", nil];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:kRKResponseReceivedNotification object:response userInfo:userInfo];
|
|
|
|
if ([response isServiceUnavailable] && [[RKClient sharedClient] serviceUnavailableAlertEnabled]) {
|
|
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:[[RKClient sharedClient] serviceUnavailableAlertTitle]
|
|
message:[[RKClient sharedClient] serviceUnavailableAlertMessage]
|
|
delegate:nil
|
|
cancelButtonTitle:NSLocalizedString(@"OK", nil)
|
|
otherButtonTitles:nil];
|
|
[alertView show];
|
|
[alertView release];
|
|
|
|
}
|
|
}
|
|
|
|
- (BOOL)isGET {
|
|
return _method == RKRequestMethodGET;
|
|
}
|
|
|
|
- (BOOL)isPOST {
|
|
return _method == RKRequestMethodPOST;
|
|
}
|
|
|
|
- (BOOL)isPUT {
|
|
return _method == RKRequestMethodPUT;
|
|
}
|
|
|
|
- (BOOL)isDELETE {
|
|
return _method == RKRequestMethodDELETE;
|
|
}
|
|
|
|
- (BOOL)isLoading {
|
|
return _isLoading;
|
|
}
|
|
|
|
- (BOOL)isLoaded {
|
|
return _isLoaded;
|
|
}
|
|
|
|
- (NSString*)resourcePath {
|
|
NSString* resourcePath = nil;
|
|
if ([self.URL isKindOfClass:[RKURL class]]) {
|
|
RKURL* url = (RKURL*)self.URL;
|
|
resourcePath = url.resourcePath;
|
|
}
|
|
return resourcePath;
|
|
}
|
|
|
|
- (BOOL)wasSentToResourcePath:(NSString*)resourcePath {
|
|
return [[self resourcePath] isEqualToString:resourcePath];
|
|
}
|
|
|
|
@end
|