-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathh2load_Cookie.cc
190 lines (175 loc) · 6.07 KB
/
h2load_Cookie.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include <set>
#include "h2load_Cookie.h"
#include "config_schema.h"
#include "h2load_utils.h"
namespace h2load
{
std::vector<h2load::Cookie> Cookie::parse_cookie_string(const std::string& cookie_string,
const std::string& origin_authority, const std::string& origin_schema)
{
static std::set<std::string, ci_less> cookie_attributes {"Secure", "HttpOnly", "Expires", "Domain", "Path", "SameSite", "Max-Age"};
std::vector <Cookie> parsed_cookies;
bool secure_origin = (origin_schema == "https");
std::vector<std::string> tokens = tokenize_string(cookie_string, "; ");
for (auto& token : tokens)
{
std::vector<std::string> key_value_pair = tokenize_string(token, "=");
if ((cookie_attributes.count(key_value_pair[0]) == 0) && (key_value_pair.size() == 2))
{
parsed_cookies.emplace_back(h2load::Cookie());
parsed_cookies.back().origin = origin_authority;
util::inp_strlower(parsed_cookies.back().origin);
parsed_cookies.back().secure_origin = secure_origin;
parsed_cookies.back().cookie_key = key_value_pair[0];
parsed_cookies.back().cookie_value = key_value_pair[1];
parsed_cookies.back().sameSite = "Lax";
}
else if (cookie_attributes.count(key_value_pair[0]) == 1)
{
if (parsed_cookies.size() == 0)
{
continue;
}
util::inp_strlower(key_value_pair[0]);
if (key_value_pair[0] == "expires" && key_value_pair.size() == 2)
{
parsed_cookies.back().expires = key_value_pair[1];
}
else if (key_value_pair[0] == "secure" && key_value_pair.size() == 1)
{
parsed_cookies.back().secure = true;
}
else if (key_value_pair[0] == "httponly" && key_value_pair.size() == 1)
{
parsed_cookies.back().httpOnly = true;
}
else if (key_value_pair[0] == "domain" && key_value_pair.size() == 2)
{
parsed_cookies.back().domain = key_value_pair[1];
util::inp_strlower(parsed_cookies.back().domain);
}
else if (key_value_pair[0] == "path" && key_value_pair.size() == 2)
{
parsed_cookies.back().path = key_value_pair[1];
}
else if (key_value_pair[0] == "samesite" && key_value_pair.size() == 2)
{
parsed_cookies.back().sameSite = key_value_pair[1];
}
else if (key_value_pair[0] == "max-age" && key_value_pair.size() == 2)
{
parsed_cookies.back().maxAge = key_value_pair[1];
}
}
else
{
std::cerr << "invalid token in cookie string:" << key_value_pair[0] << std::endl;
}
}
return parsed_cookies;
}
bool Cookie::is_cookie_acceptable(const Cookie& cookie)
{
if (cookie.cookie_key.find("__Host-") == 0)
{
/*
If a cookie name has this prefix,
it is accepted in a Set-Cookie header only if
it is also marked with the Secure attribute,
was sent from a secure origin,
does not include a Domain attribute,
and has the Path attribute set to "/"
*/
if (!cookie.secure || !cookie.secure_origin || !cookie.domain.empty() || cookie.path != "/")
{
return false;
}
}
if (cookie.cookie_key.find("__Secure-") == 0)
{
/*
If a cookie name has this prefix,
it is accepted in a Set-Cookie header only if
it is marked with the Secure attribute and was sent from a secure origin
*/
if (!cookie.secure || !cookie.secure_origin)
{
// _Secure- check failed, this cookie is not accepted
return false;
}
}
if (cookie.sameSite == "None" && !cookie.secure)
{
// if SameSite=None then the Secure attribute must also be set
return false;
}
return true;
}
bool Cookie::is_cookie_allowed_to_be_sent(const Cookie& cookie, const std::string dest_schema,
const std::string& dest_authority,
const std::string& dest_path)
{
if (cookie.secure && dest_schema == "http")
{
return false;
}
std::string authority = dest_authority;
util::inp_strlower(authority);
if (cookie.domain.size())
{
std::string dest_host = tokenize_string(authority, ":")[0];
std::string domain = cookie.domain;
size_t pos = dest_host.rfind(domain);
if (pos == std::string::npos || ((dest_host.size() - pos) != domain.size()))
{
return false;
}
}
else // domain empty, origin exact match with no sub domain allowed
{
std::string origin = cookie.origin;
if (origin != authority)
{
return false;
}
}
if (cookie.path.size() && dest_path.size())
{
size_t pos = dest_path.find(cookie.path);
if (pos != 0)
{
return false;
}
}
if (cookie.sameSite.size() && cookie.sameSite != "None")
{
if (cookie.origin != authority)
{
return false;
}
/* not a browser, difference between Strict and Lax is not considered
else if (cookie.sameSite == "Strict" && previous URL is not same with cookie origin)
{
return false;
}
*/
}
return true;
}
std::ostream& operator<<(std::ostream& o, const Cookie& cookie)
{
o << "Cookie: { "
<< "key:" << cookie.cookie_key
<< ", value:" << cookie.cookie_value
<< ", origin:" << cookie.origin
<< ", secure_origin:" << cookie.secure_origin
<< ", expires:" << cookie.expires
<< ", secure:" << cookie.secure
<< ", httpOnly:" << cookie.httpOnly
<< ", domain:" << cookie.domain
<< ", path:" << cookie.path
<< ", sameSite:" << cookie.sameSite
<< " }";
return o;
}
}