Skip to content

Commit

Permalink
Fixed iOS 7 support for URL query functions
Browse files Browse the repository at this point in the history
Summary:
public
Unfortunately, it turns out that NSURLComponents.queryItems only works on iOS 8 and above. This diff re-implements the RCTGetURLQueryParam and RCTURLByReplacingQueryParam functions using functionality available in iOS 7.

Reviewed By: javache

Differential Revision: D2803679

fb-gh-sync-id: 56f10bef4894d16197975b6023b7aa5ab106d8cb
  • Loading branch information
nicklockwood authored and facebook-github-bot-4 committed Jan 5, 2016
1 parent 2462c8f commit 180fc06
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 8 deletions.
14 changes: 14 additions & 0 deletions Examples/UIExplorer/UIExplorerUnitTests/RCTURLUtilsTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ - (void)testGetQueryParam
XCTAssertEqualObjects(bar, @"foo");
}

- (void)testGetEncodedParam
{
NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=You%20%26%20Me"];
NSString *foo = RCTGetURLQueryParam(URL, @"foo");
XCTAssertEqualObjects(foo, @"You & Me");
}

- (void)testQueryParamNotFound
{
NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=bar"];
Expand Down Expand Up @@ -58,6 +65,13 @@ - (void)testReplaceParam
XCTAssertEqualObjects(result.absoluteString, @"http://example.com?foo=foo&bar=foo");
}

- (void)testReplaceEncodedParam
{
NSURL *URL = [NSURL URLWithString:@"http://example.com?foo=You%20%26%20Me"];
NSURL *result = RCTURLByReplacingQueryParam(URL, @"foo", @"Me & You");
XCTAssertEqualObjects(result.absoluteString, @"http://example.com?foo=Me%20%26%20You");
}

- (void)testAppendParam
{
NSURL *URL = [NSURL URLWithString:@"http://example.com?bar=foo"];
Expand Down
40 changes: 32 additions & 8 deletions React/Base/RCTUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -591,9 +591,13 @@ static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
}
NSURLComponents *components = [NSURLComponents componentsWithURL:URL
resolvingAgainstBaseURL:YES];
for (NSURLQueryItem *item in components.queryItems.reverseObjectEnumerator) {
if ([item.name isEqualToString:param]) {
return item.value;

// TODO: use NSURLComponents.queryItems once we drop support for iOS 7
for (NSString *item in [components.percentEncodedQuery componentsSeparatedByString:@"&"].reverseObjectEnumerator) {
NSArray *keyValue = [item componentsSeparatedByString:@"="];
NSString *key = [keyValue.firstObject stringByRemovingPercentEncoding];
if ([key isEqualToString:param]) {
return [keyValue.lastObject stringByRemovingPercentEncoding];
}
}
return nil;
Expand All @@ -607,22 +611,42 @@ static void RCTGetRGBAColorComponents(CGColorRef color, CGFloat rgba[4])
}
NSURLComponents *components = [NSURLComponents componentsWithURL:URL
resolvingAgainstBaseURL:YES];

// TODO: use NSURLComponents.queryItems once we drop support for iOS 7

// Unhelpfully, iOS doesn't provide this set as a constant
static NSCharacterSet *URLParamCharacterSet;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSMutableCharacterSet *characterSet = [NSMutableCharacterSet new];
[characterSet formUnionWithCharacterSet:[NSCharacterSet URLQueryAllowedCharacterSet]];
[characterSet removeCharactersInString:@"&=?"];
URLParamCharacterSet = [characterSet copy];
});

NSString *encodedParam =
[param stringByAddingPercentEncodingWithAllowedCharacters:URLParamCharacterSet];

__block NSInteger paramIndex = NSNotFound;
NSMutableArray *queryItems = [components.queryItems mutableCopy];
NSMutableArray *queryItems = [[components.percentEncodedQuery componentsSeparatedByString:@"&"] mutableCopy];
[queryItems enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:
^(NSURLQueryItem *item, NSUInteger i, BOOL *stop) {
if ([item.name isEqualToString:param]) {
^(NSString *item, NSUInteger i, BOOL *stop) {
NSArray *keyValue = [item componentsSeparatedByString:@"="];
if ([keyValue.firstObject isEqualToString:encodedParam]) {
paramIndex = i;
*stop = YES;
}
}];

NSURLQueryItem *newItem = [NSURLQueryItem queryItemWithName:param value:value];
NSString *encodedValue =
[value stringByAddingPercentEncodingWithAllowedCharacters:URLParamCharacterSet];

NSString *newItem = [encodedParam stringByAppendingFormat:@"=%@", encodedValue];
if (paramIndex == NSNotFound) {
[queryItems addObject:newItem];
} else {
[queryItems replaceObjectAtIndex:paramIndex withObject:newItem];
}
components.queryItems = queryItems;
components.percentEncodedQuery = [queryItems componentsJoinedByString:@"&"];
return components.URL;
}

0 comments on commit 180fc06

Please sign in to comment.