Skip to content

Commit 959b133

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 c820eb7 commit 959b133

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
@@ -67,31 +67,29 @@ class TestHTTPCookie: XCTestCase {
6767
.domain: "apple.com",
6868
.originURL: URL(string: "https://apple.com")!,
6969
.comment: "This comment should be nil since this is a v0 cookie.",
70-
.commentURL: URL(string: "https://apple.com")!,
70+
.commentURL: "https://apple.com",
7171
.discard: "TRUE",
7272
.expires: Date(timeIntervalSince1970: 1000),
7373
.maximumAge: "2000",
7474
.port: "443,8443",
7575
.secure: "YES"
7676
])
77-
XCTAssertNil(versionZeroCookieWithInvalidVersionOneProps?.comment)
78-
XCTAssertNil(versionZeroCookieWithInvalidVersionOneProps?.commentURL)
77+
XCTAssertEqual(versionZeroCookieWithInvalidVersionOneProps?.version, 0)
78+
XCTAssertNotNil(versionZeroCookieWithInvalidVersionOneProps?.comment)
79+
XCTAssertNotNil(versionZeroCookieWithInvalidVersionOneProps?.commentURL)
7980
XCTAssert(versionZeroCookieWithInvalidVersionOneProps?.isSessionOnly == true)
8081

8182
// v0 should never use NSHTTPCookieMaximumAge
82-
XCTAssert(
83-
versionZeroCookieWithInvalidVersionOneProps?.expiresDate?.timeIntervalSince1970 ==
84-
Date(timeIntervalSince1970: 1000).timeIntervalSince1970
85-
)
83+
XCTAssertNil(versionZeroCookieWithInvalidVersionOneProps?.expiresDate?.timeIntervalSince1970)
8684

87-
XCTAssertNil(versionZeroCookieWithInvalidVersionOneProps?.portList)
85+
XCTAssertEqual(versionZeroCookieWithInvalidVersionOneProps?.portList, [NSNumber(value: 443)])
8886
XCTAssert(versionZeroCookieWithInvalidVersionOneProps?.isSecure == true)
8987
XCTAssert(versionZeroCookieWithInvalidVersionOneProps?.version == 0)
9088
}
9189

9290
func test_RequestHeaderFields() {
9391
let noCookies: [HTTPCookie] = []
94-
XCTAssertEqual(HTTPCookie.requestHeaderFields(with: noCookies)["Cookie"], "")
92+
XCTAssertNil(HTTPCookie.requestHeaderFields(with: noCookies)["Cookie"])
9593

9694
let basicCookies: [HTTPCookie] = [
9795
HTTPCookie(properties: [
@@ -117,7 +115,7 @@ class TestHTTPCookie: XCTestCase {
117115
"Set-Cookie": "fr=anjd&232; Max-Age=7776000; path=/; domain=.example.com; secure; httponly",
118116
"header2":"value2",
119117
"header3":"value3"]
120-
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "http://example.com")!)
118+
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "https://example.com")!)
121119
XCTAssertEqual(cookies.count, 1)
122120
XCTAssertEqual(cookies[0].name, "fr")
123121
XCTAssertEqual(cookies[0].value, "anjd&232")
@@ -134,19 +132,20 @@ class TestHTTPCookie: XCTestCase {
134132
"Set-Cookie": "fr=a&2@#; Max-Age=1186000; path=/; domain=.example.com; secure, xd=plm!@#;path=/;domain=.example2.com",
135133
"header2":"value2",
136134
"header3":"value3"]
137-
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "http://example.com")!)
135+
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "https://example.com")!)
138136
XCTAssertEqual(cookies.count, 2)
139137
XCTAssertTrue(cookies[0].isSecure)
140138
XCTAssertFalse(cookies[1].isSecure)
141139
}
142140

143141
func test_cookiesWithResponseHeaderNoDomain() {
144142
let header = ["header1":"value1",
145-
"Set-Cookie": "fr=anjd&232; expires=Wed, 21 Sep 2016 05:33:00 GMT; Max-Age=7776000; path=/; secure; httponly",
143+
"Set-Cookie": "fr=anjd&232; expires=Wed, 21 Sep 2016 05:33:00 GMT; path=/; secure; httponly",
146144
"header2":"value2",
147145
"header3":"value3"]
148-
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "http://example.com")!)
149-
XCTAssertEqual(cookies[0].domain, "http://example.com")
146+
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "https://example.com")!)
147+
XCTAssertEqual(cookies[0].version, 0)
148+
XCTAssertEqual(cookies[0].domain, "example.com")
150149
XCTAssertNotNil(cookies[0].expiresDate)
151150

152151
let formatter = DateFormatter()
@@ -165,8 +164,8 @@ class TestHTTPCookie: XCTestCase {
165164
"Set-Cookie": "fr=tx; expires=Wed, 21-Sep-2016 05:33:00 GMT; Max-Age=7776000; secure; httponly",
166165
"header2":"value2",
167166
"header3":"value3"]
168-
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "http://example.com")!)
169-
XCTAssertEqual(cookies[0].domain, "http://example.com")
167+
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, for: URL(string: "https://example.com")!)
168+
XCTAssertEqual(cookies[0].domain, "example.com")
170169
XCTAssertEqual(cookies[0].path, "/")
171170
}
172171
}

0 commit comments

Comments
 (0)