Skip to content

Commit 69c65ef

Browse files
committed
Override error implementation to correct the NSLocalizedDescription key for RKHTTPRequestOperation objects. fixes RestKit#1070
1 parent 138bbdd commit 69c65ef

File tree

6 files changed

+114
-4
lines changed

6 files changed

+114
-4
lines changed

Code/Network/RKHTTPRequestOperation.m

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#undef RKLogComponent
2929
#define RKLogComponent RKlcl_cRestKitNetwork
3030

31+
NSString *RKStringFromIndexSet(NSIndexSet *indexSet); // Defined in RKResponseDescriptor.m
32+
3133
static BOOL RKLogIsStringBlank(NSString *string)
3234
{
3335
return ([[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0);
@@ -163,10 +165,13 @@ - (void)HTTPOperationDidFinish:(NSNotification *)notification
163165
@end
164166

165167
@interface AFURLConnectionOperation () <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
168+
@property (readwrite, nonatomic, strong) NSError *HTTPError;
166169
@end
167170

168171
@implementation RKHTTPRequestOperation
169172

173+
@dynamic HTTPError;
174+
170175
- (BOOL)hasAcceptableStatusCode
171176
{
172177
return self.acceptableStatusCodes ? [self.acceptableStatusCodes containsIndex:[self.response statusCode]] : [super hasAcceptableStatusCode];
@@ -177,6 +182,32 @@ - (BOOL)hasAcceptableContentType
177182
return self.acceptableContentTypes ? RKMIMETypeInSet([self.response MIMEType], self.acceptableContentTypes) : [super hasAcceptableContentType];
178183
}
179184

185+
- (NSError *)error
186+
{
187+
// The first we are invoked, we need to mutate the HTTP error to correct the Content Types and Status Codes returned
188+
if (self.response && !self.HTTPError) {
189+
NSError *error = [super error];
190+
if ([error.domain isEqualToString:AFNetworkingErrorDomain]) {
191+
if (![self hasAcceptableStatusCode] || ![self hasAcceptableContentType]) {
192+
NSMutableDictionary *userInfo = [error.userInfo mutableCopy];
193+
194+
if (error.code == NSURLErrorBadServerResponse) {
195+
// Replace the NSLocalizedDescriptionKey
196+
NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200;
197+
[userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected status code in (%@), got %d", nil), RKStringFromIndexSet([self acceptableStatusCodes]), statusCode] forKey:NSLocalizedDescriptionKey];
198+
self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo];
199+
} else if (error.code == NSURLErrorCannotDecodeContentData) {
200+
// Because we have shifted the Acceptable Content Types and Status Codes
201+
[userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected content type %@, got %@", nil), [self acceptableContentTypes], [self.response MIMEType]] forKey:NSLocalizedDescriptionKey];
202+
self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
203+
}
204+
}
205+
}
206+
}
207+
208+
return [super error];
209+
}
210+
180211
- (BOOL)wasNotModified
181212
{
182213
return [(NSString *)[[self.response allHeaderFields] objectForKey:@"Status"] isEqualToString:@"304 Not Modified"];

Code/Network/RKObjectManager.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ RKMappingResult, RKRequestDescriptor, RKResponseDescriptor;
312312
@property (nonatomic, strong) NSString *requestSerializationMIMEType;
313313

314314
/**
315-
Sets a default header on the HTTP cleitn for the HTTP "Accept" header to specify the preferred serialization format for retrieved data.
315+
Sets a default header on the HTTP client for the HTTP "Accept" header to specify the preferred serialization format for retrieved data.
316316
317317
This method is a convenience method whose implementation is equivalent to the following example code:
318318

Code/Network/RKObjectRequestOperation.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static void RKDecrementNetworkAcitivityIndicator()
5757
return [NSString stringWithFormat:@"%@ '%@'", request.HTTPMethod, [request.URL absoluteString]];
5858
}
5959

60-
static NSIndexSet *RKObjectRequestOperationAcceptableMIMETypes()
60+
static NSIndexSet *RKObjectRequestOperationAcceptableStatusCodes()
6161
{
6262
static NSMutableIndexSet *statusCodes = nil;
6363
if (! statusCodes) {
@@ -136,7 +136,7 @@ - (id)initWithHTTPRequestOperation:(RKHTTPRequestOperation *)requestOperation re
136136
self.responseDescriptors = responseDescriptors;
137137
self.HTTPRequestOperation = requestOperation;
138138
self.HTTPRequestOperation.acceptableContentTypes = [RKMIMETypeSerialization registeredMIMETypes];
139-
self.HTTPRequestOperation.acceptableStatusCodes = RKObjectRequestOperationAcceptableMIMETypes();
139+
self.HTTPRequestOperation.acceptableStatusCodes = RKObjectRequestOperationAcceptableStatusCodes();
140140
}
141141

142142
return self;

RestKit.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@
367367
2548AC6E162F5E00009E79BF /* RKManagedObjectRequestOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2548AC6C162F5E00009E79BF /* RKManagedObjectRequestOperationTest.m */; };
368368
2549D646162B376F003DD135 /* RKRequestDescriptorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2549D645162B376F003DD135 /* RKRequestDescriptorTest.m */; };
369369
2549D647162B376F003DD135 /* RKRequestDescriptorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2549D645162B376F003DD135 /* RKRequestDescriptorTest.m */; };
370+
2551338F167838590017E4B6 /* RKHTTPRequestOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2551338E167838590017E4B6 /* RKHTTPRequestOperationTest.m */; };
371+
25513390167838590017E4B6 /* RKHTTPRequestOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2551338E167838590017E4B6 /* RKHTTPRequestOperationTest.m */; };
370372
25565956161FC3C300F5BB20 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25565955161FC3C300F5BB20 /* CoreServices.framework */; };
371373
25565959161FC3CD00F5BB20 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25565958161FC3CD00F5BB20 /* SystemConfiguration.framework */; };
372374
25565965161FDD8800F5BB20 /* RKResponseMapperOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 25565964161FDD8800F5BB20 /* RKResponseMapperOperationTest.m */; };
@@ -827,6 +829,7 @@
827829
2548AC6C162F5E00009E79BF /* RKManagedObjectRequestOperationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKManagedObjectRequestOperationTest.m; sourceTree = "<group>"; };
828830
2549D645162B376F003DD135 /* RKRequestDescriptorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKRequestDescriptorTest.m; sourceTree = "<group>"; };
829831
254A62BF14AD591C00939BEE /* RKPaginatorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKPaginatorTest.m; sourceTree = "<group>"; };
832+
2551338E167838590017E4B6 /* RKHTTPRequestOperationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKHTTPRequestOperationTest.m; sourceTree = "<group>"; };
830833
25565955161FC3C300F5BB20 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/CoreServices.framework; sourceTree = DEVELOPER_DIR; };
831834
25565958161FC3CD00F5BB20 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; };
832835
25565964161FDD8800F5BB20 /* RKResponseMapperOperationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKResponseMapperOperationTest.m; sourceTree = "<group>"; };
@@ -1454,6 +1457,7 @@
14541457
2549D645162B376F003DD135 /* RKRequestDescriptorTest.m */,
14551458
2548AC6C162F5E00009E79BF /* RKManagedObjectRequestOperationTest.m */,
14561459
2536D1FC167270F100DF9BB0 /* RKRouterTest.m */,
1460+
2551338E167838590017E4B6 /* RKHTTPRequestOperationTest.m */,
14571461
);
14581462
name = Network;
14591463
path = Logic/Network;
@@ -2353,6 +2357,7 @@
23532357
2546A95816628EDD0078E044 /* RKConnectionDescriptionTest.m in Sources */,
23542358
2543A25D1664FD3100821D5B /* RKResponseDescriptorTest.m in Sources */,
23552359
2536D1FD167270F100DF9BB0 /* RKRouterTest.m in Sources */,
2360+
2551338F167838590017E4B6 /* RKHTTPRequestOperationTest.m in Sources */,
23562361
);
23572362
runOnlyForDeploymentPostprocessing = 0;
23582363
};
@@ -2502,6 +2507,7 @@
25022507
2546A95916628EDD0078E044 /* RKConnectionDescriptionTest.m in Sources */,
25032508
2543A25E1664FD3200821D5B /* RKResponseDescriptorTest.m in Sources */,
25042509
2536D1FE167270F100DF9BB0 /* RKRouterTest.m in Sources */,
2510+
25513390167838590017E4B6 /* RKHTTPRequestOperationTest.m in Sources */,
25052511
);
25062512
runOnlyForDeploymentPostprocessing = 0;
25072513
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// RKHTTPRequestOperationTest.m
3+
// RestKit
4+
//
5+
// Created by Blake Watters on 12/11/12.
6+
// Copyright (c) 2012 RestKit. All rights reserved.
7+
//
8+
9+
#import "RKTestEnvironment.h"
10+
#import "RKHTTPRequestOperation.h"
11+
12+
@interface RKHTTPRequestOperationTest : SenTestCase
13+
14+
@end
15+
16+
@implementation RKHTTPRequestOperationTest
17+
18+
- (void)testThatLoadingAnUnexpectedContentTypeReturnsCorrectErrorMessage
19+
{
20+
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/XML/channels.xml" relativeToURL:[RKTestFactory baseURL]]];
21+
RKHTTPRequestOperation *requestOperation = [[RKHTTPRequestOperation alloc] initWithRequest:request];
22+
requestOperation.acceptableContentTypes = [NSSet setWithObject:@"application/json"];
23+
requestOperation.acceptableStatusCodes = [NSIndexSet indexSetWithIndex:200];
24+
[requestOperation start];
25+
[requestOperation waitUntilFinished];
26+
27+
expect(requestOperation.error).notTo.beNil();
28+
expect([requestOperation.error localizedDescription]).to.equal(@"Expected content type {(\n \"application/json\"\n)}, got application/xml");
29+
}
30+
31+
- (void)testThatLoadingAnUnexpectedStatusCodeReturnsCorrectErrorMessage
32+
{
33+
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/503" relativeToURL:[RKTestFactory baseURL]]];
34+
RKHTTPRequestOperation *requestOperation = [[RKHTTPRequestOperation alloc] initWithRequest:request];
35+
requestOperation.acceptableContentTypes = [NSSet setWithObject:@"text/xml"];
36+
requestOperation.acceptableStatusCodes = [NSIndexSet indexSetWithIndex:200];
37+
[requestOperation start];
38+
[requestOperation waitUntilFinished];
39+
40+
expect(requestOperation.error).notTo.beNil();
41+
expect([requestOperation.error localizedDescription]).to.equal(@"Expected status code in (200), got 503");
42+
}
43+
44+
@end

Tests/Logic/Network/RKObjectRequestOperationTest.m

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,6 @@ - (void)testMappingResponseWithExactMatchForResponseDescriptorPathPattern
334334

335335
- (void)testMappingResponseWithDynamicMatchForResponseDescriptorPathPattern
336336
{
337-
338337
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
339338
[userMapping addAttributeMappingsFromArray:@[@"firstname"]];
340339
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping pathPattern:@"/JSON/:name\\.json" keyPath:@"data.STUser" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
@@ -545,4 +544,34 @@ - (void)testShouldAllowMutationOfTheParsedDataInWillMapData
545544
expect(user.email).to.equal(@"blake@restkit.org");
546545
}
547546

547+
- (void)testThatLoadingAnUnexpectedContentTypeReturnsCorrectErrorMessage
548+
{
549+
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
550+
[userMapping addAttributeMappingsFromArray:@[@"firstname"]];
551+
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping pathPattern:@"/JSON/ComplexNestedUser.json" keyPath:@"data.STUser" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
552+
553+
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/XML/channels.xml" relativeToURL:[RKTestFactory baseURL]]];
554+
RKObjectRequestOperation *requestOperation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
555+
[requestOperation start];
556+
[requestOperation waitUntilFinished];
557+
558+
expect(requestOperation.error).notTo.beNil();
559+
expect([requestOperation.error localizedDescription]).to.equal(@"Expected content type {(\n \"application/json\",\n \"application/x-www-form-urlencoded\"\n)}, got application/xml");
560+
}
561+
562+
- (void)testThatLoadingAnUnexpectedStatusCodeReturnsCorrectErrorMessage
563+
{
564+
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKTestComplexUser class]];
565+
[userMapping addAttributeMappingsFromArray:@[@"firstname"]];
566+
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping pathPattern:@"/JSON/ComplexNestedUser.json" keyPath:@"data.STUser" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
567+
568+
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/503" relativeToURL:[RKTestFactory baseURL]]];
569+
RKObjectRequestOperation *requestOperation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ responseDescriptor ]];
570+
[requestOperation start];
571+
[requestOperation waitUntilFinished];
572+
573+
expect(requestOperation.error).notTo.beNil();
574+
expect([requestOperation.error localizedDescription]).to.equal(@"Expected status code in (200-299,400-499), got 503");
575+
}
576+
548577
@end

0 commit comments

Comments
 (0)