summaryrefslogtreecommitdiffabout
path: root/src
Unidiff
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-rw-r--r--src/cookies.cc7
1 files changed, 5 insertions, 2 deletions
diff --git a/src/cookies.cc b/src/cookies.cc
index 40a0c8b..1ee4f7c 100644
--- a/src/cookies.cc
+++ b/src/cookies.cc
@@ -1,242 +1,245 @@
1#include "kingate/cookies.h" 1#include "kingate/cookies.h"
2#include "kingate/util.h" 2#include "kingate/util.h"
3#include "kingate/exception.h" 3#include "kingate/exception.h"
4 4
5namespace kingate { 5namespace kingate {
6 6
7 /* 7 /*
8 * RFC 2109: 8 * RFC 2109:
9 * av-pairs = av-pair *(";" av-pair) 9 * av-pairs = av-pair *(";" av-pair)
10 * av-pair = attr ["=" value] ; optional value 10 * av-pair = attr ["=" value] ; optional value
11 * attr = token 11 * attr = token
12 * value = word 12 * value = word
13 * word = token | quoted-string 13 * word = token | quoted-string
14 */ 14 */
15 15
16 /* RFC 2109: 16 /* RFC 2109:
17 * 17 *
18 * The origin server effectively ends a session by sending the client a 18 * The origin server effectively ends a session by sending the client a
19 * Set-Cookie header with Max-Age=0. 19 * Set-Cookie header with Max-Age=0.
20 * 20 *
21 * An origin server may include multiple Set-Cookie headers in a response. 21 * An origin server may include multiple Set-Cookie headers in a response.
22 * Note that an intervening gateway could fold multiple such headers into a 22 * Note that an intervening gateway could fold multiple such headers into a
23 * single header. 23 * single header.
24 * 24 *
25 * 25 *
26 * set-cookie = "Set-Cookie:" cookies 26 * set-cookie = "Set-Cookie:" cookies
27 * cookies = 1#cookie 27 * cookies = 1#cookie
28 * cookie = NAME "=" VALUE *(";" cookie-av) 28 * cookie = NAME "=" VALUE *(";" cookie-av)
29 * NAME = attr 29 * NAME = attr
30 * VALUE = value 30 * VALUE = value
31 * cookie-av = "Comment" "=" value 31 * cookie-av = "Comment" "=" value
32 * | "Domain" "=" value 32 * | "Domain" "=" value
33 * | "Max-Age" "=" value 33 * | "Max-Age" "=" value
34 * | "Path" "=" value 34 * | "Path" "=" value
35 * | "Secure" 35 * | "Secure"
36 * | "Version" "=" 1*DIGIT 36 * | "Version" "=" 1*DIGIT
37 * 37 *
38 * 38 *
39 * The origin server should send the following additional HTTP/1.1 39 * The origin server should send the following additional HTTP/1.1
40 * response headers, depending on circumstances: 40 * response headers, depending on circumstances:
41 * 41 *
42 * * To suppress caching of the Set-Cookie header: Cache-control: no- 42 * * To suppress caching of the Set-Cookie header: Cache-control: no-
43 * cache="set-cookie". 43 * cache="set-cookie".
44 * 44 *
45 * and one of the following: 45 * and one of the following:
46 * 46 *
47 * * To suppress caching of a private document in shared caches: Cache- 47 * * To suppress caching of a private document in shared caches: Cache-
48 * control: private. 48 * control: private.
49 * 49 *
50 * * To allow caching of a document and require that it be validated 50 * * To allow caching of a document and require that it be validated
51 * before returning it to the client: Cache-control: must-revalidate. 51 * before returning it to the client: Cache-control: must-revalidate.
52 * 52 *
53 * * To allow caching of a document, but to require that proxy caches 53 * * To allow caching of a document, but to require that proxy caches
54 * (not user agent caches) validate it before returning it to the 54 * (not user agent caches) validate it before returning it to the
55 * client: Cache-control: proxy-revalidate. 55 * client: Cache-control: proxy-revalidate.
56 * 56 *
57 * * To allow caching of a document and request that it be validated 57 * * To allow caching of a document and request that it be validated
58 * before returning it to the client (by "pre-expiring" it): 58 * before returning it to the client (by "pre-expiring" it):
59 * Cache-control: max-age=0. Not all caches will revalidate the 59 * Cache-control: max-age=0. Not all caches will revalidate the
60 * document in every case. 60 * document in every case.
61 * 61 *
62 * HTTP/1.1 servers must send Expires: old-date (where old-date is a 62 * HTTP/1.1 servers must send Expires: old-date (where old-date is a
63 * date long in the past) on responses containing Set-Cookie response 63 * date long in the past) on responses containing Set-Cookie response
64 * headers unless they know for certain (by out of band means) that 64 * headers unless they know for certain (by out of band means) that
65 * there are no downsteam HTTP/1.0 proxies. HTTP/1.1 servers may send 65 * there are no downsteam HTTP/1.0 proxies. HTTP/1.1 servers may send
66 * other Cache-Control directives that permit caching by HTTP/1.1 66 * other Cache-Control directives that permit caching by HTTP/1.1
67 * proxies in addition to the Expires: old-date directive; the Cache- 67 * proxies in addition to the Expires: old-date directive; the Cache-
68 * Control directive will override the Expires: old-date for HTTP/1.1 68 * Control directive will override the Expires: old-date for HTTP/1.1
69 * proxies. 69 * proxies.
70 * 70 *
71 */ 71 */
72 72
73 void cookie::_set_string(const string& p,const string& v) { 73 void cookie::_set_string(const string& p,const string& v) {
74 (*this)[p]=v; 74 (*this)[p]=v;
75 } 75 }
76 76
77 void cookie::set_comment(const string& c) { 77 void cookie::set_comment(const string& c) {
78 _set_string("comment",c); 78 _set_string("comment",c);
79 } 79 }
80 void cookie::set_domain(const string& d) { 80 void cookie::set_domain(const string& d) {
81 _set_string("domain",d); 81 _set_string("domain",d);
82 } 82 }
83 void cookie::set_max_age(const string& ma) { 83 void cookie::set_max_age(const string& ma) {
84 _set_string("max-age",ma); 84 _set_string("max-age",ma);
85 } 85 }
86 void cookie::set_path(const string& p) { 86 void cookie::set_path(const string& p) {
87 _set_string("path",p); 87 _set_string("path",p);
88 } 88 }
89 void cookie::set_secure(bool s) { 89 void cookie::set_secure(bool s) {
90 if(s) 90 if(s)
91 _set_string("secure",""); 91 _set_string("secure","");
92 else 92 else
93 erase("secure"); 93 erase("secure");
94 } 94 }
95 95
96 void cookie::set_expires(const string& e) { 96 void cookie::set_expires(const string& e) {
97 (*this)["expires"] = e; 97 (*this)["expires"] = e;
98 } 98 }
99 99
100 const string& cookie::_get_string(const string& s) const { 100 const string& cookie::_get_string(const string& s) const {
101 const_iterator i = find(s); 101 const_iterator i = find(s);
102 if(i==end()) 102 if(i==end())
103 throw exception_notfound(CODEPOINT,"No parameter set"); 103 throw exception_notfound(CODEPOINT,"No parameter set");
104 return i->second; 104 return i->second;
105 } 105 }
106 106
107 const string& cookie::get_comment() const { 107 const string& cookie::get_comment() const {
108 return _get_string("comment"); 108 return _get_string("comment");
109 } 109 }
110 const string& cookie::get_domain() const { 110 const string& cookie::get_domain() const {
111 return _get_string("domain"); 111 return _get_string("domain");
112 } 112 }
113 const string& cookie::get_max_age() const { 113 const string& cookie::get_max_age() const {
114 return _get_string("max-age"); 114 return _get_string("max-age");
115 } 115 }
116 const string& cookie::get_path() const { 116 const string& cookie::get_path() const {
117 return _get_string("path"); 117 return _get_string("path");
118 } 118 }
119 bool cookie::get_secure() const { 119 bool cookie::get_secure() const {
120 return find("secure")!=end(); 120 return find("secure")!=end();
121 } 121 }
122 122
123 const string& cookie::get_expires() const { 123 const string& cookie::get_expires() const {
124 return _get_string("expires"); 124 return _get_string("expires");
125 } 125 }
126 126
127 bool cookie::has_comment() const { 127 bool cookie::has_comment() const {
128 return find("comment")!=end(); 128 return find("comment")!=end();
129 } 129 }
130 bool cookie::has_domain() const { 130 bool cookie::has_domain() const {
131 return find("domain")!=end(); 131 return find("domain")!=end();
132 } 132 }
133 bool cookie::has_max_age() const { 133 bool cookie::has_max_age() const {
134 return find("max-age")!=end(); 134 return find("max-age")!=end();
135 } 135 }
136 bool cookie::has_path() const { 136 bool cookie::has_path() const {
137 return find("path")!=end(); 137 return find("path")!=end();
138 } 138 }
139 139
140 bool cookie::has_expires() const { 140 bool cookie::has_expires() const {
141 return find("expires")!=end(); 141 return find("expires")!=end();
142 } 142 }
143 143
144 void cookie::unset_comment() { 144 void cookie::unset_comment() {
145 erase("comment"); 145 erase("comment");
146 } 146 }
147 void cookie::unset_domain() { 147 void cookie::unset_domain() {
148 erase("domain"); 148 erase("domain");
149 } 149 }
150 void cookie::unset_max_age() { 150 void cookie::unset_max_age() {
151 erase("max-age"); 151 erase("max-age");
152 } 152 }
153 void cookie::unset_path() { 153 void cookie::unset_path() {
154 erase("path"); 154 erase("path");
155 } 155 }
156 156
157 void cookie::unset_expires() { 157 void cookie::unset_expires() {
158 erase("expires"); 158 erase("expires");
159 } 159 }
160 160
161 string cookie::set_cookie_header_rfc2109() const { 161 string cookie::set_cookie_header_rfc2109() const {
162 string rv = name + "=" + http_quoted_string(value); 162 string rv = name + "=" + http_quoted_string(value);
163 for(const_iterator i=begin();i!=end();++i) { 163 for(const_iterator i=begin();i!=end();++i) {
164 if(i->first=="secure") { 164 if(i->first=="secure") {
165 rv += "; secure"; 165 rv += "; secure";
166 }else{ 166 }else{
167 rv += "; "+i->first+"="+http_quote(i->second); 167 rv += "; "+i->first+"="+http_quote(i->second);
168 } 168 }
169 } 169 }
170 rv += "; Version=1"; 170 rv += "; Version=1";
171 return rv; 171 return rv;
172 } 172 }
173 173
174 string cookie::set_cookie_header() const { 174 string cookie::set_cookie_header() const {
175 string rv = name + "=" + value; 175 string rv = name + "=" + value;
176 for(const_iterator i=begin();i!=end();++i) { 176 for(const_iterator i=begin();i!=end();++i) {
177 if(i->first=="secure") { 177 if(i->first=="secure") {
178 rv += "; secure"; 178 rv += "; secure";
179 }else{ 179 }else{
180 rv += "; "+i->first+"="+i->second; 180 rv += "; "+i->first+"="+i->second;
181 } 181 }
182 } 182 }
183 return rv; 183 return rv;
184 } 184 }
185 185
186 void cookies_t::set_cookie(const cookie& c) {
187 insert(value_type(c.get_name(),c));
188 }
189
186 bool cookies_t::has_cookie(const key_type& n) const { 190 bool cookies_t::has_cookie(const key_type& n) const {
187 return find(n)!=end(); 191 return find(n)!=end();
188 } 192 }
189 193
190 const cookie& cookies_t::get_cookie(const key_type& n) const { 194 const cookie& cookies_t::get_cookie(const key_type& n) const {
191 const_iterator i=find(n); 195 const_iterator i=find(n);
192 if(i==end()) 196 if(i==end())
193 throw exception_notfound(CODEPOINT,"No cookie with such name found"); 197 throw exception_notfound(CODEPOINT,"No cookie with such name found");
194 return i->second; 198 return i->second;
195 } 199 }
196 200
197 cookie& cookies_t::get_cookie(const key_type& n) { 201 cookie& cookies_t::get_cookie(const key_type& n) {
198 iterator i=find(n); 202 iterator i=find(n);
199 if(i==end()) 203 if(i==end())
200 throw exception_notfound(CODEPOINT,"No cookie with such name found"); 204 throw exception_notfound(CODEPOINT,"No cookie with such name found");
201 return i->second; 205 return i->second;
202 } 206 }
203 207
204 void cookies_t::parse_cookies(const string& s) { 208 void cookies_t::parse_cookies(const string& s) {
205 string str = s; 209 string str = s;
206 while(!str.empty()) { 210 while(!str.empty()) {
207 string::size_type sc = str.find(';'); 211 string::size_type sc = str.find(';');
208 string s; 212 string s;
209 if(sc==string::npos) { 213 if(sc==string::npos) {
210 s = str; 214 s = str;
211 str.erase(); 215 str.erase();
212 }else{ 216 }else{
213 s = str.substr(0,sc); 217 s = str.substr(0,sc);
214 str.erase(0,sc+1); 218 str.erase(0,sc+1);
215 } 219 }
216 string::size_type nsp=s.find_first_not_of(" \t"); 220 string::size_type nsp=s.find_first_not_of(" \t");
217 if((nsp!=string::npos) && nsp) 221 if((nsp!=string::npos) && nsp)
218 s.erase(0,nsp); 222 s.erase(0,nsp);
219 string::size_type eq=s.find('='); 223 string::size_type eq=s.find('=');
220 if(eq==string::npos) 224 if(eq==string::npos)
221 continue; 225 continue;
222 string n = s.substr(0,eq); 226 string n = s.substr(0,eq);
223 s.erase(0,eq+1); 227 s.erase(0,eq+1);
224 nsp = n.find_last_not_of(" \t"); 228 nsp = n.find_last_not_of(" \t");
225 n.erase(nsp+1); 229 n.erase(nsp+1);
226 nsp = s.find_first_not_of(" \t"); 230 nsp = s.find_first_not_of(" \t");
227 string v; 231 string v;
228 if(nsp!=string::npos) 232 if(nsp!=string::npos)
229 v = s.substr(nsp); 233 v = s.substr(nsp);
230 else 234 else
231 v = s; 235 v = s;
232 nsp = v.find_last_not_of(" \t"); 236 nsp = v.find_last_not_of(" \t");
233 if(nsp==string::npos) 237 if(nsp==string::npos)
234 v.erase(); 238 v.erase();
235 else 239 else
236 v.erase(nsp+1); 240 v.erase(nsp+1);
237 cookie& c = (*this)[n]; 241 set_cookie(cookie(n,v));
238 c.set_name(n); c.set_value(v);
239 } 242 }
240 } 243 }
241 244
242} 245}