@@ -19,8 +19,8 @@ import XCTest
19
19
20
20
class HTTPClientCookieTests : XCTestCase {
21
21
func testCookie( ) {
22
- let v = " key=value; PaTh=/path; DoMaIn=example.com ; eXpIRes=Wed, 21 Oct 2015 07:28:00 GMT; max-AGE=42; seCURE; HTTPOnly "
23
- guard let c = HTTPClient . Cookie ( header: v, defaultDomain: " example.com " ) else {
22
+ let v = " key=value; PaTh=/path; DoMaIn=EXampLE.CoM ; eXpIRes=Wed, 21 Oct 2015 07:28:00 GMT; max-AGE=42; seCURE; HTTPOnly "
23
+ guard let c = HTTPClient . Cookie ( header: v, defaultDomain: " exAMPle.cOm " ) else {
24
24
XCTFail ( " Failed to parse cookie " )
25
25
return
26
26
}
@@ -52,7 +52,7 @@ class HTTPClientCookieTests: XCTestCase {
52
52
53
53
func testCookieDefaults( ) {
54
54
let v = " key=value "
55
- guard let c = HTTPClient . Cookie ( header: v, defaultDomain: " example .com" ) else {
55
+ guard let c = HTTPClient . Cookie ( header: v, defaultDomain: " exAMPle .com" ) else {
56
56
XCTFail ( " Failed to parse cookie " )
57
57
return
58
58
}
@@ -94,6 +94,248 @@ class HTTPClientCookieTests: XCTestCase {
94
94
XCTAssertNil ( HTTPClient . Cookie ( header: " =value; " , defaultDomain: " exampe.org " ) )
95
95
}
96
96
97
+ func testExpires( ) {
98
+ // Empty values, and unrecognized timestamps, are ignored.
99
+ // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.1
100
+ var c = HTTPClient . Cookie ( header: " key=value; expires= " , defaultDomain: " example.com " )
101
+ XCTAssertEqual ( " key " , c? . name)
102
+ XCTAssertEqual ( " value " , c? . value)
103
+ XCTAssertNil ( c? . expires)
104
+
105
+ c = HTTPClient . Cookie ( header: " key=value; expires " , defaultDomain: " example.com " )
106
+ XCTAssertEqual ( " key " , c? . name)
107
+ XCTAssertEqual ( " value " , c? . value)
108
+ XCTAssertNil ( c? . expires)
109
+
110
+ c = HTTPClient . Cookie ( header: " key=value; expires=foo " , defaultDomain: " example.com " )
111
+ XCTAssertEqual ( " key " , c? . name)
112
+ XCTAssertEqual ( " value " , c? . value)
113
+ XCTAssertNil ( c? . expires)
114
+
115
+ c = HTTPClient . Cookie ( header: " key=value; expires=04/01/2022 " , defaultDomain: " example.com " )
116
+ XCTAssertEqual ( " key " , c? . name)
117
+ XCTAssertEqual ( " value " , c? . value)
118
+ XCTAssertNil ( c? . expires)
119
+
120
+ // Later values override earlier values, except if they are ignored.
121
+ c = HTTPClient . Cookie ( header: " key=value; expires=Sunday, 06-Nov-94 08:49:37 GMT; expires=04/01/2022 " , defaultDomain: " example.com " )
122
+ XCTAssertEqual ( " key " , c? . name)
123
+ XCTAssertEqual ( " value " , c? . value)
124
+ XCTAssertEqual ( Date ( timeIntervalSince1970: 784_111_777 ) , c? . expires)
125
+
126
+ c = HTTPClient . Cookie ( header: " key=value; expires=Sunday, 06-Nov-94 08:49:37 GMT; expires= " , defaultDomain: " example.com " )
127
+ XCTAssertEqual ( " key " , c? . name)
128
+ XCTAssertEqual ( " value " , c? . value)
129
+ XCTAssertEqual ( Date ( timeIntervalSince1970: 784_111_777 ) , c? . expires)
130
+
131
+ c = HTTPClient . Cookie ( header: " key=value; expires=Sunday, 06-Nov-94 08:49:37 GMT; expires " , defaultDomain: " example.com " )
132
+ XCTAssertEqual ( " key " , c? . name)
133
+ XCTAssertEqual ( " value " , c? . value)
134
+ XCTAssertEqual ( Date ( timeIntervalSince1970: 784_111_777 ) , c? . expires)
135
+
136
+ // For more comprehensive tests of the various timestamp formats, see: `testCookieExpiresDateParsing`.
137
+ }
138
+
139
+ func testMaxAge( ) {
140
+ // Empty values, and values containing non-digits, are ignored.
141
+ // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.2
142
+ var c = HTTPClient . Cookie ( header: " key=value; max-age= " , defaultDomain: " example.com " )
143
+ XCTAssertEqual ( " key " , c? . name)
144
+ XCTAssertEqual ( " value " , c? . value)
145
+ XCTAssertNil ( c? . maxAge)
146
+
147
+ c = HTTPClient . Cookie ( header: " key=value; max-age " , defaultDomain: " example.com " )
148
+ XCTAssertEqual ( " key " , c? . name)
149
+ XCTAssertEqual ( " value " , c? . value)
150
+ XCTAssertNil ( c? . maxAge)
151
+
152
+ c = HTTPClient . Cookie ( header: " key=value; max-age=foo " , defaultDomain: " example.com " )
153
+ XCTAssertEqual ( " key " , c? . name)
154
+ XCTAssertEqual ( " value " , c? . value)
155
+ XCTAssertNil ( c? . maxAge)
156
+
157
+ c = HTTPClient . Cookie ( header: " key=value; max-age=123foo " , defaultDomain: " example.com " )
158
+ XCTAssertEqual ( " key " , c? . name)
159
+ XCTAssertEqual ( " value " , c? . value)
160
+ XCTAssertNil ( c? . maxAge)
161
+
162
+ // Later values override earlier values, except if they are ignored.
163
+ c = HTTPClient . Cookie ( header: " key=value; max-age=123; max-age=456baz " , defaultDomain: " example.com " )
164
+ XCTAssertEqual ( " key " , c? . name)
165
+ XCTAssertEqual ( " value " , c? . value)
166
+ XCTAssertEqual ( 123 , c? . maxAge)
167
+
168
+ c = HTTPClient . Cookie ( header: " key=value; max-age=-123; max-age= " , defaultDomain: " example.com " )
169
+ XCTAssertEqual ( " key " , c? . name)
170
+ XCTAssertEqual ( " value " , c? . value)
171
+ XCTAssertEqual ( - 123 , c? . maxAge)
172
+
173
+ c = HTTPClient . Cookie ( header: " key=value; max-age=123; max-age " , defaultDomain: " example.com " )
174
+ XCTAssertEqual ( " key " , c? . name)
175
+ XCTAssertEqual ( " value " , c? . value)
176
+ XCTAssertEqual ( 123 , c? . maxAge)
177
+ }
178
+
179
+ func testDomain( ) {
180
+ // Empty domains should be ignored.
181
+ // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3
182
+ var c = HTTPClient . Cookie ( header: " key=value; domain= " , defaultDomain: " example.com " )
183
+ XCTAssertEqual ( " key " , c? . name)
184
+ XCTAssertEqual ( " value " , c? . value)
185
+ XCTAssertEqual ( " example.com " , c? . domain)
186
+
187
+ c = HTTPClient . Cookie ( header: " key=value; domain " , defaultDomain: " example.com " )
188
+ XCTAssertEqual ( " key " , c? . name)
189
+ XCTAssertEqual ( " value " , c? . value)
190
+ XCTAssertEqual ( " example.com " , c? . domain)
191
+
192
+ // A single leading dot is stripped.
193
+ c = HTTPClient . Cookie ( header: " key=value; domain=.foo " , defaultDomain: " example.com " )
194
+ XCTAssertEqual ( " key " , c? . name)
195
+ XCTAssertEqual ( " value " , c? . value)
196
+ XCTAssertEqual ( " foo " , c? . domain)
197
+
198
+ c = HTTPClient . Cookie ( header: " key=value; domain=..foo " , defaultDomain: " example.com " )
199
+ XCTAssertEqual ( " key " , c? . name)
200
+ XCTAssertEqual ( " value " , c? . value)
201
+ XCTAssertEqual ( " .foo " , c? . domain)
202
+
203
+ // RFC-6562 checks for empty values before stipping the dot (resulting in an empty domain),
204
+ // but later, empty domains are placed by the canonicalized request host.
205
+ // We use the default domain as the request host.
206
+ c = HTTPClient . Cookie ( header: " key=value; domain=. " , defaultDomain: " example.com " )
207
+ XCTAssertEqual ( " key " , c? . name)
208
+ XCTAssertEqual ( " value " , c? . value)
209
+ XCTAssertEqual ( " example.com " , c? . domain)
210
+
211
+ // Later values override earlier values, except if they are ignored.
212
+ c = HTTPClient . Cookie ( header: " key=value; domain=foo; domain=bar " , defaultDomain: " example.com " )
213
+ XCTAssertEqual ( " key " , c? . name)
214
+ XCTAssertEqual ( " value " , c? . value)
215
+ XCTAssertEqual ( " bar " , c? . domain)
216
+
217
+ c = HTTPClient . Cookie ( header: " key=value; domain=foo; domain= " , defaultDomain: " example.com " )
218
+ XCTAssertEqual ( " key " , c? . name)
219
+ XCTAssertEqual ( " value " , c? . value)
220
+ XCTAssertEqual ( " foo " , c? . domain)
221
+
222
+ c = HTTPClient . Cookie ( header: " key=value; domain=foo; domain " , defaultDomain: " example.com " )
223
+ XCTAssertEqual ( " key " , c? . name)
224
+ XCTAssertEqual ( " value " , c? . value)
225
+ XCTAssertEqual ( " foo " , c? . domain)
226
+
227
+ c = HTTPClient . Cookie ( header: " key=value; domain=foo; domain=. " , defaultDomain: " example.com " )
228
+ XCTAssertEqual ( " key " , c? . name)
229
+ XCTAssertEqual ( " value " , c? . value)
230
+ XCTAssertEqual ( " example.com " , c? . domain)
231
+
232
+ // The domain (including the defaultDomain parameter) should be normalized to lowercase.
233
+ c = HTTPClient . Cookie ( header: " key=value; domain=FOO; domain " , defaultDomain: " example.com " )
234
+ XCTAssertEqual ( " key " , c? . name)
235
+ XCTAssertEqual ( " value " , c? . value)
236
+ XCTAssertEqual ( " foo " , c? . domain)
237
+
238
+ c = HTTPClient . Cookie ( header: " key=value; domain=; domain " , defaultDomain: " EXAMPLE.com " )
239
+ XCTAssertEqual ( " key " , c? . name)
240
+ XCTAssertEqual ( " value " , c? . value)
241
+ XCTAssertEqual ( " example.com " , c? . domain)
242
+ }
243
+
244
+ func testPath( ) {
245
+ // An empty path, or path which does not begin with a "/", is considered the default path.
246
+ // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.4
247
+ var c = HTTPClient . Cookie ( header: " key=value; path= " , defaultDomain: " example.com " )
248
+ XCTAssertEqual ( " key " , c? . name)
249
+ XCTAssertEqual ( " value " , c? . value)
250
+ XCTAssertEqual ( " / " , c? . path)
251
+
252
+ c = HTTPClient . Cookie ( header: " key=value; path " , defaultDomain: " example.com " )
253
+ XCTAssertEqual ( " key " , c? . name)
254
+ XCTAssertEqual ( " value " , c? . value)
255
+ XCTAssertEqual ( " / " , c? . path)
256
+
257
+ c = HTTPClient . Cookie ( header: " key=value; path=foo " , defaultDomain: " example.com " )
258
+ XCTAssertEqual ( " key " , c? . name)
259
+ XCTAssertEqual ( " value " , c? . value)
260
+ XCTAssertEqual ( " / " , c? . path)
261
+
262
+ // Later path values override earlier values, even if the later value is considered the default path.
263
+ c = HTTPClient . Cookie ( header: " key=value; path=/abc; path=/foo " , defaultDomain: " example.com " )
264
+ XCTAssertEqual ( " key " , c? . name)
265
+ XCTAssertEqual ( " value " , c? . value)
266
+ XCTAssertEqual ( " /foo " , c? . path)
267
+
268
+ c = HTTPClient . Cookie ( header: " key=value; path=/abc; path=foo " , defaultDomain: " example.com " )
269
+ XCTAssertEqual ( " key " , c? . name)
270
+ XCTAssertEqual ( " value " , c? . value)
271
+ XCTAssertEqual ( " / " , c? . path)
272
+
273
+ c = HTTPClient . Cookie ( header: " key=value; path=/abc; path " , defaultDomain: " example.com " )
274
+ XCTAssertEqual ( " key " , c? . name)
275
+ XCTAssertEqual ( " value " , c? . value)
276
+ XCTAssertEqual ( " / " , c? . path)
277
+ }
278
+
279
+ func testSecure( ) {
280
+ // If the cookie contains a key called "secure" (case-insensitive), the secure flag is set.
281
+ // Regardless of its value.
282
+ // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.5
283
+ var c = HTTPClient . Cookie ( header: " key=value; secure= " , defaultDomain: " example.com " )
284
+ XCTAssertEqual ( " key " , c? . name)
285
+ XCTAssertEqual ( " value " , c? . value)
286
+ XCTAssertEqual ( true , c? . secure)
287
+
288
+ c = HTTPClient . Cookie ( header: " key=value; secure " , defaultDomain: " example.com " )
289
+ XCTAssertEqual ( " key " , c? . name)
290
+ XCTAssertEqual ( " value " , c? . value)
291
+ XCTAssertEqual ( true , c? . secure)
292
+
293
+ c = HTTPClient . Cookie ( header: " key=value; secure=0 " , defaultDomain: " example.com " )
294
+ XCTAssertEqual ( " key " , c? . name)
295
+ XCTAssertEqual ( " value " , c? . value)
296
+ XCTAssertEqual ( true , c? . secure)
297
+
298
+ c = HTTPClient . Cookie ( header: " key=value; secure=false " , defaultDomain: " example.com " )
299
+ XCTAssertEqual ( " key " , c? . name)
300
+ XCTAssertEqual ( " value " , c? . value)
301
+ XCTAssertEqual ( true , c? . secure)
302
+
303
+ c = HTTPClient . Cookie ( header: " key=value; secure=no " , defaultDomain: " example.com " )
304
+ XCTAssertEqual ( " key " , c? . name)
305
+ XCTAssertEqual ( " value " , c? . value)
306
+ XCTAssertEqual ( true , c? . secure)
307
+ }
308
+
309
+ func testHttpOnly( ) {
310
+ // If the cookie contains a key called "httponly" (case-insensitive), the http-only flag is set.
311
+ // Regardless of its value.
312
+ // https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.6
313
+ var c = HTTPClient . Cookie ( header: " key=value; httponly= " , defaultDomain: " example.com " )
314
+ XCTAssertEqual ( " key " , c? . name)
315
+ XCTAssertEqual ( " value " , c? . value)
316
+ XCTAssertEqual ( true , c? . httpOnly)
317
+
318
+ c = HTTPClient . Cookie ( header: " key=value; httponly " , defaultDomain: " example.com " )
319
+ XCTAssertEqual ( " key " , c? . name)
320
+ XCTAssertEqual ( " value " , c? . value)
321
+ XCTAssertEqual ( true , c? . httpOnly)
322
+
323
+ c = HTTPClient . Cookie ( header: " key=value; httponly=0 " , defaultDomain: " example.com " )
324
+ XCTAssertEqual ( " key " , c? . name)
325
+ XCTAssertEqual ( " value " , c? . value)
326
+ XCTAssertEqual ( true , c? . httpOnly)
327
+
328
+ c = HTTPClient . Cookie ( header: " key=value; httponly=false " , defaultDomain: " example.com " )
329
+ XCTAssertEqual ( " key " , c? . name)
330
+ XCTAssertEqual ( " value " , c? . value)
331
+ XCTAssertEqual ( true , c? . httpOnly)
332
+
333
+ c = HTTPClient . Cookie ( header: " key=value; httponly=no " , defaultDomain: " example.com " )
334
+ XCTAssertEqual ( " key " , c? . name)
335
+ XCTAssertEqual ( " value " , c? . value)
336
+ XCTAssertEqual ( true , c? . httpOnly)
337
+ }
338
+
97
339
func testCookieExpiresDateParsing( ) {
98
340
let domain = " example.org "
99
341
0 commit comments