blob: 3729650292756f09778923ea1727c478e4c0a5d2 [file] [log] [blame]
[email protected]ebfe3172012-07-12 12:21:411// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string>
6
7#include "net/cookies/parsed_cookie.h"
8#include "testing/gtest/include/gtest/gtest.h"
9
10namespace net {
11
12namespace {
13
14class ParsedCookieTest : public testing::Test { };
15
16} // namespace
17
18TEST(ParsedCookieTest, TestBasic) {
19 ParsedCookie pc("a=b");
20 EXPECT_TRUE(pc.IsValid());
21 EXPECT_FALSE(pc.IsSecure());
22 EXPECT_EQ("a", pc.Name());
23 EXPECT_EQ("b", pc.Value());
24}
25
26TEST(ParsedCookieTest, TestQuoted) {
27 // These are some quoting cases which the major browsers all
28 // handle differently. I've tested Internet Explorer 6, Opera 9.6,
29 // Firefox 3, and Safari Windows 3.2.1. We originally tried to match
30 // Firefox closely, however we now match Internet Explorer and Safari.
31 const char* values[] = {
32 // Trailing whitespace after a quoted value. The whitespace after
33 // the quote is stripped in all browsers.
34 "\"zzz \" ", "\"zzz \"",
35 // Handling a quoted value with a ';', like FOO="zz;pp" ;
36 // IE and Safari: "zz;
37 // Firefox and Opera: "zz;pp"
38 "\"zz;pp\" ;", "\"zz",
39 // Handling a value with multiple quoted parts, like FOO="zzz " "ppp" ;
40 // IE and Safari: "zzz " "ppp";
41 // Firefox: "zzz ";
42 // Opera: <rejects cookie>
43 "\"zzz \" \"ppp\" ", "\"zzz \" \"ppp\"",
44 // A quote in a value that didn't start quoted. like FOO=A"B ;
45 // IE, Safari, and Firefox: A"B;
46 // Opera: <rejects cookie>
47 "A\"B", "A\"B",
48 };
49
50 for (size_t i = 0; i < arraysize(values); i += 2) {
51 std::string input(values[i]);
52 std::string expected(values[i + 1]);
53
54 ParsedCookie pc("aBc=" + input + " ; path=\"/\" ; httponly ");
55 EXPECT_TRUE(pc.IsValid());
56 EXPECT_FALSE(pc.IsSecure());
57 EXPECT_TRUE(pc.IsHttpOnly());
58 EXPECT_TRUE(pc.HasPath());
59 EXPECT_EQ("aBc", pc.Name());
60 EXPECT_EQ(expected, pc.Value());
61
62 // If a path was quoted, the path attribute keeps the quotes. This will
63 // make the cookie effectively useless, but path parameters aren't supposed
64 // to be quoted. Bug 1261605.
65 EXPECT_EQ("\"/\"", pc.Path());
66 }
67}
68
69TEST(ParsedCookieTest, TestNameless) {
70 ParsedCookie pc("BLAHHH; path=/; secure;");
71 EXPECT_TRUE(pc.IsValid());
72 EXPECT_TRUE(pc.IsSecure());
73 EXPECT_TRUE(pc.HasPath());
74 EXPECT_EQ("/", pc.Path());
75 EXPECT_EQ("", pc.Name());
76 EXPECT_EQ("BLAHHH", pc.Value());
77}
78
79TEST(ParsedCookieTest, TestAttributeCase) {
80 ParsedCookie pc("BLAHHH; Path=/; sECuRe; httpONLY");
81 EXPECT_TRUE(pc.IsValid());
82 EXPECT_TRUE(pc.IsSecure());
83 EXPECT_TRUE(pc.IsHttpOnly());
84 EXPECT_TRUE(pc.HasPath());
85 EXPECT_EQ("/", pc.Path());
86 EXPECT_EQ("", pc.Name());
87 EXPECT_EQ("BLAHHH", pc.Value());
88 EXPECT_EQ(3U, pc.NumberOfAttributes());
89}
90
91TEST(ParsedCookieTest, TestDoubleQuotedNameless) {
92 ParsedCookie pc("\"BLA\\\"HHH\"; path=/; secure;");
93 EXPECT_TRUE(pc.IsValid());
94 EXPECT_TRUE(pc.IsSecure());
95 EXPECT_TRUE(pc.HasPath());
96 EXPECT_EQ("/", pc.Path());
97 EXPECT_EQ("", pc.Name());
98 EXPECT_EQ("\"BLA\\\"HHH\"", pc.Value());
99 EXPECT_EQ(2U, pc.NumberOfAttributes());
100}
101
102TEST(ParsedCookieTest, QuoteOffTheEnd) {
103 ParsedCookie pc("a=\"B");
104 EXPECT_TRUE(pc.IsValid());
105 EXPECT_EQ("a", pc.Name());
106 EXPECT_EQ("\"B", pc.Value());
107 EXPECT_EQ(0U, pc.NumberOfAttributes());
108}
109
110TEST(ParsedCookieTest, MissingName) {
111 ParsedCookie pc("=ABC");
112 EXPECT_TRUE(pc.IsValid());
113 EXPECT_EQ("", pc.Name());
114 EXPECT_EQ("ABC", pc.Value());
115 EXPECT_EQ(0U, pc.NumberOfAttributes());
116}
117
118TEST(ParsedCookieTest, MissingValue) {
119 ParsedCookie pc("ABC=; path = /wee");
120 EXPECT_TRUE(pc.IsValid());
121 EXPECT_EQ("ABC", pc.Name());
122 EXPECT_EQ("", pc.Value());
123 EXPECT_TRUE(pc.HasPath());
124 EXPECT_EQ("/wee", pc.Path());
125 EXPECT_EQ(1U, pc.NumberOfAttributes());
126}
127
128TEST(ParsedCookieTest, Whitespace) {
129 ParsedCookie pc(" A = BC ;secure;;; httponly");
130 EXPECT_TRUE(pc.IsValid());
131 EXPECT_EQ("A", pc.Name());
132 EXPECT_EQ("BC", pc.Value());
133 EXPECT_FALSE(pc.HasPath());
134 EXPECT_FALSE(pc.HasDomain());
135 EXPECT_TRUE(pc.IsSecure());
136 EXPECT_TRUE(pc.IsHttpOnly());
137 // We parse anything between ; as attributes, so we end up with two
138 // attributes with an empty string name and value.
139 EXPECT_EQ(4U, pc.NumberOfAttributes());
140}
141TEST(ParsedCookieTest, MultipleEquals) {
142 ParsedCookie pc(" A=== BC ;secure;;; httponly");
143 EXPECT_TRUE(pc.IsValid());
144 EXPECT_EQ("A", pc.Name());
145 EXPECT_EQ("== BC", pc.Value());
146 EXPECT_FALSE(pc.HasPath());
147 EXPECT_FALSE(pc.HasDomain());
148 EXPECT_TRUE(pc.IsSecure());
149 EXPECT_TRUE(pc.IsHttpOnly());
150 EXPECT_EQ(4U, pc.NumberOfAttributes());
151}
152
[email protected]ebfe3172012-07-12 12:21:41153TEST(ParsedCookieTest, QuotedTrailingWhitespace) {
154 ParsedCookie pc("ANCUUID=\"zohNumRKgI0oxyhSsV3Z7D\" ; "
155 "expires=Sun, 18-Apr-2027 21:06:29 GMT ; "
156 "path=/ ; ");
157 EXPECT_TRUE(pc.IsValid());
158 EXPECT_EQ("ANCUUID", pc.Name());
159 // Stripping whitespace after the quotes matches all other major browsers.
160 EXPECT_EQ("\"zohNumRKgI0oxyhSsV3Z7D\"", pc.Value());
161 EXPECT_TRUE(pc.HasExpires());
162 EXPECT_TRUE(pc.HasPath());
163 EXPECT_EQ("/", pc.Path());
164 EXPECT_EQ(2U, pc.NumberOfAttributes());
165}
166
167TEST(ParsedCookieTest, TrailingWhitespace) {
168 ParsedCookie pc("ANCUUID=zohNumRKgI0oxyhSsV3Z7D ; "
169 "expires=Sun, 18-Apr-2027 21:06:29 GMT ; "
170 "path=/ ; ");
171 EXPECT_TRUE(pc.IsValid());
172 EXPECT_EQ("ANCUUID", pc.Name());
173 EXPECT_EQ("zohNumRKgI0oxyhSsV3Z7D", pc.Value());
174 EXPECT_TRUE(pc.HasExpires());
175 EXPECT_TRUE(pc.HasPath());
176 EXPECT_EQ("/", pc.Path());
177 EXPECT_EQ(2U, pc.NumberOfAttributes());
178}
179
180TEST(ParsedCookieTest, TooManyPairs) {
181 std::string blankpairs;
182 blankpairs.resize(ParsedCookie::kMaxPairs - 1, ';');
183
184 ParsedCookie pc1(blankpairs + "secure");
185 EXPECT_TRUE(pc1.IsValid());
186 EXPECT_TRUE(pc1.IsSecure());
187
188 ParsedCookie pc2(blankpairs + ";secure");
189 EXPECT_TRUE(pc2.IsValid());
190 EXPECT_FALSE(pc2.IsSecure());
191}
192
193// TODO(erikwright): some better test cases for invalid cookies.
194TEST(ParsedCookieTest, InvalidWhitespace) {
195 ParsedCookie pc(" ");
196 EXPECT_FALSE(pc.IsValid());
197}
198
199TEST(ParsedCookieTest, InvalidTooLong) {
200 std::string maxstr;
201 maxstr.resize(ParsedCookie::kMaxCookieSize, 'a');
202
203 ParsedCookie pc1(maxstr);
204 EXPECT_TRUE(pc1.IsValid());
205
206 ParsedCookie pc2(maxstr + "A");
207 EXPECT_FALSE(pc2.IsValid());
208}
209
210TEST(ParsedCookieTest, InvalidEmpty) {
[email protected]69d7f892013-04-09 06:41:12211 ParsedCookie pc("");
[email protected]ebfe3172012-07-12 12:21:41212 EXPECT_FALSE(pc.IsValid());
213}
214
215TEST(ParsedCookieTest, EmbeddedTerminator) {
216 ParsedCookie pc1("AAA=BB\0ZYX");
217 ParsedCookie pc2("AAA=BB\rZYX");
218 ParsedCookie pc3("AAA=BB\nZYX");
219 EXPECT_TRUE(pc1.IsValid());
220 EXPECT_EQ("AAA", pc1.Name());
221 EXPECT_EQ("BB", pc1.Value());
222 EXPECT_TRUE(pc2.IsValid());
223 EXPECT_EQ("AAA", pc2.Name());
224 EXPECT_EQ("BB", pc2.Value());
225 EXPECT_TRUE(pc3.IsValid());
226 EXPECT_EQ("AAA", pc3.Name());
227 EXPECT_EQ("BB", pc3.Value());
228}
229
230TEST(ParsedCookieTest, ParseTokensAndValues) {
231 EXPECT_EQ("hello",
232 ParsedCookie::ParseTokenString("hello\nworld"));
233 EXPECT_EQ("fs!!@",
234 ParsedCookie::ParseTokenString("fs!!@;helloworld"));
235 EXPECT_EQ("hello world\tgood",
236 ParsedCookie::ParseTokenString("hello world\tgood\rbye"));
237 EXPECT_EQ("A",
238 ParsedCookie::ParseTokenString("A=B=C;D=E"));
239 EXPECT_EQ("hello",
240 ParsedCookie::ParseValueString("hello\nworld"));
241 EXPECT_EQ("fs!!@",
242 ParsedCookie::ParseValueString("fs!!@;helloworld"));
243 EXPECT_EQ("hello world\tgood",
244 ParsedCookie::ParseValueString("hello world\tgood\rbye"));
245 EXPECT_EQ("A=B=C",
246 ParsedCookie::ParseValueString("A=B=C;D=E"));
247}
248
[email protected]64527a52012-08-02 13:37:41249TEST(ParsedCookieTest, SerializeCookieLine) {
250 const char input[] = "ANCUUID=zohNumRKgI0oxyhSsV3Z7D ; "
251 "expires=Sun, 18-Apr-2027 21:06:29 GMT ; "
252 "path=/ ; ";
253 const char output[] = "ANCUUID=zohNumRKgI0oxyhSsV3Z7D; "
254 "expires=Sun, 18-Apr-2027 21:06:29 GMT; "
255 "path=/";
256 ParsedCookie pc(input);
257 EXPECT_EQ(output, pc.ToCookieLine());
258}
259
260
261TEST(ParsedCookieTest, SetNameAndValue) {
[email protected]69d7f892013-04-09 06:41:12262 ParsedCookie empty("");
[email protected]64527a52012-08-02 13:37:41263 EXPECT_FALSE(empty.IsValid());
264 EXPECT_FALSE(empty.SetDomain("foobar.com"));
265 EXPECT_TRUE(empty.SetName("name"));
266 EXPECT_TRUE(empty.SetValue("value"));
267 EXPECT_EQ("name=value", empty.ToCookieLine());
268 EXPECT_TRUE(empty.IsValid());
269
270 // We don't test
271 // ParsedCookie invalid("@foo=bar");
272 // EXPECT_FALSE(invalid.IsValid());
273 // here because we are slightly more tolerant to invalid cookie names and
274 // values that are set by webservers. We only enforce a correct name and
275 // value if set via SetName() and SetValue().
276
277 ParsedCookie pc("name=value");
278 EXPECT_TRUE(pc.IsValid());
279
280 // Set invalid name / value.
281 EXPECT_FALSE(pc.SetName("@foobar"));
282 EXPECT_EQ("name=value", pc.ToCookieLine());
283 EXPECT_TRUE(pc.IsValid());
284
[email protected]69d7f892013-04-09 06:41:12285 EXPECT_FALSE(pc.SetName(""));
[email protected]64527a52012-08-02 13:37:41286 EXPECT_EQ("name=value", pc.ToCookieLine());
287 EXPECT_TRUE(pc.IsValid());
288
289 EXPECT_FALSE(pc.SetValue("foo bar"));
290 EXPECT_EQ("name=value", pc.ToCookieLine());
291 EXPECT_TRUE(pc.IsValid());
292
293 EXPECT_FALSE(pc.SetValue("\"foobar"));
294 EXPECT_EQ("name=value", pc.ToCookieLine());
295 EXPECT_TRUE(pc.IsValid());
296
297 // Set valid name / value
298 EXPECT_TRUE(pc.SetName("test"));
299 EXPECT_EQ("test=value", pc.ToCookieLine());
300 EXPECT_TRUE(pc.IsValid());
301
302 EXPECT_TRUE(pc.SetValue("\"foobar\""));
303 EXPECT_EQ("test=\"foobar\"", pc.ToCookieLine());
304 EXPECT_TRUE(pc.IsValid());
305
[email protected]69d7f892013-04-09 06:41:12306 EXPECT_TRUE(pc.SetValue(""));
[email protected]64527a52012-08-02 13:37:41307 EXPECT_EQ("test=", pc.ToCookieLine());
308 EXPECT_TRUE(pc.IsValid());
309}
310
311TEST(ParsedCookieTest, SetAttributes) {
312 ParsedCookie pc("name=value");
313 EXPECT_TRUE(pc.IsValid());
314
315 // Clear an unset attribute.
[email protected]69d7f892013-04-09 06:41:12316 EXPECT_TRUE(pc.SetDomain(""));
[email protected]64527a52012-08-02 13:37:41317 EXPECT_FALSE(pc.HasDomain());
318 EXPECT_EQ("name=value", pc.ToCookieLine());
319 EXPECT_TRUE(pc.IsValid());
320
321 // Set a string containing an invalid character
322 EXPECT_FALSE(pc.SetDomain("foo;bar"));
323 EXPECT_FALSE(pc.HasDomain());
324 EXPECT_EQ("name=value", pc.ToCookieLine());
325 EXPECT_TRUE(pc.IsValid());
326
327 // Set all other attributes and check that they are appended in order.
328 EXPECT_TRUE(pc.SetDomain("domain.com"));
329 EXPECT_TRUE(pc.SetPath("/"));
[email protected]64527a52012-08-02 13:37:41330 EXPECT_TRUE(pc.SetExpires("Sun, 18-Apr-2027 21:06:29 GMT"));
331 EXPECT_TRUE(pc.SetMaxAge("12345"));
332 EXPECT_TRUE(pc.SetIsSecure(true));
333 EXPECT_TRUE(pc.SetIsHttpOnly(true));
[email protected]dedec0b2013-02-28 04:50:10334 EXPECT_EQ("name=value; domain=domain.com; path=/; "
[email protected]64527a52012-08-02 13:37:41335 "expires=Sun, 18-Apr-2027 21:06:29 GMT; max-age=12345; secure; "
336 "httponly",
337 pc.ToCookieLine());
338 EXPECT_TRUE(pc.HasDomain());
339 EXPECT_TRUE(pc.HasPath());
[email protected]64527a52012-08-02 13:37:41340 EXPECT_TRUE(pc.HasExpires());
341 EXPECT_TRUE(pc.HasMaxAge());
342 EXPECT_TRUE(pc.IsSecure());
343 EXPECT_TRUE(pc.IsHttpOnly());
344
345 // Clear one attribute from the middle.
[email protected]dedec0b2013-02-28 04:50:10346 EXPECT_TRUE(pc.SetPath("/foo"));
[email protected]64527a52012-08-02 13:37:41347 EXPECT_TRUE(pc.HasDomain());
348 EXPECT_TRUE(pc.HasPath());
[email protected]64527a52012-08-02 13:37:41349 EXPECT_TRUE(pc.HasExpires());
[email protected]64527a52012-08-02 13:37:41350 EXPECT_TRUE(pc.IsSecure());
351 EXPECT_TRUE(pc.IsHttpOnly());
[email protected]dedec0b2013-02-28 04:50:10352 EXPECT_EQ("name=value; domain=domain.com; path=/foo; "
[email protected]64527a52012-08-02 13:37:41353 "expires=Sun, 18-Apr-2027 21:06:29 GMT; max-age=12345; secure; "
354 "httponly",
355 pc.ToCookieLine());
356
357 // Clear the rest and change the name and value.
[email protected]69d7f892013-04-09 06:41:12358 EXPECT_TRUE(pc.SetDomain(""));
359 EXPECT_TRUE(pc.SetPath(""));
360 EXPECT_TRUE(pc.SetExpires(""));
361 EXPECT_TRUE(pc.SetMaxAge(""));
[email protected]64527a52012-08-02 13:37:41362 EXPECT_TRUE(pc.SetIsSecure(false));
363 EXPECT_TRUE(pc.SetIsHttpOnly(false));
364 EXPECT_TRUE(pc.SetName("name2"));
365 EXPECT_TRUE(pc.SetValue("value2"));
366 EXPECT_FALSE(pc.HasDomain());
367 EXPECT_FALSE(pc.HasPath());
[email protected]64527a52012-08-02 13:37:41368 EXPECT_FALSE(pc.HasExpires());
369 EXPECT_FALSE(pc.HasMaxAge());
370 EXPECT_FALSE(pc.IsSecure());
371 EXPECT_FALSE(pc.IsHttpOnly());
372 EXPECT_EQ("name2=value2", pc.ToCookieLine());
373}
374
[email protected]ebfe3172012-07-12 12:21:41375} // namespace net