6
6
// See http://swift.org/LICENSE.txt for license information
7
7
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
8
8
//
9
-
9
+ import Dispatch
10
10
11
11
/*!
12
12
@enum NSHTTPCookieAcceptPolicy
@@ -35,11 +35,33 @@ extension HTTPCookie {
35
35
generate cookie-related HTTP header fields.
36
36
*/
37
37
open class HTTPCookieStorage : NSObject {
38
-
39
- public override init ( ) { NSUnimplemented ( ) }
38
+
39
+ private static var sharedStorage : HTTPCookieStorage ?
40
+
41
+ private let cookieFilePath : String = NSHomeDirectory ( ) + " /.cookies "
42
+ private let workQueue : DispatchQueue = DispatchQueue ( label: " HTTPCookieStorage.workqueue " )
43
+ var allCookies : [ String : HTTPCookie ]
44
+
45
+ public override init ( ) {
46
+ allCookies = [ : ]
47
+ cookieAcceptPolicy = . always
48
+ super. init ( )
49
+ if let cookies = NSMutableDictionary ( contentsOfFile: cookieFilePath) {
50
+ var cookies0 = _SwiftValue. fetch ( cookies) as? [ String : [ String : Any ] ] ?? [ : ]
51
+ for key in cookies0. keys {
52
+ if let cookie = createCookie ( cookies0 [ key] !) {
53
+ allCookies [ key] = cookie
54
+ }
55
+ }
56
+ }
57
+ }
40
58
41
59
open var cookies : [ HTTPCookie ] ? {
42
- NSUnimplemented ( )
60
+ var theCookies : [ HTTPCookie ] ?
61
+ workQueue. sync {
62
+ theCookies = Array ( self . allCookies. values)
63
+ }
64
+ return theCookies
43
65
}
44
66
45
67
/*!
@@ -49,7 +71,14 @@ open class HTTPCookieStorage: NSObject {
49
71
@discussion Starting in OS X 10.11, each app has its own sharedHTTPCookieStorage singleton,
50
72
which will not be shared with other applications.
51
73
*/
52
- class var shared : HTTPCookieStorage { get { NSUnimplemented ( ) } }
74
+ open class var shared : HTTPCookieStorage {
75
+ get {
76
+ if sharedStorage == nil {
77
+ sharedStorage = HTTPCookieStorage ( )
78
+ }
79
+ return sharedStorage!
80
+ }
81
+ }
53
82
54
83
/*!
55
84
@method sharedCookieStorageForGroupContainerIdentifier:
@@ -70,8 +99,48 @@ open class HTTPCookieStorage: NSObject {
70
99
@discussion The cookie will override an existing cookie with the
71
100
same name, domain and path, if any.
72
101
*/
73
- open func setCookie( _ cookie: HTTPCookie ) { NSUnimplemented ( ) }
102
+ open func setCookie( _ cookie: HTTPCookie ) {
103
+ workQueue. sync {
104
+ if cookieAcceptPolicy == . never { return }
105
+
106
+ //add or replace
107
+ let key = cookie. domain + cookie. path + cookie. name
108
+ if let _ = allCookies. index ( forKey: key) {
109
+ allCookies. updateValue ( cookie, forKey: key)
110
+ } else {
111
+ allCookies [ key] = cookie
112
+ }
113
+
114
+ //remove stale cookies, these may include the one we just added
115
+ let expired = allCookies. filter { ( _, value) in value. expiresDate != nil && value. expiresDate!. timeIntervalSinceNow < 0 }
116
+ expired. forEach { ( key, _) in self . allCookies. removeValue ( forKey: key) }
117
+
118
+ persistCookies ( )
119
+ }
120
+ }
74
121
122
+ private func createCookie( _ properties: [ String : Any ] ) -> HTTPCookie ? {
123
+ var cookieProperties : [ HTTPCookiePropertyKey : Any ] = [ : ]
124
+ properties. keys. forEach {
125
+ if $0 == " Expires " {
126
+ let value = properties [ $0] as! NSNumber
127
+ cookieProperties [ HTTPCookiePropertyKey ( rawValue: $0) ] = Date ( timeIntervalSince1970: value. doubleValue)
128
+ } else {
129
+ cookieProperties [ HTTPCookiePropertyKey ( rawValue: $0) ] = properties [ $0]
130
+ }
131
+ }
132
+ return HTTPCookie ( properties: cookieProperties)
133
+ }
134
+
135
+ private func persistCookies( ) {
136
+ //persist cookies
137
+ var persistDictionary : [ String : [ String : Any ] ] = [ : ]
138
+ allCookies. filter { ( _, value) in value. expiresDate != nil && value. isSessionOnly == false && value. expiresDate!. timeIntervalSinceNow > 0 }
139
+ . forEach { persistDictionary [ $0. 0 ] = $0. 1 . simpleDictionary ( ) }
140
+ let nsdict = _SwiftValue. store ( persistDictionary) as! NSDictionary
141
+ _ = nsdict. write ( toFile: cookieFilePath, atomically: true )
142
+ }
143
+
75
144
/*!
76
145
@method deleteCookie:
77
146
@abstract Delete the specified cookie
@@ -129,6 +198,7 @@ open class HTTPCookieStorage: NSObject {
129
198
@discussion proper sorting of cookies may require extensive string conversion, which can be avoided by allowing the system to perform the sorting. This API is to be preferred over the more generic -[NSHTTPCookieStorage cookies] API, if sorting is going to be performed.
130
199
*/
131
200
open func sortedCookies( using sortOrder: [ SortDescriptor ] ) -> [ HTTPCookie ] { NSUnimplemented ( ) }
201
+
132
202
}
133
203
134
204
/*!
@@ -137,3 +207,16 @@ open class HTTPCookieStorage: NSObject {
137
207
*/
138
208
public let NSHTTPCookieManagerCookiesChangedNotification : String = " " // NSUnimplemented
139
209
210
+ extension HTTPCookie {
211
+ public func simpleDictionary( ) -> [ String : Any ] {
212
+ var properties : [ String : Any ] = [ : ]
213
+ properties [ " Name " ] = _name
214
+ properties [ " Path " ] = _path
215
+ properties [ " Value " ] = _value
216
+ properties [ " Secure " ] = _secure
217
+ properties [ " Version " ] = _version
218
+ properties [ " Expires " ] = _expiresDate!. timeIntervalSince1970
219
+ properties [ " Domain " ] = _domain
220
+ return properties
221
+ }
222
+ }
0 commit comments