Skip to content

Commit 7b50d79

Browse files
authored
Merge pull request #1643 from maksimorlovich/swift-4.2-branch
2 parents 2d02e61 + 9bf8361 commit 7b50d79

File tree

3 files changed

+77
-6
lines changed

3 files changed

+77
-6
lines changed

Foundation/HTTPCookie.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ open class HTTPCookie : NSObject {
246246
_path = path
247247
_name = name
248248
_value = value
249-
_domain = canonicalDomain
249+
_domain = canonicalDomain.lowercased()
250250

251251
if let
252252
secureString = properties[.secure] as? String, !secureString.isEmpty

Foundation/HTTPCookieStorage.swift

+27-5
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,8 @@ open class HTTPCookieStorage: NSObject {
267267
into a set of header fields to add to a request.
268268
*/
269269
open func cookies(for url: URL) -> [HTTPCookie]? {
270-
guard let host = url.host else { return nil }
271-
return Array(self.syncQ.sync(execute: {allCookies}).values.filter{ $0.domain == host })
270+
guard let host = url.host?.lowercased() else { return nil }
271+
return Array(self.syncQ.sync(execute: {allCookies}).values.filter{ $0.validFor(host: host) })
272272
}
273273

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

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

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

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

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

336336
extension HTTPCookie {
337+
internal func validFor(host: String) -> Bool {
338+
// RFC6265 - HTTP State Management Mechanism
339+
// https://tools.ietf.org/html/rfc6265#section-5.1.3
340+
//
341+
// 5.1.3. Domain Matching
342+
// A string domain-matches a given domain string if at least one of the
343+
// following conditions hold:
344+
//
345+
// 1) The domain string and the string are identical. (Note that both
346+
// the domain string and the string will have been canonicalized to
347+
// lower case at this point.)
348+
//
349+
// 2) All of the following conditions hold:
350+
// * The domain string is a suffix of the string.
351+
// * The last character of the string that is not included in the
352+
// domain string is a %x2E (".") character.
353+
// * The string is a host name (i.e., not an IP address).
354+
355+
guard domain.hasPrefix(".") else { return host == domain }
356+
return host == domain.dropFirst() || host.hasSuffix(domain)
357+
}
358+
337359
internal func persistableDictionary() -> [String: Any] {
338360
var properties: [String: Any] = [:]
339361
properties[HTTPCookiePropertyKey.name.rawValue] = name

TestFoundation/TestHTTPCookieStorage.swift

+49
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class TestHTTPCookieStorage: XCTestCase {
2626
("test_cookiesForURLWithMainDocumentURL", test_cookiesForURLWithMainDocumentURL),
2727
("test_cookieInXDGSpecPath", test_cookieInXDGSpecPath),
2828
("test_descriptionCookie", test_descriptionCookie),
29+
("test_cookieDomainMatching", test_cookieDomainMatching),
2930
]
3031
}
3132

@@ -89,6 +90,11 @@ class TestHTTPCookieStorage: XCTestCase {
8990
descriptionCookie(with: .groupContainer("test"))
9091
}
9192

93+
func test_cookieDomainMatching() {
94+
cookieDomainMatching(with: .shared)
95+
cookieDomainMatching(with: .groupContainer("test"))
96+
}
97+
9298
func getStorage(for type: _StorageType) -> HTTPCookieStorage {
9399
switch type {
94100
case .shared:
@@ -272,6 +278,49 @@ class TestHTTPCookieStorage: XCTestCase {
272278
XCTAssertEqual(storage.description, "<NSHTTPCookieStorage cookies count:\(cookies1.count)>")
273279
}
274280

281+
func cookieDomainMatching(with storageType: _StorageType) {
282+
let storage = getStorage(for: storageType)
283+
284+
let simpleCookie1 = HTTPCookie(properties: [ // swift.org domain only
285+
.name: "TestCookie1",
286+
.value: "TestValue1",
287+
.path: "/",
288+
.domain: "swift.org",
289+
])!
290+
291+
storage.setCookie(simpleCookie1)
292+
293+
let simpleCookie2 = HTTPCookie(properties: [ // *.swift.org
294+
.name: "TestCookie2",
295+
.value: "TestValue2",
296+
.path: "/",
297+
.domain: ".SWIFT.org",
298+
])!
299+
300+
storage.setCookie(simpleCookie2)
301+
302+
let simpleCookie3 = HTTPCookie(properties: [ // bugs.swift.org
303+
.name: "TestCookie3",
304+
.value: "TestValue3",
305+
.path: "/",
306+
.domain: "bugs.swift.org",
307+
])!
308+
309+
storage.setCookie(simpleCookie3)
310+
XCTAssertEqual(storage.cookies!.count, 3)
311+
312+
let swiftOrgUrl = URL(string: "https://swift.ORG")!
313+
let ciSwiftOrgUrl = URL(string: "https://CI.swift.ORG")!
314+
let bugsSwiftOrgUrl = URL(string: "https://BUGS.swift.org")!
315+
let exampleComUrl = URL(string: "http://www.example.com")!
316+
let superSwiftOrgUrl = URL(string: "https://superswift.org")!
317+
XCTAssertEqual(Set(storage.cookies(for: swiftOrgUrl)!), Set([simpleCookie1, simpleCookie2]))
318+
XCTAssertEqual(storage.cookies(for: ciSwiftOrgUrl)!, [simpleCookie2])
319+
XCTAssertEqual(Set(storage.cookies(for: bugsSwiftOrgUrl)!), Set([simpleCookie2, simpleCookie3]))
320+
XCTAssertEqual(storage.cookies(for: exampleComUrl)!, [])
321+
XCTAssertEqual(storage.cookies(for: superSwiftOrgUrl)!, [])
322+
}
323+
275324
func test_cookieInXDGSpecPath() {
276325
#if !os(Android) && !DARWIN_COMPATIBILITY_TESTS
277326
//Test without setting the environment variable

0 commit comments

Comments
 (0)