Skip to content

Commit 0215082

Browse files
committed
DarwinCompatibility: HTTPCookie fixes for version 0 cookies
- For expiry date, prefer maximum-age over expires-date but only use maximum-age for version 1 cookies. - For version 0 cookies only return the first port number, if available.
1 parent dc11b4e commit 0215082

File tree

2 files changed

+48
-44
lines changed

2 files changed

+48
-44
lines changed

Foundation/HTTPCookie.swift

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -266,54 +266,55 @@ open class HTTPCookie : NSObject {
266266
}
267267
_version = version
268268

269-
if let portString = properties[.port] as? String, _version == 1 {
270-
_portList = portString.split(separator: ",")
269+
if let portString = properties[.port] as? String {
270+
let portList = portString.split(separator: ",")
271271
.compactMap { Int(String($0)) }
272272
.map { NSNumber(value: $0) }
273+
if version == 1 {
274+
_portList = portList
275+
} else {
276+
// Version 0 only stores a single port number
277+
_portList = portList.count > 0 ? [portList[0]] : nil
278+
}
273279
} else {
274280
_portList = nil
275281
}
276282

277-
// TODO: factor into a utility function
278-
if version == 0 {
283+
var expDate: Date? = nil
284+
// Maximum-Age is prefered over expires-Date but only version 1 cookies use Maximum-Age
285+
if let maximumAge = properties[.maximumAge] as? String,
286+
let secondsFromNow = Int(maximumAge) {
287+
if version == 1 {
288+
expDate = Date(timeIntervalSinceNow: Double(secondsFromNow))
289+
}
290+
} else {
279291
let expiresProperty = properties[.expires]
280292
if let date = expiresProperty as? Date {
281-
_expiresDate = date
293+
expDate = date
282294
} else if let dateString = expiresProperty as? String {
283295
let formatter = DateFormatter()
284296
formatter.locale = Locale(identifier: "en_US_POSIX")
285297
formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss O" // per RFC 6265 '<rfc1123-date, defined in [RFC2616], Section 3.3.1>'
286298
let timeZone = TimeZone(abbreviation: "GMT")
287299
formatter.timeZone = timeZone
288-
_expiresDate = formatter.date(from: dateString)
289-
} else {
290-
_expiresDate = nil
300+
expDate = formatter.date(from: dateString)
291301
}
292-
} else if
293-
let maximumAge = properties[.maximumAge] as? String,
294-
let secondsFromNow = Int(maximumAge), _version == 1 {
295-
_expiresDate = Date(timeIntervalSinceNow: Double(secondsFromNow))
296-
} else {
297-
_expiresDate = nil
298302
}
303+
_expiresDate = expDate
299304

300305
if let discardString = properties[.discard] as? String {
301306
_sessionOnly = discardString == "TRUE"
302307
} else {
303308
_sessionOnly = properties[.maximumAge] == nil && version >= 1
304309
}
305-
if version == 0 {
306-
_comment = nil
307-
_commentURL = nil
310+
311+
_comment = properties[.comment] as? String
312+
if let commentURL = properties[.commentURL] as? URL {
313+
_commentURL = commentURL
314+
} else if let commentURL = properties[.commentURL] as? String {
315+
_commentURL = URL(string: commentURL)
308316
} else {
309-
_comment = properties[.comment] as? String
310-
if let commentURL = properties[.commentURL] as? URL {
311-
_commentURL = commentURL
312-
} else if let commentURL = properties[.commentURL] as? String {
313-
_commentURL = URL(string: commentURL)
314-
} else {
315-
_commentURL = nil
316-
}
317+
_commentURL = nil
317318
}
318319
_HTTPOnly = false
319320

@@ -363,7 +364,11 @@ open class HTTPCookie : NSObject {
363364
cookieString.removeLast()
364365
cookieString.removeLast()
365366
}
366-
return ["Cookie": cookieString]
367+
if cookieString == "" {
368+
return [:]
369+
} else {
370+
return ["Cookie": cookieString]
371+
}
367372
}
368373

369374
/// Return an array of cookies parsed from the specified response header fields and URL.
@@ -418,9 +423,9 @@ open class HTTPCookie : NSObject {
418423
properties[canonicalize(name)] = value
419424
}
420425

421-
//if domain wasn't provided use the URL
426+
// If domain wasn't provided, extract it from the URL
422427
if properties[.domain] == nil {
423-
properties[.domain] = url.absoluteString
428+
properties[.domain] = url.host
424429
}
425430

426431
//the default Path is "/"

TestFoundation/TestHTTPCookie.swift

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,31 +75,29 @@ class TestHTTPCookie: XCTestCase {
7575
.domain: "apple.com",
7676
.originURL: URL(string: "https://apple.com")!,
7777
.comment: "This comment should be nil since this is a v0 cookie.",
78-
.commentURL: URL(string: "https://apple.com")!,
78+
.commentURL: "https://apple.com",
7979
.discard: "TRUE",
8080
.expires: Date(timeIntervalSince1970: 1000),
8181
.maximumAge: "2000",
8282
.port: "443,8443",
8383
.secure: "YES"
8484
])
85-
XCTAssertNil(versionZeroCookieWithInvalidVersionOneProps?.comment)
86-
XCTAssertNil(versionZeroCookieWithInvalidVersionOneProps?.commentURL)
85+
XCTAssertEqual(versionZeroCookieWithInvalidVersionOneProps?.version, 0)
86+
XCTAssertNotNil(versionZeroCookieWithInvalidVersionOneProps?.comment)
87+
XCTAssertNotNil(versionZeroCookieWithInvalidVersionOneProps?.commentURL)
8788
XCTAssert(versionZeroCookieWithInvalidVersionOneProps?.isSessionOnly == true)
8889

8990
// v0 should never use NSHTTPCookieMaximumAge
90-
XCTAssert(
91-
versionZeroCookieWithInvalidVersionOneProps?.expiresDate?.timeIntervalSince1970 ==
92-
Date(timeIntervalSince1970: 1000).timeIntervalSince1970
93-
)
91+
XCTAssertNil(versionZeroCookieWithInvalidVersionOneProps?.expiresDate?.timeIntervalSince1970)
9492

95-
XCTAssertNil(versionZeroCookieWithInvalidVersionOneProps?.portList)
93+
XCTAssertEqual(versionZeroCookieWithInvalidVersionOneProps?.portList, [NSNumber(value: 443)])
9694
XCTAssert(versionZeroCookieWithInvalidVersionOneProps?.isSecure == true)
9795
XCTAssert(versionZeroCookieWithInvalidVersionOneProps?.version == 0)
9896
}
9997

10098
func test_RequestHeaderFields() {
10199
let noCookies: [HTTPCookie] = []
102-
XCTAssertEqual(HTTPCookie.requestHeaderFields(with: noCookies)["Cookie"], "")
100+
XCTAssertNil(HTTPCookie.requestHeaderFields(with: noCookies)["Cookie"])
103101

104102
let basicCookies: [HTTPCookie] = [
105103
HTTPCookie(properties: [
@@ -125,7 +123,7 @@ class TestHTTPCookie: XCTestCase {
125123
"Set-Cookie": "fr=anjd&232; Max-Age=7776000; path=/; domain=.example.com; secure; httponly",
126124
"header2":"value2",
127125
"header3":"value3"]
128-
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "http://example.com")!)
126+
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "https://example.com")!)
129127
XCTAssertEqual(cookies.count, 1)
130128
XCTAssertEqual(cookies[0].name, "fr")
131129
XCTAssertEqual(cookies[0].value, "anjd&232")
@@ -142,19 +140,20 @@ class TestHTTPCookie: XCTestCase {
142140
"Set-Cookie": "fr=a&2@#; Max-Age=1186000; path=/; domain=.example.com; secure, xd=plm!@#;path=/;domain=.example2.com",
143141
"header2":"value2",
144142
"header3":"value3"]
145-
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "http://example.com")!)
143+
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "https://example.com")!)
146144
XCTAssertEqual(cookies.count, 2)
147145
XCTAssertTrue(cookies[0].isSecure)
148146
XCTAssertFalse(cookies[1].isSecure)
149147
}
150148

151149
func test_cookiesWithResponseHeaderNoDomain() {
152150
let header = ["header1":"value1",
153-
"Set-Cookie": "fr=anjd&232; expires=Wed, 21 Sep 2016 05:33:00 GMT; Max-Age=7776000; path=/; secure; httponly",
151+
"Set-Cookie": "fr=anjd&232; expires=Wed, 21 Sep 2016 05:33:00 GMT; path=/; secure; httponly",
154152
"header2":"value2",
155153
"header3":"value3"]
156-
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "http://example.com")!)
157-
XCTAssertEqual(cookies[0].domain, "http://example.com")
154+
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "https://example.com")!)
155+
XCTAssertEqual(cookies[0].version, 0)
156+
XCTAssertEqual(cookies[0].domain, "example.com")
158157
XCTAssertNotNil(cookies[0].expiresDate)
159158

160159
let formatter = DateFormatter()
@@ -173,8 +172,8 @@ class TestHTTPCookie: XCTestCase {
173172
"Set-Cookie": "fr=tx; expires=Wed, 21-Sep-2016 05:33:00 GMT; Max-Age=7776000; secure; httponly",
174173
"header2":"value2",
175174
"header3":"value3"]
176-
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "http://example.com")!)
177-
XCTAssertEqual(cookies[0].domain, "http://example.com")
175+
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "https://example.com")!)
176+
XCTAssertEqual(cookies[0].domain, "example.com")
178177
XCTAssertEqual(cookies[0].path, "/")
179178
}
180179
}

0 commit comments

Comments
 (0)