Skip to content

Commit

Permalink
Merge pull request #1643 from maksimorlovich/swift-4.2-branch
Browse files Browse the repository at this point in the history
  • Loading branch information
swift-ci committed Aug 6, 2018
2 parents 2d02e61 + 9bf8361 commit 7b50d79
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Foundation/HTTPCookie.swift
Expand Up @@ -246,7 +246,7 @@ open class HTTPCookie : NSObject {
_path = path
_name = name
_value = value
_domain = canonicalDomain
_domain = canonicalDomain.lowercased()

if let
secureString = properties[.secure] as? String, !secureString.isEmpty
Expand Down
32 changes: 27 additions & 5 deletions Foundation/HTTPCookieStorage.swift
Expand Up @@ -267,8 +267,8 @@ open class HTTPCookieStorage: NSObject {
into a set of header fields to add to a request.
*/
open func cookies(for url: URL) -> [HTTPCookie]? {
guard let host = url.host else { return nil }
return Array(self.syncQ.sync(execute: {allCookies}).values.filter{ $0.domain == host })
guard let host = url.host?.lowercased() else { return nil }
return Array(self.syncQ.sync(execute: {allCookies}).values.filter{ $0.validFor(host: host) })
}

/*!
Expand All @@ -293,17 +293,17 @@ open class HTTPCookieStorage: NSObject {
guard cookieAcceptPolicy != .never else { return }

//if the urls don't have a host, we cannot do anything
guard let urlHost = url?.host else { return }
guard let urlHost = url?.host?.lowercased() else { return }

if mainDocumentURL != nil && cookieAcceptPolicy == .onlyFromMainDocumentDomain {
guard let mainDocumentHost = mainDocumentURL?.host else { return }
guard let mainDocumentHost = mainDocumentURL?.host?.lowercased() else { return }

//the url.host must be a suffix of manDocumentURL.host, this is based on Darwin's behaviour
guard mainDocumentHost.hasSuffix(urlHost) else { return }
}

//save only those cookies whose domain matches with the url.host
let validCookies = cookies.filter { urlHost == $0.domain }
let validCookies = cookies.filter { $0.validFor(host: urlHost) }
for cookie in validCookies {
setCookie(cookie)
}
Expand Down Expand Up @@ -334,6 +334,28 @@ public extension Notification.Name {
}

extension HTTPCookie {
internal func validFor(host: String) -> Bool {
// RFC6265 - HTTP State Management Mechanism
// https://tools.ietf.org/html/rfc6265#section-5.1.3
//
// 5.1.3. Domain Matching
// A string domain-matches a given domain string if at least one of the
// following conditions hold:
//
// 1) The domain string and the string are identical. (Note that both
// the domain string and the string will have been canonicalized to
// lower case at this point.)
//
// 2) All of the following conditions hold:
// * The domain string is a suffix of the string.
// * The last character of the string that is not included in the
// domain string is a %x2E (".") character.
// * The string is a host name (i.e., not an IP address).

guard domain.hasPrefix(".") else { return host == domain }
return host == domain.dropFirst() || host.hasSuffix(domain)
}

internal func persistableDictionary() -> [String: Any] {
var properties: [String: Any] = [:]
properties[HTTPCookiePropertyKey.name.rawValue] = name
Expand Down
49 changes: 49 additions & 0 deletions TestFoundation/TestHTTPCookieStorage.swift
Expand Up @@ -26,6 +26,7 @@ class TestHTTPCookieStorage: XCTestCase {
("test_cookiesForURLWithMainDocumentURL", test_cookiesForURLWithMainDocumentURL),
("test_cookieInXDGSpecPath", test_cookieInXDGSpecPath),
("test_descriptionCookie", test_descriptionCookie),
("test_cookieDomainMatching", test_cookieDomainMatching),
]
}

Expand Down Expand Up @@ -89,6 +90,11 @@ class TestHTTPCookieStorage: XCTestCase {
descriptionCookie(with: .groupContainer("test"))
}

func test_cookieDomainMatching() {
cookieDomainMatching(with: .shared)
cookieDomainMatching(with: .groupContainer("test"))
}

func getStorage(for type: _StorageType) -> HTTPCookieStorage {
switch type {
case .shared:
Expand Down Expand Up @@ -272,6 +278,49 @@ class TestHTTPCookieStorage: XCTestCase {
XCTAssertEqual(storage.description, "<NSHTTPCookieStorage cookies count:\(cookies1.count)>")
}

func cookieDomainMatching(with storageType: _StorageType) {
let storage = getStorage(for: storageType)

let simpleCookie1 = HTTPCookie(properties: [ // swift.org domain only
.name: "TestCookie1",
.value: "TestValue1",
.path: "/",
.domain: "swift.org",
])!

storage.setCookie(simpleCookie1)

let simpleCookie2 = HTTPCookie(properties: [ // *.swift.org
.name: "TestCookie2",
.value: "TestValue2",
.path: "/",
.domain: ".SWIFT.org",
])!

storage.setCookie(simpleCookie2)

let simpleCookie3 = HTTPCookie(properties: [ // bugs.swift.org
.name: "TestCookie3",
.value: "TestValue3",
.path: "/",
.domain: "bugs.swift.org",
])!

storage.setCookie(simpleCookie3)
XCTAssertEqual(storage.cookies!.count, 3)

let swiftOrgUrl = URL(string: "https://swift.ORG")!
let ciSwiftOrgUrl = URL(string: "https://CI.swift.ORG")!
let bugsSwiftOrgUrl = URL(string: "https://BUGS.swift.org")!
let exampleComUrl = URL(string: "http://www.example.com")!
let superSwiftOrgUrl = URL(string: "https://superswift.org")!
XCTAssertEqual(Set(storage.cookies(for: swiftOrgUrl)!), Set([simpleCookie1, simpleCookie2]))
XCTAssertEqual(storage.cookies(for: ciSwiftOrgUrl)!, [simpleCookie2])
XCTAssertEqual(Set(storage.cookies(for: bugsSwiftOrgUrl)!), Set([simpleCookie2, simpleCookie3]))
XCTAssertEqual(storage.cookies(for: exampleComUrl)!, [])
XCTAssertEqual(storage.cookies(for: superSwiftOrgUrl)!, [])
}

func test_cookieInXDGSpecPath() {
#if !os(Android) && !DARWIN_COMPATIBILITY_TESTS
//Test without setting the environment variable
Expand Down

0 comments on commit 7b50d79

Please sign in to comment.