Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Fix #1042: Implement DomainAndRegistry for eTLD+1 #5239

Merged
merged 3 commits into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@ import UIKit
import XCTest
@testable import Shared

private extension String {
var isIPv6: Bool {
return self.contains(":")
}

var baseDomain: String? {
guard !NSURL.isHostIPAddress(host: self) else { return nil }

// If this is just a hostname and not a FQDN, use the entire hostname.
if !self.contains(".") {
return self
}

let registry = NSURL.domainAndRegistry(host: self)
return registry.isEmpty ? nil : registry
}

var publicSuffix: String? {
let registry = NSURL.registry(host: self)
return registry.isEmpty ? nil : registry
}
}

class NSURLExtensionsTests: XCTestCase {
func testRemovesHTTPFromURL() {
let url = URL(string: "http://google.com")
Expand Down Expand Up @@ -76,66 +99,78 @@ class NSURLExtensionsTests: XCTestCase {
let url = "http://a.bbc.co.uk".asURL!
let expected = url.publicSuffix!
XCTAssertEqual("co.uk", expected)
XCTAssertEqual("co.uk", url.host?.publicSuffix!)
}

func testBaseDomainWithTrailingDot() {
var url = URL(string: "https://test.domain.com")
XCTAssertEqual(url?.baseDomain, "domain.com")
XCTAssertEqual(url?.host?.baseDomain, "domain.com")

url = URL(string: "https://test.domain.com.")
XCTAssertEqual(url?.baseDomain, "domain.com")
XCTAssertEqual(url?.baseDomain, "domain.com.")
XCTAssertEqual(url?.host?.baseDomain, "domain.com.")

url = URL(string: "https://test.domain.com..")
XCTAssertEqual(url?.baseDomain, nil)
XCTAssertEqual(url?.host?.baseDomain, nil)

url = URL(string: "https://foo")
XCTAssertEqual(url?.baseDomain, "foo")
XCTAssertEqual(url?.host?.baseDomain, "foo")

url = URL(string: "https://foo.")
XCTAssertEqual(url?.baseDomain, ".foo")
XCTAssertEqual(url?.host?.baseDomain, nil)

url = URL(string: "https://.")
XCTAssertEqual(url?.baseDomain, "")
XCTAssertEqual(url?.baseDomain, nil)
XCTAssertEqual(url?.host?.baseDomain, nil)
}

func testCanadaComputers() {
let url = "http://m.canadacomputers.com".asURL!
let actual = url.baseDomain!
let actual = url.baseDomain
XCTAssertEqual("canadacomputers.com", actual)
XCTAssertEqual("canadacomputers.com", url.host?.baseDomain)
}

func testMultipleSuffixesInsideURL() {
let url = "http://com:org@m.canadacomputers.co.uk".asURL!
let actual = url.baseDomain!
let actual = url.baseDomain
XCTAssertEqual("canadacomputers.co.uk", actual)
XCTAssertEqual("canadacomputers.co.uk", url.host?.baseDomain)
}

func testNormalBaseDomainWithManySubdomains() {
// TLD Entry: co.uk
let url = "http://a.b.c.d.bbc.co.uk".asURL!
let expected = url.publicSuffix!
let expected = url.publicSuffix
XCTAssertEqual("co.uk", expected)
XCTAssertEqual("co.uk", url.host?.publicSuffix)
}

func testWildCardDomainWithSingleSubdomain() {
// TLD Entry: *.kawasaki.jp
let url = "http://a.kawasaki.jp".asURL!
let expected = url.publicSuffix!
XCTAssertEqual("a.kawasaki.jp", expected)
let expected = url.publicSuffix
XCTAssertEqual(expected, nil)
XCTAssertEqual(url.host?.publicSuffix, nil)
}

func testWildCardDomainWithManySubdomains() {
// TLD Entry: *.kawasaki.jp
let url = "http://a.b.c.d.kawasaki.jp".asURL!
let expected = url.publicSuffix!
let expected = url.publicSuffix
XCTAssertEqual("d.kawasaki.jp", expected)
XCTAssertEqual("d.kawasaki.jp", url.host?.publicSuffix)
}

func testExceptionDomain() {
// TLD Entry: !city.kawasaki.jp
let url = "http://city.kawasaki.jp".asURL!
let expected = url.publicSuffix!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe remove that ! You're testing it's not nil so I don't think you should put that ! there plus you don't really need it. Both would result in a failed test but one will give you some better test information.

XCTAssertEqual("kawasaki.jp", expected)
XCTAssertEqual("kawasaki.jp", url.host?.publicSuffix)
}

//MARK: Base Domain
Expand All @@ -144,41 +179,47 @@ class NSURLExtensionsTests: XCTestCase {
let url = "http://bbc.co.uk".asURL!
let expected = url.baseDomain!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above and all the rest below.

XCTAssertEqual("bbc.co.uk", expected)
XCTAssertEqual("bbc.co.uk", url.host?.baseDomain)
}

func testNormalBaseSubdomainWithAdditionalSubdomain() {
// TLD Entry: co.uk
let url = "http://a.bbc.co.uk".asURL!
let expected = url.baseDomain!
XCTAssertEqual("bbc.co.uk", expected)
XCTAssertEqual("bbc.co.uk", url.host?.baseDomain)
}

func testBaseDomainForWildcardDomain() {
// TLD Entry: *.kawasaki.jp
let url = "http://a.b.kawasaki.jp".asURL!
let expected = url.baseDomain!
XCTAssertEqual("a.b.kawasaki.jp", expected)
XCTAssertEqual("a.b.kawasaki.jp", url.host?.baseDomain)
}

func testBaseDomainForWildcardDomainWithAdditionalSubdomain() {
// TLD Entry: *.kawasaki.jp
let url = "http://a.b.c.kawasaki.jp".asURL!
let expected = url.baseDomain!
XCTAssertEqual("b.c.kawasaki.jp", expected)
XCTAssertEqual("b.c.kawasaki.jp", url.host?.baseDomain)
}

func testBaseDomainForExceptionDomain() {
// TLD Entry: !city.kawasaki.jp
let url = "http://city.kawasaki.jp".asURL!
let expected = url.baseDomain!
XCTAssertEqual("city.kawasaki.jp", expected)
XCTAssertEqual("city.kawasaki.jp", url.host?.baseDomain)
}

func testBaseDomainForExceptionDomainWithAdditionalSubdomain() {
// TLD Entry: !city.kawasaki.jp
let url = "http://a.city.kawasaki.jp".asURL!
let expected = url.baseDomain!
XCTAssertEqual("city.kawasaki.jp", expected)
XCTAssertEqual("city.kawasaki.jp", url.host?.baseDomain)
}

func testBugzillaURLDomain() {
Expand All @@ -195,6 +236,7 @@ class NSURLExtensionsTests: XCTestCase {
let url = "http://[::1]/foo/bar".asURL!
XCTAssertTrue(url.isIPv6)
XCTAssertNil(url.baseDomain)
XCTAssertNil("[::1]".baseDomain)
XCTAssertEqual(url.normalizedHost()!, "[::1]")
}

Expand Down
8 changes: 4 additions & 4 deletions Client.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,7 @@
CA29F2F3273DAEA100C391C3 /* PlaylistOnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA29F2F2273DAEA100C391C3 /* PlaylistOnboardingView.swift */; };
CA2CA1B127F4B50300B25646 /* ReadyState.js in Resources */ = {isa = PBXBuildFile; fileRef = CA2CA1B027F4B50300B25646 /* ReadyState.js */; };
CA2CA1CF27F4B93400B25646 /* ReadyStateScriptHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2CA1CE27F4B93400B25646 /* ReadyStateScriptHelper.swift */; };
CA2CA21F27F75E4800B25646 /* NSURLExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2CA21E27F75E4800B25646 /* NSURLExtensionsTests.swift */; };
CA2EE0A527349E970089C75F /* disconnect-entitylist.json in Resources */ = {isa = PBXBuildFile; fileRef = CA2EE09927349E970089C75F /* disconnect-entitylist.json */; };
CA2EE0A727349F760089C75F /* OnboardingAdblockDisconnect.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA2EE0A627349F760089C75F /* OnboardingAdblockDisconnect.swift */; };
CA39359227E3CBB400D18585 /* CertificateUtilsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA39359127E3CBB400D18585 /* CertificateUtilsTest.swift */; };
Expand Down Expand Up @@ -1258,7 +1259,6 @@
E698FFDA1B4AADF40001F623 /* TabScrollController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E698FFD91B4AADF40001F623 /* TabScrollController.swift */; };
E69922171B94E3EF007C480D /* Licenses.html in Resources */ = {isa = PBXBuildFile; fileRef = E69922121B94E3EF007C480D /* Licenses.html */; };
E6F965121B2F1CF20034B023 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; };
E6F9653C1B2F1D5D0034B023 /* NSURLExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F9653B1B2F1D5D0034B023 /* NSURLExtensionsTests.swift */; };
E6FF6ACA1D873CFF0070C294 /* PageMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6FF6AC91D873CFF0070C294 /* PageMetadata.swift */; };
EB11A1052044A90E0018F749 /* TrackingProtectionPageStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB11A1022044A90D0018F749 /* TrackingProtectionPageStats.swift */; };
EB11A1062044A90E0018F749 /* ContentBlockerHelper+TabContentScript.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB11A1032044A90E0018F749 /* ContentBlockerHelper+TabContentScript.swift */; };
Expand Down Expand Up @@ -3051,6 +3051,7 @@
CA29F2F2273DAEA100C391C3 /* PlaylistOnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaylistOnboardingView.swift; sourceTree = "<group>"; };
CA2CA1B027F4B50300B25646 /* ReadyState.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = ReadyState.js; sourceTree = "<group>"; };
CA2CA1CE27F4B93400B25646 /* ReadyStateScriptHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadyStateScriptHelper.swift; sourceTree = "<group>"; };
CA2CA21E27F75E4800B25646 /* NSURLExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURLExtensionsTests.swift; sourceTree = "<group>"; };
CA2EE09927349E970089C75F /* disconnect-entitylist.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "disconnect-entitylist.json"; sourceTree = "<group>"; };
CA2EE0A627349F760089C75F /* OnboardingAdblockDisconnect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingAdblockDisconnect.swift; sourceTree = "<group>"; };
CA39359127E3CBB400D18585 /* CertificateUtilsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CertificateUtilsTest.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3256,7 +3257,6 @@
E6F738761EB7A97500B50143 /* Release.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
E6F9650C1B2F1CF20034B023 /* SharedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SharedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
E6F9650F1B2F1CF20034B023 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E6F9653B1B2F1D5D0034B023 /* NSURLExtensionsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURLExtensionsTests.swift; sourceTree = "<group>"; };
E6FF6AC91D873CFF0070C294 /* PageMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageMetadata.swift; sourceTree = "<group>"; };
EB11A1022044A90D0018F749 /* TrackingProtectionPageStats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrackingProtectionPageStats.swift; sourceTree = "<group>"; };
EB11A1032044A90E0018F749 /* ContentBlockerHelper+TabContentScript.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ContentBlockerHelper+TabContentScript.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5642,6 +5642,7 @@
5D6DDEFF21428CF0001FF0AE /* DAUTests.swift */,
27A586E0214C0DDD000CAE3C /* PreferencesTest.swift */,
0A42150021AC0E8E006B8E39 /* TimeExtensionTests.swift */,
CA2CA21E27F75E4800B25646 /* NSURLExtensionsTests.swift */,
5DE7689520B3456E00FF5533 /* Info.plist */,
2777273F22EB44B300F0214C /* StringExtensionTests.swift */,
5EEB25DD234E667700279091 /* CertificatePinningTest.swift */,
Expand Down Expand Up @@ -6474,7 +6475,6 @@
28786E541AB0F5FA009EA9EF /* DeferredTests.swift */,
A176323020CF2A6000126F25 /* DeferredTestUtils.swift */,
E4E25CCA1CA99E7400D0F088 /* HexExtensionsTests.swift */,
E6F9653B1B2F1D5D0034B023 /* NSURLExtensionsTests.swift */,
2FEBABAE1AB3659000DB5728 /* ResultTests.swift */,
28A6CE891AC082E200C1A2D4 /* UtilsTests.swift */,
3BB54B301E68EB2B0021DAC4 /* AuthenticationKeychainInfoTests.swift */,
Expand Down Expand Up @@ -8404,6 +8404,7 @@
0A917391231D173C0069A08B /* AppReviewTests.swift in Sources */,
5EEB25DE234E667700279091 /* CertificatePinningTest.swift in Sources */,
5D6DDF0021428CF0001FF0AE /* DAUTests.swift in Sources */,
CA2CA21F27F75E4800B25646 /* NSURLExtensionsTests.swift in Sources */,
0A42150121AC0E8E006B8E39 /* TimeExtensionTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -8435,7 +8436,6 @@
0AB7FCDF235DEE8F00F1D9F5 /* NumberExtensionTests.swift in Sources */,
E4E25CCB1CA99E7400D0F088 /* HexExtensionsTests.swift in Sources */,
28532BE91C471FFB000072D9 /* ResultTests.swift in Sources */,
E6F9653C1B2F1D5D0034B023 /* NSURLExtensionsTests.swift in Sources */,
3B4AA24B1D8B8C4C00A2E008 /* ArrayExtensionTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
10 changes: 7 additions & 3 deletions Shared/Extensions/URLExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import UIKit
import BraveCore

private struct ETLDEntry: CustomStringConvertible {
let entry: String
Expand Down Expand Up @@ -260,8 +261,9 @@ extension URL {
if !host.contains(".") {
return host
}

return publicSuffixFromHost(host, withAdditionalParts: 1)

let registry = (self as NSURL).domainAndRegistry
return registry.isEmpty ? nil : registry
}

/**
Expand Down Expand Up @@ -320,7 +322,8 @@ extension URL {
:returns: The public suffix for within the given hostname.
*/
public var publicSuffix: String? {
return host.flatMap { publicSuffixFromHost($0, withAdditionalParts: 0) }
let registry = (self as NSURL).registry
return registry.isEmpty ? nil : registry
}

public func isWebPage(includeDataURIs: Bool = true) -> Bool {
Expand Down Expand Up @@ -735,6 +738,7 @@ public struct InternalURL {

// MARK: Private Helpers
private extension URL {
@available(*, deprecated, message: "Use URL.publicSuffix or URL.baseDomain depending on your needs")
func publicSuffixFromHost(_ host: String, withAdditionalParts additionalPartCount: Int) -> String? {
if host.isEmpty {
return nil
Expand Down