Improve RKPathMatcher so that it only evaluates a path match positively if the number of slashes in the source string matches the number of slashes in the pattern. closes #1212, closes #1192

This commit is contained in:
Blake Watters
2013-03-10 16:37:35 -04:00
parent 334085def5
commit 34b8a30b06
4 changed files with 56 additions and 10 deletions

View File

@@ -139,7 +139,7 @@
@property (nonatomic, strong, readonly) NSDictionary *responseMappingsDictionary;
/**
Returns an array containing all `RKResponseDescriptor` objects in the configured `responseDescriptors` array that were found to match response.
Returns an array containing all `RKResponseDescriptor` objects in the configured `responseDescriptors` array that were found to match the response.
@see `responseDescriptors`
@see `RKResponseDescriptor`

View File

@@ -38,6 +38,16 @@ static NSString *RKEncodeURLString(NSString *unencodedString)
return encodedString;
}
static NSUInteger RKNumberOfSlashesInString(NSString *string)
{
static NSRegularExpression *regex = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
regex = [NSRegularExpression regularExpressionWithPattern:@"/" options:NSRegularExpressionCaseInsensitive error:nil];
});
return [regex numberOfMatchesInString:string options:0 range:NSMakeRange(0, [string length])];
}
@interface RKPathMatcher ()
@property (nonatomic, strong) SOCPattern *socPattern;
@property (nonatomic, copy) NSString *patternString; // SOCPattern keeps it private
@@ -102,14 +112,10 @@ static NSString *RKEncodeURLString(NSString *unencodedString)
[argumentsCollection addEntriesFromDictionary:self.queryParameters];
}
}
if (![self matches])
return NO;
if (!arguments) {
return YES;
}
if (![self matches]) return NO;
if (!arguments) return YES;
NSDictionary *extracted = [self.socPattern parameterDictionaryFromSourceString:self.rootPath];
if (extracted)
[argumentsCollection addEntriesFromDictionary:RKDictionaryByReplacingPercentEscapesInEntriesFromDictionary(extracted)];
if (extracted) [argumentsCollection addEntriesFromDictionary:RKDictionaryByReplacingPercentEscapesInEntriesFromDictionary(extracted)];
*arguments = argumentsCollection;
return YES;
}
@@ -125,7 +131,8 @@ static NSString *RKEncodeURLString(NSString *unencodedString)
{
self.sourcePath = sourceString;
self.rootPath = sourceString;
return [self itMatchesAndHasParsedArguments:arguments tokenizeQueryStrings:shouldTokenize];
return [self itMatchesAndHasParsedArguments:arguments tokenizeQueryStrings:shouldTokenize]
&& RKNumberOfSlashesInString(self.patternString) == RKNumberOfSlashesInString(self.rootPath);
}
- (NSString *)pathFromObject:(id)object addingEscapes:(BOOL)addEscapes interpolatedParameters:(NSDictionary **)interpolatedParameters

View File

@@ -284,6 +284,28 @@ NSString *RKPathAndQueryStringFromURLRelativeToURL(NSURL *URL, NSURL *baseURL);
expect(mapper.responseMappingsDictionary).to.equal(expectedMappingsDictionary);
}
- (void)testThatResponseDescriptorsDoNotMatchTooAggressively
{
NSURL *responseURL = [NSURL URLWithString:@"http://restkit.org/categories/some-category-name/articles/the-article-name"];
NSURLRequest *request = [NSURLRequest requestWithURL:responseURL];
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:responseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"application/json"}];
NSData *data = [@"{\"some\": \"Data\"}" dataUsingEncoding:NSUTF8StringEncoding];
NSURL *baseURL = [NSURL URLWithString:@"http://restkit.org"];
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
RKResponseDescriptor *responseDescriptor1 = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:@"/categories" keyPath:nil statusCodes:[NSIndexSet indexSetWithIndex:200]];
responseDescriptor1.baseURL = baseURL;
RKResponseDescriptor *responseDescriptor2 = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:@"/categories/:categoryName" keyPath:nil statusCodes:[NSIndexSet indexSetWithIndex:200]];
responseDescriptor2.baseURL = baseURL;
RKResponseDescriptor *responseDescriptor3 = [RKResponseDescriptor responseDescriptorWithMapping:mapping pathPattern:@"/categories/:categorySlug/articles/:articleSlug" keyPath:nil statusCodes:[NSIndexSet indexSetWithIndex:200]];
responseDescriptor3.baseURL = baseURL;
RKObjectResponseMapperOperation *mapper = [[RKObjectResponseMapperOperation alloc] initWithRequest:request response:response data:data responseDescriptors:@[ responseDescriptor1, responseDescriptor2, responseDescriptor3 ]];
[mapper start];
expect(mapper.matchingResponseDescriptors).to.haveCountOf(1);
expect(mapper.matchingResponseDescriptors).to.equal(@[ responseDescriptor3 ]);
}
#pragma mark -
- (void)testThatObjectResponseMapperOperationDoesNotMapWithTargetObjectForUnsuccessfulResponseStatusCode

View File

@@ -156,7 +156,7 @@
expect(matches).to.equal(NO);
pathMatcher = [RKPathMatcher pathMatcherWithPattern:@"/api/:version/organizations/:organizationID"];
matches = [pathMatcher matchesPath:@"/api/v1/organizations/1234/" tokenizeQueryStrings:NO parsedArguments:nil];
matches = [pathMatcher matchesPath:@"/api/v1/organizations/1234" tokenizeQueryStrings:NO parsedArguments:nil];
expect(matches).to.equal(YES);
}
@@ -176,4 +176,21 @@
expect(match).to.beTruthy();
}
- (void)testThatMatchingPathPatternsDoesNotMatchPathsShorterThanTheInput
{
NSString *path = @"/categories/some-category-name/articles/the-article-name";
RKPathMatcher *pathMatcher1 = [RKPathMatcher pathMatcherWithPattern:@"/categories"];
BOOL matches = [pathMatcher1 matchesPath:path tokenizeQueryStrings:NO parsedArguments:nil];
expect(matches).to.equal(NO);
RKPathMatcher *pathMatcher2 = [RKPathMatcher pathMatcherWithPattern:@"/categories/:categoryName"];
matches = [pathMatcher2 matchesPath:path tokenizeQueryStrings:NO parsedArguments:nil];
expect(matches).to.equal(NO);
RKPathMatcher *pathMatcher3 = [RKPathMatcher pathMatcherWithPattern:@"/categories/:categorySlug/articles/:articleSlug"];
matches = [pathMatcher3 matchesPath:path tokenizeQueryStrings:NO parsedArguments:nil];
expect(matches).to.equal(YES);
}
@end