Skip to content

Commit 7ce6805

Browse files
committed
Change cookie parsing date format, fix Optional any warnings
1 parent 2000be1 commit 7ce6805

File tree

2 files changed

+87
-68
lines changed

2 files changed

+87
-68
lines changed

Foundation/NSHTTPCookie.swift

Lines changed: 66 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -37,39 +37,42 @@ extension HTTPCookiePropertyKey {
3737

3838
/// Key for cookie value
3939
public static let value = HTTPCookiePropertyKey(rawValue: "Value")
40-
40+
4141
/// Key for cookie origin URL
4242
public static let originURL = HTTPCookiePropertyKey(rawValue: "OriginURL")
4343

4444
/// Key for cookie version
4545
public static let version = HTTPCookiePropertyKey(rawValue: "Version")
46-
46+
4747
/// Key for cookie domain
4848
public static let domain = HTTPCookiePropertyKey(rawValue: "Domain")
49-
49+
5050
/// Key for cookie path
5151
public static let path = HTTPCookiePropertyKey(rawValue: "Path")
52-
52+
5353
/// Key for cookie secure flag
5454
public static let secure = HTTPCookiePropertyKey(rawValue: "Secure")
55-
55+
5656
/// Key for cookie expiration date
5757
public static let expires = HTTPCookiePropertyKey(rawValue: "Expires")
5858

5959
/// Key for cookie comment text
6060
public static let comment = HTTPCookiePropertyKey(rawValue: "Comment")
61-
61+
6262
/// Key for cookie comment URL
6363
public static let commentURL = HTTPCookiePropertyKey(rawValue: "CommentURL")
64-
64+
6565
/// Key for cookie discard (session-only) flag
6666
public static let discard = HTTPCookiePropertyKey(rawValue: "Discard")
67-
67+
6868
/// Key for cookie maximum age (an alternate way of specifying the expiration)
6969
public static let maximumAge = HTTPCookiePropertyKey(rawValue: "Max-Age")
7070

7171
/// Key for cookie ports
7272
public static let port = HTTPCookiePropertyKey(rawValue: "Port")
73+
74+
// For Cocoa compatibility
75+
internal static let created = HTTPCookiePropertyKey(rawValue: "Created")
7376
}
7477

7578
/// `NSHTTPCookie` represents an http cookie.
@@ -94,10 +97,10 @@ open class HTTPCookie : NSObject {
9497
let _version: Int
9598
var _properties: [HTTPCookiePropertyKey : Any]
9699

97-
static let _attributes: [HTTPCookiePropertyKey] = [.name, .value, .originURL, .version,
98-
.domain, .path, .secure, .expires,
99-
.comment, .commentURL, .discard, .maximumAge,
100-
.port]
100+
static let _attributes: [HTTPCookiePropertyKey]
101+
= [.name, .value, .originURL, .version, .domain,
102+
.path, .secure, .expires, .comment, .commentURL,
103+
.discard, .maximumAge, .port]
101104

102105
/// Initialize a NSHTTPCookie object with a dictionary of parameters
103106
///
@@ -268,7 +271,7 @@ open class HTTPCookie : NSObject {
268271
version = 0
269272
}
270273
_version = version
271-
274+
272275
if let portString = properties[.port] as? String, _version == 1 {
273276
_portList = portString.characters
274277
.split(separator: ",")
@@ -286,7 +289,7 @@ open class HTTPCookie : NSObject {
286289
} else if let dateString = expiresProperty as? String {
287290
let formatter = DateFormatter()
288291
formatter.locale = Locale(identifier: "en_US_POSIX")
289-
formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss O" // per RFC 6265 '<rfc1123-date, defined in [RFC2616], Section 3.3.1>'
292+
formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss z" // per RFC 6265 '<rfc1123-date, defined in [RFC2616], Section 3.3.1>'
290293
let timeZone = TimeZone(abbreviation: "GMT")
291294
formatter.timeZone = timeZone
292295
_expiresDate = formatter.date(from: dateString)
@@ -300,8 +303,7 @@ open class HTTPCookie : NSObject {
300303
} else {
301304
_expiresDate = nil
302305
}
303-
304-
306+
305307
if let discardString = properties[.discard] as? String {
306308
_sessionOnly = discardString == "TRUE"
307309
} else {
@@ -321,23 +323,38 @@ open class HTTPCookie : NSObject {
321323
}
322324
}
323325
_HTTPOnly = false
324-
_properties = [.comment : properties[.comment],
325-
.commentURL : properties[.commentURL],
326-
HTTPCookiePropertyKey(rawValue: "Created") : Date().timeIntervalSinceReferenceDate, // Cocoa Compatibility
327-
.discard : _sessionOnly,
328-
.domain : _domain,
329-
.expires : _expiresDate,
330-
.maximumAge : properties[.maximumAge],
331-
.name : _name,
332-
.originURL : properties[.originURL],
333-
.path : _path,
334-
.port : _portList,
335-
.secure : _secure,
336-
.value : _value,
337-
.version : _version
326+
327+
328+
_properties = [
329+
.created : Date().timeIntervalSinceReferenceDate, // Cocoa Compatibility
330+
.discard : _sessionOnly,
331+
.domain : _domain,
332+
.name : _name,
333+
.path : _path,
334+
.secure : _secure,
335+
.value : _value,
336+
.version : _version
338337
]
338+
if let comment = properties[.comment] {
339+
_properties[.comment] = comment
340+
}
341+
if let commentURL = properties[.commentURL] {
342+
_properties[.commentURL] = commentURL
343+
}
344+
if let expires = properties[.expires] {
345+
_properties[.expires] = expires
346+
}
347+
if let maximumAge = properties[.maximumAge] {
348+
_properties[.maximumAge] = maximumAge
349+
}
350+
if let originURL = properties[.originURL] {
351+
_properties[.originURL] = originURL
352+
}
353+
if let _portList = _portList, _portList.count > 0 {
354+
_properties[.port] = _portList
355+
}
339356
}
340-
357+
341358
/// Return a dictionary of header fields that can be used to add the
342359
/// specified cookies to the request.
343360
///
@@ -355,7 +372,7 @@ open class HTTPCookie : NSObject {
355372
}
356373
return ["Cookie": cookieString]
357374
}
358-
375+
359376
/// Return an array of cookies parsed from the specified response header fields and URL.
360377
///
361378
/// This method will ignore irrelevant header fields so
@@ -371,7 +388,7 @@ open class HTTPCookie : NSObject {
371388
// names and values. This implementation takes care of multiple cookies in the same field, however it doesn't
372389
//support commas and semicolons in names and values(except for dates)
373390

374-
guard let cookies: String = headerFields["Set-Cookie"] else { return [] }
391+
guard let cookies: String = headerFields["Set-Cookie"] else { return [] }
375392

376393
let nameValuePairs = cookies.components(separatedBy: ";") //split the name/value and attribute/value pairs
377394
.map({$0.trim()}) //trim whitespaces
@@ -383,7 +400,7 @@ open class HTTPCookie : NSObject {
383400

384401
//mark cookie boundaries in the name-value array
385402
var cookieIndices = (0..<nameValuePairs.count).filter({nameValuePairs[$0].hasPrefix("Name")})
386-
cookieIndices.append(nameValuePairs.count)
403+
cookieIndices.append(nameValuePairs.count)
387404

388405
//bake the cookies
389406
var httpCookies: [HTTPCookie] = []
@@ -392,9 +409,9 @@ open class HTTPCookie : NSObject {
392409
httpCookies.append(aCookie)
393410
}
394411
}
395-
412+
396413
return httpCookies
397-
}
414+
}
398415

399416
//Bake a cookie
400417
private class func createHttpCookie(url: URL, pairs: ArraySlice<String>) -> HTTPCookie? {
@@ -403,20 +420,20 @@ open class HTTPCookie : NSObject {
403420
let name = pair.components(separatedBy: "=")[0]
404421
var value = pair.components(separatedBy: "\(name)=")[1] //a value can have an "="
405422
if canonicalize(name) == .expires {
406-
value = value.insertComma(at: 3) //re-insert the comma
423+
value = value.insertComma(at: 3) //re-insert the comma
407424
}
408425
properties[canonicalize(name)] = value
409426
}
410-
427+
411428
//if domain wasn't provided use the URL
412429
if properties[.domain] == nil {
413430
properties[.domain] = url.absoluteString
414431
}
415-
432+
416433
//the default Path is "/"
417434
if properties[.path] == nil {
418435
properties[.path] = "/"
419-
}
436+
}
420437

421438
return HTTPCookie(properties: properties)
422439
}
@@ -470,25 +487,25 @@ open class HTTPCookie : NSObject {
470487
open var properties: [HTTPCookiePropertyKey : Any]? {
471488
return _properties
472489
}
473-
490+
474491
/// The version of the receiver.
475492
///
476493
/// Version 0 maps to "old-style" Netscape cookies.
477494
/// Version 1 maps to RFC2965 cookies. There may be future versions.
478495
open var version: Int {
479496
return _version
480497
}
481-
498+
482499
/// The name of the receiver.
483500
open var name: String {
484501
return _name
485502
}
486-
503+
487504
/// The value of the receiver.
488505
open var value: String {
489506
return _value
490507
}
491-
508+
492509
/// Returns The expires date of the receiver.
493510
///
494511
/// The expires date is the date when the cookie should be
@@ -497,7 +514,7 @@ open class HTTPCookie : NSObject {
497514
/*@NSCopying*/ open var expiresDate: Date? {
498515
return _expiresDate
499516
}
500-
517+
501518
/// Whether the receiver is session-only.
502519
///
503520
/// `true` if this receiver should be discarded at the end of the
@@ -506,7 +523,7 @@ open class HTTPCookie : NSObject {
506523
open var isSessionOnly: Bool {
507524
return _sessionOnly
508525
}
509-
526+
510527
/// The domain of the receiver.
511528
///
512529
/// This value specifies URL domain to which the cookie
@@ -546,7 +563,7 @@ open class HTTPCookie : NSObject {
546563
open var isHTTPOnly: Bool {
547564
return _HTTPOnly
548565
}
549-
566+
550567
/// The comment of the receiver.
551568
///
552569
/// This value specifies a string which is suitable for
@@ -555,7 +572,7 @@ open class HTTPCookie : NSObject {
555572
open var comment: String? {
556573
return _comment
557574
}
558-
575+
559576
/// The comment URL of the receiver.
560577
///
561578
/// This value specifies a URL which is suitable for
@@ -564,7 +581,7 @@ open class HTTPCookie : NSObject {
564581
/*@NSCopying*/ open var commentURL: URL? {
565582
return _commentURL
566583
}
567-
584+
568585
/// The list ports to which the receiver should be sent.
569586
///
570587
/// This value specifies an NSArray of NSNumbers

TestFoundation/TestNSHTTPCookie.swift

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ class TestNSHTTPCookie: XCTestCase {
2121
return [
2222
("test_BasicConstruction", test_BasicConstruction),
2323
("test_RequestHeaderFields", test_RequestHeaderFields),
24-
("test_cookiesWithResponseHeader1cookie", test_cookiesWithResponseHeader1cookie),
25-
("test_cookiesWithResponseHeader0cookies", test_cookiesWithResponseHeader0cookies),
26-
("test_cookiesWithResponseHeader2cookies", test_cookiesWithResponseHeader2cookies),
27-
("test_cookiesWithResponseHeaderNoDomain", test_cookiesWithResponseHeaderNoDomain),
24+
("test_cookiesWithResponseHeader1cookie", test_cookiesWithResponseHeader1cookie),
25+
("test_cookiesWithResponseHeader0cookies", test_cookiesWithResponseHeader0cookies),
26+
("test_cookiesWithResponseHeader2cookies", test_cookiesWithResponseHeader2cookies),
27+
("test_cookiesWithResponseHeaderNoDomain", test_cookiesWithResponseHeaderNoDomain),
2828
("test_cookiesWithResponseHeaderNoPathNoDomain", test_cookiesWithResponseHeaderNoPathNoDomain)
2929
]
3030
}
@@ -96,11 +96,11 @@ class TestNSHTTPCookie: XCTestCase {
9696
XCTAssert(versionZeroCookieWithInvalidVersionOneProps?.isSecure == true)
9797
XCTAssert(versionZeroCookieWithInvalidVersionOneProps?.version == 0)
9898
}
99-
99+
100100
func test_RequestHeaderFields() {
101101
let noCookies: [HTTPCookie] = []
102102
XCTAssertEqual(HTTPCookie.requestHeaderFields(with: noCookies)["Cookie"], "")
103-
103+
104104
let basicCookies: [HTTPCookie] = [
105105
HTTPCookie(properties: [
106106
.name: "TestCookie1",
@@ -115,15 +115,15 @@ class TestNSHTTPCookie: XCTestCase {
115115
.originURL: URL(string: "https://apple.com")!
116116
])!,
117117
]
118-
118+
119119
let basicCookieString = HTTPCookie.requestHeaderFields(with: basicCookies)["Cookie"]
120120
XCTAssertEqual(basicCookieString, "TestCookie1=testValue1; TestCookie2=testValue2")
121121
}
122122

123123
func test_cookiesWithResponseHeader1cookie() {
124-
let header = ["header1":"value1",
125-
"Set-Cookie": "fr=anjd&232; Max-Age=7776000; path=/; domain=.example.com; secure; httponly",
126-
"header2":"value2",
124+
let header = ["header1":"value1",
125+
"Set-Cookie": "fr=anjd&232; Max-Age=7776000; path=/; domain=.example.com; secure; httponly",
126+
"header2":"value2",
127127
"header3":"value3"]
128128
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, forURL: URL(string: "http://example.com")!)
129129
XCTAssertEqual(cookies.count, 1)
@@ -138,9 +138,9 @@ class TestNSHTTPCookie: XCTestCase {
138138
}
139139

140140
func test_cookiesWithResponseHeader2cookies() {
141-
let header = ["header1":"value1",
141+
let header = ["header1":"value1",
142142
"Set-Cookie": "fr=a&2@#; Max-Age=1186000; path=/; domain=.example.com; secure, xd=plm!@#;path=/;domain=.example2.com",
143-
"header2":"value2",
143+
"header2":"value2",
144144
"header3":"value3"]
145145
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, forURL: URL(string: "http://example.com")!)
146146
XCTAssertEqual(cookies.count, 2)
@@ -149,15 +149,17 @@ class TestNSHTTPCookie: XCTestCase {
149149
}
150150

151151
func test_cookiesWithResponseHeaderNoDomain() {
152-
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",
154-
"header2":"value2",
152+
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",
154+
"header2":"value2",
155155
"header3":"value3"]
156156
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, forURL: URL(string: "http://example.com")!)
157157
XCTAssertEqual(cookies[0].domain, "http://example.com")
158+
XCTAssertNotNil(cookies[0].expiresDate)
159+
158160
let formatter = DateFormatter()
159161
formatter.locale = Locale(identifier: "en_US_POSIX")
160-
formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss O"
162+
formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss z"
161163
formatter.timeZone = TimeZone(abbreviation: "GMT")
162164
if let expiresDate = formatter.date(from: "Wed, 21 Sep 2016 05:33:00 GMT") {
163165
XCTAssertTrue(expiresDate.compare(cookies[0].expiresDate!) == .orderedSame)
@@ -167,12 +169,12 @@ class TestNSHTTPCookie: XCTestCase {
167169
}
168170

169171
func test_cookiesWithResponseHeaderNoPathNoDomain() {
170-
let header = ["header1":"value1",
172+
let header = ["header1":"value1",
171173
"Set-Cookie": "fr=tx; expires=Wed, 21-Sep-2016 05:33:00 GMT; Max-Age=7776000; secure; httponly",
172-
"header2":"value2",
174+
"header2":"value2",
173175
"header3":"value3"]
174176
let cookies = HTTPCookie.cookies(withResponseHeaderFields: header, forURL: URL(string: "http://example.com")!)
175177
XCTAssertEqual(cookies[0].domain, "http://example.com")
176-
XCTAssertEqual(cookies[0].path, "/")
178+
XCTAssertEqual(cookies[0].path, "/")
177179
}
178180
}

0 commit comments

Comments
 (0)