Skip to content

Commit 5ff19f0

Browse files
cipolleschifacebook-github-bot
authored andcommitted
Back out "Reapply Fix escaping in the URL conversion" (#37103)
Summary: Pull Request resolved: #37103 Re backout the fix as there are some edge cases not handled properly internally. ## Changelog: [iOS][Fixed] - Revert change in URL escaping Reviewed By: javache, sammy-SC, rshest Differential Revision: D45309232 fbshipit-source-id: d9f473d1f6409beb1069d9af7e649ee5b1b06d6e
1 parent 495506d commit 5ff19f0

File tree

2 files changed

+22
-79
lines changed

2 files changed

+22
-79
lines changed

packages/react-native/React/Base/RCTConvert.m

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,30 @@ + (NSURL *)NSURL:(id)json
8383
return nil;
8484
}
8585

86-
@try { // NSURL has a history of crashing with bad input, so let's be
86+
@try { // NSURL has a history of crashing with bad input, so let's be safe
8787

88-
NSURLComponents *urlComponents = [NSURLComponents componentsWithString:path]; //[NSURL URLWithString:path];
89-
if (urlComponents.scheme) {
90-
return [self _preprocessURLComponents:urlComponents from:path].URL;
88+
NSURL *URL = [NSURL URLWithString:path];
89+
if (URL.scheme) { // Was a well-formed absolute URL
90+
return URL;
9191
}
9292

93+
// Check if it has a scheme
94+
if ([path rangeOfString:@"://"].location != NSNotFound) {
95+
NSMutableCharacterSet *urlAllowedCharacterSet = [NSMutableCharacterSet new];
96+
[urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLUserAllowedCharacterSet]];
97+
[urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLPasswordAllowedCharacterSet]];
98+
[urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLHostAllowedCharacterSet]];
99+
[urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLPathAllowedCharacterSet]];
100+
[urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLQueryAllowedCharacterSet]];
101+
[urlAllowedCharacterSet formUnionWithCharacterSet:[NSCharacterSet URLFragmentAllowedCharacterSet]];
102+
path = [path stringByAddingPercentEncodingWithAllowedCharacters:urlAllowedCharacterSet];
103+
URL = [NSURL URLWithString:path];
104+
if (URL) {
105+
return URL;
106+
}
107+
}
108+
109+
// Assume that it's a local path
93110
path = path.stringByRemovingPercentEncoding;
94111
if ([path hasPrefix:@"~"]) {
95112
// Path is inside user directory
@@ -98,8 +115,7 @@ + (NSURL *)NSURL:(id)json
98115
// Assume it's a resource path
99116
path = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:path];
100117
}
101-
NSURL *URL = [NSURL fileURLWithPath:path];
102-
if (!URL) {
118+
if (!(URL = [NSURL fileURLWithPath:path])) {
103119
RCTLogConvertError(json, @"a valid URL");
104120
}
105121
return URL;
@@ -109,39 +125,6 @@ + (NSURL *)NSURL:(id)json
109125
}
110126
}
111127

112-
// This function preprocess the URLComponents received to make sure that we decode it properly
113-
// handling all the use cases.
114-
// See the `RCTConvert_NSURLTests` file for a list of use cases that we want to support:
115-
// To achieve that, we are currently splitting the url, extracting the fragment, so we can
116-
// decode and encode everything but the fragment (which has to be left unmodified)
117-
+ (NSURLComponents *)_preprocessURLComponents:(NSURLComponents *)urlComponents from:(NSString *)path
118-
{
119-
// https://developer.apple.com/documentation/foundation/nsurlcomponents
120-
// "[NSURLComponents's] behavior differs subtly from the NSURL class, which conforms to older RFCs"
121-
// Specifically, NSURL rejects some URLs that NSURLComponents will handle
122-
// gracefully.
123-
NSRange fragmentRange = urlComponents.rangeOfFragment;
124-
125-
if (fragmentRange.length == 0) {
126-
// No fragment, pre-remove all escaped characters so we can encode them once if they are present.
127-
NSError *error = nil;
128-
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"%[0-90-9]" options:0 error:&error];
129-
NSTextCheckingResult *match = [regex firstMatchInString:path options:0 range:NSMakeRange(0, path.length)];
130-
if (match) {
131-
return [NSURLComponents componentsWithString:path.stringByRemovingPercentEncoding];
132-
}
133-
return [NSURLComponents componentsWithString:path];
134-
}
135-
// Pre-remove all escaped characters (excluding the fragment) to handle partially encoded strings
136-
NSString *baseUrlString = [path substringToIndex:fragmentRange.location].stringByRemovingPercentEncoding;
137-
// Fragment must be kept as they are passed. We don't have to escape them
138-
NSString *unmodifiedFragment = [path substringFromIndex:fragmentRange.location];
139-
140-
// Recreate the url by using a decoded base and an unmodified fragment.
141-
NSString *preprocessedURL = [NSString stringWithFormat:@"%@%@", baseUrlString, unmodifiedFragment];
142-
return [NSURLComponents componentsWithString:preprocessedURL];
143-
}
144-
145128
RCT_ENUM_CONVERTER(
146129
NSURLRequestCachePolicy,
147130
(@{

packages/rn-tester/RNTesterUnitTests/RCTConvert_NSURLTests.m

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -77,44 +77,4 @@ - (void)testDataURL
7777
XCTAssertEqualObjects([testURL absoluteString], [expectedURL absoluteString]);
7878
}
7979

80-
// Escaping edge cases
81-
TEST_URL(
82-
urlWithMultipleHashes,
83-
@"https://example.com/#/abc/#test:example.com",
84-
@"https://example.com/#/abc/%23test:example.com")
85-
TEST_URL(urlWithEqualsInQuery, @"https://example.com/abc.def?ghi=1234", @"https://example.com/abc.def?ghi=1234")
86-
TEST_URL(
87-
urlWithEscapedCharacterInFragment,
88-
@"https://example.com/abc/def.ghi#jkl-mno%27p-qrs",
89-
@"https://example.com/abc/def.ghi#jkl-mno%27p-qrs")
90-
TEST_URL(
91-
urlWithLongQuery,
92-
@"https://example.com/abc?q=def+ghi+jkl&mno=p-q-r-s&tuv=wxy&z_=abc&abc=5",
93-
@"https://example.com/abc?q=def+ghi+jkl&mno=p-q-r-s&tuv=wxy&z_=abc&abc=5")
94-
TEST_URL(
95-
urlWithEscapedCharacterInPathFragment,
96-
@"https://example.com/#/abc/%23def%3Aghi.org",
97-
@"https://example.com/#/abc/%23def%3Aghi.org")
98-
TEST_URL(
99-
urlWithEscapedCharacterInQuery,
100-
@"https://site.com/script?foo=bar#this_ref",
101-
@"https://site.com/script?foo=bar#this_ref")
102-
TEST_URL(
103-
urlWithUnescapedJson,
104-
@"https://example.com/?{\"key\":\"value\"}",
105-
@"https://example.com/?%7B%22key%22:%22value%22%7D")
106-
TEST_URL(
107-
urlWithPartiallyEscapedData,
108-
@"https://example.com/?{%22key%22:%22value%22}",
109-
@"https://example.com/?%7B%22key%22:%22value%22%7D")
110-
TEST_URL(urlWithPercent, @"https://example.com/?width=22%", @"https://example.com/?width=22%25")
111-
// NOTE: This is illegal per RFC 3986, but earlier URL specs allowed it
112-
TEST_URL(urlWithSquareBracketInPath, @"http://www.foo.com/file[.html", @"http://www.foo.com/file%5B.html")
113-
114-
TEST_URL(baseDeepLink, @"myapp://launch", @"myapp://launch")
115-
TEST_URL(
116-
deepLinkWithParams,
117-
@"myapp://screen_route?withId=123&prodId=456&isSelected=true",
118-
@"myapp://screen_route?withId=123&prodId=456&isSelected=true")
119-
12080
@end

0 commit comments

Comments
 (0)