@@ -10,6 +10,7 @@ import let MacroCore.console
10
10
import class http. IncomingMessage
11
11
import class http. ServerResponse
12
12
13
+
13
14
// "Set-Cookie:" Name "=" Value *( ";" Attribute)
14
15
// "Cookie:" Name "=" Value *( ";" Name "=" Value)
15
16
//
@@ -21,11 +22,12 @@ import class http.ServerResponse
21
22
/// Module and object at the same time
22
23
///
23
24
/// Usage:
24
- ///
25
- /// let cookies = Cookies(req, res)
26
- ///
27
- /// cookies.set("theAnswer", "42") // set a cookie
28
- /// if let answer = cookies.get("theAnswer") // get a cookie
25
+ /// ```swift
26
+ /// let cookies = Cookies(req, res)
27
+ ///
28
+ /// cookies.set("theAnswer", "42") // set a cookie
29
+ /// if let answer = cookies.get("theAnswer") // get a cookie
30
+ /// ```
29
31
///
30
32
public struct Cookies {
31
33
@@ -37,24 +39,33 @@ public struct Cookies {
37
39
self . res = res
38
40
39
41
// request values we care about
40
- self . cookies = req. extractStringCookieDictionary ( )
42
+ self . cookies = req. extractStringCookieDictionary ( )
41
43
}
42
44
43
45
44
46
// get/set funcs
45
47
48
+ @inlinable
46
49
public func get( _ name: String ) -> String ? {
47
50
return cookies [ name]
48
51
}
49
52
53
+ @inlinable
50
54
public func set( cookie c: Cookie ) {
51
- guard res != nil else {
55
+ guard let res = res else {
52
56
console. warn ( " attempt to set cookie, but got no response object! " )
53
57
return
54
58
}
55
- res!. setHeader ( " Set-Cookie " , c. description)
59
+ res. setHeader ( " Set-Cookie " , c. httpHeaderValue)
60
+ }
61
+
62
+ @inlinable
63
+ public func set( _ cookie: Cookie ) {
64
+ // TODO: convenience, deprecate one
65
+ set ( cookie: cookie)
56
66
}
57
67
68
+ @inlinable
58
69
public func set( _ name: String , _ value: String ,
59
70
path : String ? = " / " ,
60
71
httpOnly : Bool = true ,
@@ -73,12 +84,14 @@ public struct Cookies {
73
84
set ( cookie: cookie)
74
85
}
75
86
87
+ @inlinable
76
88
public func reset( _ name: String ) {
77
89
set ( cookie: Cookie ( name: name, maxAge: 0 ) )
78
90
}
79
91
80
92
// subscript
81
93
94
+ @inlinable
82
95
public subscript( name : String ) -> String ? {
83
96
set {
84
97
if let newValue = newValue {
@@ -88,13 +101,12 @@ public struct Cookies {
88
101
console. error ( " attempt to set nil-value cookie: \( name) , ignoring. " )
89
102
}
90
103
}
91
- get {
92
- return get ( name)
93
- }
104
+ get { return get ( name) }
94
105
}
95
106
}
96
107
97
108
extension Cookies : CustomStringConvertible {
109
+
98
110
public var description : String {
99
111
var ms = " <Cookies: "
100
112
if cookies. isEmpty {
@@ -122,13 +134,17 @@ extension Cookies: CustomStringConvertible {
122
134
}
123
135
}
124
136
137
+ // Expose the type under the "cookies" name for naming compat.
125
138
public let cookies = Cookies . self
126
139
127
140
// MARK: - Internals
128
141
142
+ // TBD(2025-08-26): The new shared Foundation might have a proper Cookie parser?
143
+
129
144
import struct Foundation. Date
130
145
131
146
public struct Cookie {
147
+
132
148
public let name : String
133
149
public var value : String
134
150
public var path : String ?
@@ -263,8 +279,9 @@ extension String {
263
279
}
264
280
}
265
281
282
+ /// "Cookie: a=10; b=20" => [ "a=10", "b=20" ]
266
283
private func splitCookieFields( headerValue v: String ) -> [ String ] {
267
- return v. splitAndTrim ( splitchar: 59 ) // semicolon
284
+ return v. splitAndTrim ( splitchar: 59 ) // semicolon (multiple cookies in line)
268
285
}
269
286
270
287
private extension IncomingMessage {
0 commit comments