Skip to content

Commit 9f6f3b5

Browse files
committed
Bugfix FXIOS-14375 DefaultURLFormatter not handling urls properly for < iOS 17
1 parent 02858f4 commit 9f6f3b5

File tree

2 files changed

+32
-19
lines changed

2 files changed

+32
-19
lines changed

BrowserKit/Sources/WebEngine/Utilities/URLFormatter.swift

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public final class DefaultURLFormatter: URLFormatter {
6060
// Handle the entry if it has a scheme, make sure it's safe before browsing to it
6161
private func handleWithScheme(with entry: String) -> URL? {
6262
// Check if the URL includes a scheme
63-
guard let url = URL(string: entry),
63+
guard let url = handleURL(with: entry),
6464
url.scheme != nil,
6565
entry.range(of: "\\b:[0-9]{1,5}", options: .regularExpression) == nil else {
6666
return nil
@@ -73,17 +73,44 @@ public final class DefaultURLFormatter: URLFormatter {
7373
}
7474
}
7575

76-
guard let url = URL(string: entry) else { return nil }
77-
7876
// Only allow this URL if it's safe
7977
let browsingContext = BrowsingContext(type: .internalNavigation, url: url)
8078
if securityManager.canNavigateWith(browsingContext: browsingContext) == .allowed {
81-
return URL(string: entry)
79+
return url
8280
} else {
8381
return nil
8482
}
8583
}
8684

85+
private func handleURL(with entry: String) -> URL? {
86+
// Per Apple docs, for apps linked on or after iOS 17 and aligned OS versions, URL parsing has updated
87+
// from the obsolete RFC 1738/1808 parsing to the same RFC 3986 parsing as URLComponents.
88+
// iOS 17+, URL automatically percent- and IDNA-encodes invalid characters to help create a valid URL.
89+
90+
if #available(iOS 17, *) {
91+
return URL(string: entry)
92+
} else {
93+
// We only want to do percent encoding on our other schemes
94+
let hasHTTPScheme = entry.hasPrefix("http://") || entry.hasPrefix("https://")
95+
guard !hasHTTPScheme else { return URL(string: entry) }
96+
guard let escapedURL = entry.addingPercentEncoding(withAllowedCharacters: urlAllowed) else {
97+
return nil
98+
}
99+
guard let finalURL = URL(string: escapedURL), schemeIsValid(for: finalURL) else { return nil }
100+
return finalURL
101+
}
102+
}
103+
104+
/**
105+
Returns whether the URL's scheme is one of those listed on the official list of URI schemes.
106+
This only accepts permanent schemes: historical and provisional schemes are not accepted.
107+
*/
108+
public func schemeIsValid(for url: URL) -> Bool {
109+
guard let scheme = url.scheme else { return false }
110+
return SchemesDefinition.permanentURISchemes.contains(scheme.lowercased())
111+
&& url.absoluteString.lowercased() != scheme + ":"
112+
}
113+
87114
// Handle the entry if it has no scheme
88115
private func handleNoScheme(with entry: String) -> URL? {
89116
// First trim white spaces

BrowserKit/Tests/WebEngineTests/Utilities/URLFormatterTests.swift

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,7 @@ final class URLFormatterTests: XCTestCase {
3535
XCTAssertEqual(result?.absoluteString, initialUrl)
3636
}
3737

38-
func testGetURLGivenAboutConfigSpaceURLThenValidEscapedURL_foriOS17AndBelow() throws {
39-
if #available(iOS 17, *) {
40-
throw XCTSkip("Skipping since test does not apply for iOS 17 and above versions")
41-
} else {
42-
let initialUrl = "about:%20config"
43-
let subject = DefaultURLFormatter()
44-
let result = subject.getURL(entry: initialUrl)
45-
XCTAssertEqual(result?.absoluteString, "about:%20config")
46-
}
47-
}
48-
49-
func testGetURLGivenAboutConfigSpaceURLThenValidEscapedURL_foriOS17AndAbove() throws {
50-
guard #available(iOS 17, *) else {
51-
throw XCTSkip("Skipping unless iOS 17 and above versions")
52-
}
38+
func testGetURLGivenAboutConfigSpaceURLThenValidEscapedURL() throws {
5339
let initialUrl = "about: config"
5440
let subject = DefaultURLFormatter()
5541
let result = subject.getURL(entry: initialUrl)

0 commit comments

Comments
 (0)