Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(360)

Side by Side Diff: net/http/http_response_headers_unittest.cc

Issue 448373003: parameterize http response header tests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: final formatting adjustments Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <algorithm> 5 #include <algorithm>
6 #include <limits> 6 #include <limits>
7 7
8 #include "base/basictypes.h" 8 #include "base/basictypes.h"
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/pickle.h" 10 #include "base/pickle.h"
11 #include "base/time/time.h" 11 #include "base/time/time.h"
12 #include "base/values.h" 12 #include "base/values.h"
13 #include "net/http/http_byte_range.h" 13 #include "net/http/http_byte_range.h"
14 #include "net/http/http_response_headers.h" 14 #include "net/http/http_response_headers.h"
15 #include "testing/gtest/include/gtest/gtest.h" 15 #include "testing/gtest/include/gtest/gtest.h"
16 16
17 namespace { 17 namespace {
18 18
19 struct TestData { 19 struct TestData {
20 const char* raw_headers; 20 const char* raw_headers;
21 const char* expected_headers; 21 const char* expected_headers;
22 int expected_response_code; 22 int expected_response_code;
23 net::HttpVersion expected_parsed_version; 23 net::HttpVersion expected_parsed_version;
24 net::HttpVersion expected_version; 24 net::HttpVersion expected_version;
25 }; 25 };
26 26
27 struct ContentTypeTestData {
28 const std::string raw_headers;
29 const std::string mime_type;
30 const bool has_mimetype;
31 const std::string charset;
32 const bool has_charset;
33 const std::string all_content_type;
34 };
35
36 class HttpResponseHeadersTest : public testing::Test { 27 class HttpResponseHeadersTest : public testing::Test {
37 }; 28 };
38 29
39 // Transform "normal"-looking headers (\n-separated) to the appropriate 30 // Transform "normal"-looking headers (\n-separated) to the appropriate
40 // input format for ParseRawHeaders (\0-separated). 31 // input format for ParseRawHeaders (\0-separated).
41 void HeadersToRaw(std::string* headers) { 32 void HeadersToRaw(std::string* headers) {
42 std::replace(headers->begin(), headers->end(), '\n', '\0'); 33 std::replace(headers->begin(), headers->end(), '\n', '\0');
43 if (!headers->empty()) 34 if (!headers->empty())
44 *headers += '\0'; 35 *headers += '\0';
45 } 36 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 EXPECT_TRUE( 75 EXPECT_TRUE(
85 headers()->GetStaleWhileRevalidateValue(&stale_while_revalidate_value)); 76 headers()->GetStaleWhileRevalidateValue(&stale_while_revalidate_value));
86 return stale_while_revalidate_value; 77 return stale_while_revalidate_value;
87 } 78 }
88 79
89 private: 80 private:
90 scoped_refptr<net::HttpResponseHeaders> headers_; 81 scoped_refptr<net::HttpResponseHeaders> headers_;
91 TimeDelta delta_; 82 TimeDelta delta_;
92 }; 83 };
93 84
94 void TestCommon(const TestData& test) { 85 class CommonHttpResponseHeadersTest
86 : public HttpResponseHeadersTest,
87 public ::testing::WithParamInterface<TestData> {
88 };
89
90 TEST_P(CommonHttpResponseHeadersTest, TestCommon) {
91 const TestData test = GetParam();
92
95 std::string raw_headers(test.raw_headers); 93 std::string raw_headers(test.raw_headers);
96 HeadersToRaw(&raw_headers); 94 HeadersToRaw(&raw_headers);
97 std::string expected_headers(test.expected_headers); 95 std::string expected_headers(test.expected_headers);
98 96
99 std::string headers; 97 std::string headers;
100 scoped_refptr<net::HttpResponseHeaders> parsed( 98 scoped_refptr<net::HttpResponseHeaders> parsed(
101 new net::HttpResponseHeaders(raw_headers)); 99 new net::HttpResponseHeaders(raw_headers));
102 parsed->GetNormalizedHeaders(&headers); 100 parsed->GetNormalizedHeaders(&headers);
103 101
104 // Transform to readable output format (so it's easier to see diffs). 102 // Transform to readable output format (so it's easier to see diffs).
105 std::replace(headers.begin(), headers.end(), ' ', '_'); 103 std::replace(headers.begin(), headers.end(), ' ', '_');
106 std::replace(headers.begin(), headers.end(), '\n', '\\'); 104 std::replace(headers.begin(), headers.end(), '\n', '\\');
107 std::replace(expected_headers.begin(), expected_headers.end(), ' ', '_'); 105 std::replace(expected_headers.begin(), expected_headers.end(), ' ', '_');
108 std::replace(expected_headers.begin(), expected_headers.end(), '\n', '\\'); 106 std::replace(expected_headers.begin(), expected_headers.end(), '\n', '\\');
109 107
110 EXPECT_EQ(expected_headers, headers); 108 EXPECT_EQ(expected_headers, headers);
111 109
112 EXPECT_EQ(test.expected_response_code, parsed->response_code()); 110 EXPECT_EQ(test.expected_response_code, parsed->response_code());
113 111
114 EXPECT_TRUE(test.expected_parsed_version == parsed->GetParsedHttpVersion()); 112 EXPECT_TRUE(test.expected_parsed_version == parsed->GetParsedHttpVersion());
115 EXPECT_TRUE(test.expected_version == parsed->GetHttpVersion()); 113 EXPECT_TRUE(test.expected_version == parsed->GetHttpVersion());
116 } 114 }
117 115
118 } // end namespace 116 TestData response_headers_tests[] = {
117 {
118 // Normalise whitespace.
119 119
120 // Check that we normalize headers properly.
121 TEST(HttpResponseHeadersTest, NormalizeHeadersWhitespace) {
122 TestData test = {
123 "HTTP/1.1 202 Accepted \n" 120 "HTTP/1.1 202 Accepted \n"
124 "Content-TYPE : text/html; charset=utf-8 \n" 121 "Content-TYPE : text/html; charset=utf-8 \n"
125 "Set-Cookie: a \n" 122 "Set-Cookie: a \n"
126 "Set-Cookie: b \n", 123 "Set-Cookie: b \n",
127 124
128 "HTTP/1.1 202 Accepted\n" 125 "HTTP/1.1 202 Accepted\n"
129 "Content-TYPE: text/html; charset=utf-8\n" 126 "Content-TYPE: text/html; charset=utf-8\n"
130 "Set-Cookie: a, b\n", 127 "Set-Cookie: a, b\n",
131 128
132 202, 129 202,
133 net::HttpVersion(1,1), 130 net::HttpVersion(1,1),
134 net::HttpVersion(1,1) 131 net::HttpVersion(1,1)
135 }; 132 },
136 TestCommon(test); 133 {
137 } 134 // Normalize leading whitespace.
138 135
139 // Check that we normalize headers properly (header name is invalid if starts
140 // with LWS).
141 TEST(HttpResponseHeadersTest, NormalizeHeadersLeadingWhitespace) {
142 TestData test = {
143 "HTTP/1.1 202 Accepted \n" 136 "HTTP/1.1 202 Accepted \n"
144 // Starts with space -- will be skipped as invalid. 137 // Starts with space -- will be skipped as invalid.
145 " Content-TYPE : text/html; charset=utf-8 \n" 138 " Content-TYPE : text/html; charset=utf-8 \n"
146 "Set-Cookie: a \n" 139 "Set-Cookie: a \n"
147 "Set-Cookie: b \n", 140 "Set-Cookie: b \n",
148 141
149 "HTTP/1.1 202 Accepted\n" 142 "HTTP/1.1 202 Accepted\n"
150 "Set-Cookie: a, b\n", 143 "Set-Cookie: a, b\n",
151 144
152 202, 145 202,
153 net::HttpVersion(1,1), 146 net::HttpVersion(1,1),
154 net::HttpVersion(1,1) 147 net::HttpVersion(1,1)
155 }; 148 },
156 TestCommon(test); 149 {
157 } 150 // Normalize blank headers.
158 151
159 TEST(HttpResponseHeadersTest, BlankHeaders) {
160 TestData test = {
161 "HTTP/1.1 200 OK\n" 152 "HTTP/1.1 200 OK\n"
162 "Header1 : \n" 153 "Header1 : \n"
163 "Header2: \n" 154 "Header2: \n"
164 "Header3:\n" 155 "Header3:\n"
165 "Header4\n" 156 "Header4\n"
166 "Header5 :\n", 157 "Header5 :\n",
167 158
168 "HTTP/1.1 200 OK\n" 159 "HTTP/1.1 200 OK\n"
169 "Header1: \n" 160 "Header1: \n"
170 "Header2: \n" 161 "Header2: \n"
171 "Header3: \n" 162 "Header3: \n"
172 "Header5: \n", 163 "Header5: \n",
173 164
174 200, 165 200,
175 net::HttpVersion(1,1), 166 net::HttpVersion(1,1),
176 net::HttpVersion(1,1) 167 net::HttpVersion(1,1)
177 }; 168 },
178 TestCommon(test); 169 {
179 } 170 // Don't believe the http/0.9 version if there are headers!
180 171
181 TEST(HttpResponseHeadersTest, NormalizeHeadersVersion) {
182 // Don't believe the http/0.9 version if there are headers!
183 TestData test = {
184 "hTtP/0.9 201\n" 172 "hTtP/0.9 201\n"
185 "Content-TYPE: text/html; charset=utf-8\n", 173 "Content-TYPE: text/html; charset=utf-8\n",
186 174
187 "HTTP/1.0 201 OK\n" 175 "HTTP/1.0 201 OK\n"
188 "Content-TYPE: text/html; charset=utf-8\n", 176 "Content-TYPE: text/html; charset=utf-8\n",
189 177
190 201, 178 201,
191 net::HttpVersion(0,9), 179 net::HttpVersion(0,9),
192 net::HttpVersion(1,0) 180 net::HttpVersion(1,0)
193 }; 181 },
194 TestCommon(test); 182 {
195 } 183 // Accept the HTTP/0.9 version number if there are no headers.
184 // This is how HTTP/0.9 responses get constructed from
185 // HttpNetworkTransaction.
196 186
197 TEST(HttpResponseHeadersTest, PreserveHttp09) {
198 // Accept the HTTP/0.9 version number if there are no headers.
199 // This is how HTTP/0.9 responses get constructed from HttpNetworkTransaction.
200 TestData test = {
201 "hTtP/0.9 200 OK\n", 187 "hTtP/0.9 200 OK\n",
202 188
203 "HTTP/0.9 200 OK\n", 189 "HTTP/0.9 200 OK\n",
204 190
205 200, 191 200,
206 net::HttpVersion(0,9), 192 net::HttpVersion(0,9),
207 net::HttpVersion(0,9) 193 net::HttpVersion(0,9)
208 }; 194 },
209 TestCommon(test); 195 {
210 } 196 // Add missing OK.
211 197
212 TEST(HttpResponseHeadersTest, NormalizeHeadersMissingOK) {
213 TestData test = {
214 "HTTP/1.1 201\n" 198 "HTTP/1.1 201\n"
215 "Content-TYPE: text/html; charset=utf-8\n", 199 "Content-TYPE: text/html; charset=utf-8\n",
216 200
217 "HTTP/1.1 201 OK\n" 201 "HTTP/1.1 201 OK\n"
218 "Content-TYPE: text/html; charset=utf-8\n", 202 "Content-TYPE: text/html; charset=utf-8\n",
219 203
220 201, 204 201,
221 net::HttpVersion(1,1), 205 net::HttpVersion(1,1),
222 net::HttpVersion(1,1) 206 net::HttpVersion(1,1)
223 }; 207 },
224 TestCommon(test); 208 {
225 } 209 // Normalize bad status line.
226 210
227 TEST(HttpResponseHeadersTest, NormalizeHeadersBadStatus) {
228 TestData test = {
229 "SCREWED_UP_STATUS_LINE\n" 211 "SCREWED_UP_STATUS_LINE\n"
230 "Content-TYPE: text/html; charset=utf-8\n", 212 "Content-TYPE: text/html; charset=utf-8\n",
231 213
232 "HTTP/1.0 200 OK\n" 214 "HTTP/1.0 200 OK\n"
233 "Content-TYPE: text/html; charset=utf-8\n", 215 "Content-TYPE: text/html; charset=utf-8\n",
234 216
235 200, 217 200,
236 net::HttpVersion(0,0), // Parse error 218 net::HttpVersion(0,0), // Parse error.
237 net::HttpVersion(1,0) 219 net::HttpVersion(1,0)
238 }; 220 },
239 TestCommon(test); 221 {
240 } 222 // Normalize invalid status code.
241 223
242 TEST(HttpResponseHeadersTest, NormalizeHeadersInvalidStatusCode) {
243 TestData test = {
244 "HTTP/1.1 -1 Unknown\n", 224 "HTTP/1.1 -1 Unknown\n",
245 225
246 "HTTP/1.1 200 OK\n", 226 "HTTP/1.1 200 OK\n",
247 227
248 200, 228 200,
249 net::HttpVersion(1,1), 229 net::HttpVersion(1,1),
250 net::HttpVersion(1,1) 230 net::HttpVersion(1,1)
251 }; 231 },
252 TestCommon(test); 232 {
253 } 233 // Normalize empty header.
254 234
255 TEST(HttpResponseHeadersTest, NormalizeHeadersEmpty) {
256 TestData test = {
257 "", 235 "",
258 236
259 "HTTP/1.0 200 OK\n", 237 "HTTP/1.0 200 OK\n",
260 238
261 200, 239 200,
262 net::HttpVersion(0,0), // Parse Error 240 net::HttpVersion(0,0), // Parse Error.
263 net::HttpVersion(1,0) 241 net::HttpVersion(1,0)
264 }; 242 },
265 TestCommon(test); 243 {
266 } 244 // Normalize headers that start with a colon.
267 245
268 TEST(HttpResponseHeadersTest, NormalizeHeadersStartWithColon) {
269 TestData test = {
270 "HTTP/1.1 202 Accepted \n" 246 "HTTP/1.1 202 Accepted \n"
271 "foo: bar\n" 247 "foo: bar\n"
272 ": a \n" 248 ": a \n"
273 " : b\n" 249 " : b\n"
274 "baz: blat \n", 250 "baz: blat \n",
275 251
276 "HTTP/1.1 202 Accepted\n" 252 "HTTP/1.1 202 Accepted\n"
277 "foo: bar\n" 253 "foo: bar\n"
278 "baz: blat\n", 254 "baz: blat\n",
279 255
280 202, 256 202,
281 net::HttpVersion(1,1), 257 net::HttpVersion(1,1),
282 net::HttpVersion(1,1) 258 net::HttpVersion(1,1)
283 }; 259 },
284 TestCommon(test); 260 {
285 } 261 // Normalize headers that end with a colon.
286 262
287 TEST(HttpResponseHeadersTest, NormalizeHeadersStartWithColonAtEOL) {
288 TestData test = {
289 "HTTP/1.1 202 Accepted \n" 263 "HTTP/1.1 202 Accepted \n"
290 "foo: \n" 264 "foo: \n"
291 "bar:\n" 265 "bar:\n"
292 "baz: blat \n" 266 "baz: blat \n"
293 "zip:\n", 267 "zip:\n",
294 268
295 "HTTP/1.1 202 Accepted\n" 269 "HTTP/1.1 202 Accepted\n"
296 "foo: \n" 270 "foo: \n"
297 "bar: \n" 271 "bar: \n"
298 "baz: blat\n" 272 "baz: blat\n"
299 "zip: \n", 273 "zip: \n",
300 274
301 202, 275 202,
302 net::HttpVersion(1,1), 276 net::HttpVersion(1,1),
303 net::HttpVersion(1,1) 277 net::HttpVersion(1,1)
304 }; 278 },
305 TestCommon(test); 279 {
306 } 280 // Normalize whitespace headers.
307 281
308 TEST(HttpResponseHeadersTest, NormalizeHeadersOfWhitepace) {
309 TestData test = {
310 "\n \n", 282 "\n \n",
311 283
312 "HTTP/1.0 200 OK\n", 284 "HTTP/1.0 200 OK\n",
313 285
314 200, 286 200,
315 net::HttpVersion(0,0), // Parse error 287 net::HttpVersion(0,0), // Parse error.
316 net::HttpVersion(1,0) 288 net::HttpVersion(1,0)
317 }; 289 },
318 TestCommon(test); 290 {
319 } 291 // Consolidate Set-Cookie headers.
320 292
321 TEST(HttpResponseHeadersTest, RepeatedSetCookie) {
322 TestData test = {
323 "HTTP/1.1 200 OK\n" 293 "HTTP/1.1 200 OK\n"
324 "Set-Cookie: x=1\n" 294 "Set-Cookie: x=1\n"
325 "Set-Cookie: y=2\n", 295 "Set-Cookie: y=2\n",
326 296
327 "HTTP/1.1 200 OK\n" 297 "HTTP/1.1 200 OK\n"
328 "Set-Cookie: x=1, y=2\n", 298 "Set-Cookie: x=1, y=2\n",
329 299
330 200, 300 200,
331 net::HttpVersion(1,1), 301 net::HttpVersion(1,1),
332 net::HttpVersion(1,1) 302 net::HttpVersion(1,1)
333 }; 303 },
334 TestCommon(test); 304 };
335 } 305
306 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
307 CommonHttpResponseHeadersTest,
308 testing::ValuesIn(response_headers_tests));
336 309
337 TEST(HttpResponseHeadersTest, GetNormalizedHeader) { 310 TEST(HttpResponseHeadersTest, GetNormalizedHeader) {
338 std::string headers = 311 std::string headers =
339 "HTTP/1.1 200 OK\n" 312 "HTTP/1.1 200 OK\n"
340 "Cache-control: private\n" 313 "Cache-control: private\n"
341 "cache-Control: no-store\n"; 314 "cache-Control: no-store\n";
342 HeadersToRaw(&headers); 315 HeadersToRaw(&headers);
343 scoped_refptr<net::HttpResponseHeaders> parsed( 316 scoped_refptr<net::HttpResponseHeaders> parsed(
344 new net::HttpResponseHeaders(headers)); 317 new net::HttpResponseHeaders(headers));
345 318
346 std::string value; 319 std::string value;
347 EXPECT_TRUE(parsed->GetNormalizedHeader("cache-control", &value)); 320 EXPECT_TRUE(parsed->GetNormalizedHeader("cache-control", &value));
348 EXPECT_EQ("private, no-store", value); 321 EXPECT_EQ("private, no-store", value);
349 } 322 }
350 323
351 TEST(HttpResponseHeadersTest, Persist) { 324 struct PersistData {
352 const struct { 325 net::HttpResponseHeaders::PersistOptions options;
353 net::HttpResponseHeaders::PersistOptions options; 326 const char* raw_headers;
354 const char* raw_headers; 327 const char* expected_headers;
355 const char* expected_headers; 328 };
356 } tests[] = { 329
357 { net::HttpResponseHeaders::PERSIST_ALL, 330 class PersistenceTest
358 "HTTP/1.1 200 OK\n" 331 : public HttpResponseHeadersTest,
359 "Cache-control:private\n" 332 public ::testing::WithParamInterface<PersistData> {
360 "cache-Control:no-store\n", 333 };
361 334
362 "HTTP/1.1 200 OK\n" 335 TEST_P(PersistenceTest, Persist) {
363 "Cache-control: private, no-store\n" 336 const PersistData test = GetParam();
364 }, 337
365 { net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP, 338 std::string headers = test.raw_headers;
366 "HTTP/1.1 200 OK\n" 339 HeadersToRaw(&headers);
367 "connection: keep-alive\n" 340 scoped_refptr<net::HttpResponseHeaders> parsed1(
368 "server: blah\n", 341 new net::HttpResponseHeaders(headers));
369 342
370 "HTTP/1.1 200 OK\n" 343 Pickle pickle;
371 "server: blah\n" 344 parsed1->Persist(&pickle, test.options);
372 }, 345
373 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE | 346 PickleIterator iter(pickle);
374 net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP, 347 scoped_refptr<net::HttpResponseHeaders> parsed2(
375 "HTTP/1.1 200 OK\n" 348 new net::HttpResponseHeaders(pickle, &iter));
376 "fOo: 1\n" 349
377 "Foo: 2\n" 350 std::string h2;
378 "Transfer-Encoding: chunked\n" 351 parsed2->GetNormalizedHeaders(&h2);
379 "CoNnection: keep-alive\n" 352 EXPECT_EQ(std::string(test.expected_headers), h2);
380 "cache-control: private, no-cache=\"foo\"\n",
381
382 "HTTP/1.1 200 OK\n"
383 "cache-control: private, no-cache=\"foo\"\n"
384 },
385 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
386 "HTTP/1.1 200 OK\n"
387 "Foo: 2\n"
388 "Cache-Control: private,no-cache=\"foo, bar\"\n"
389 "bar",
390
391 "HTTP/1.1 200 OK\n"
392 "Cache-Control: private,no-cache=\"foo, bar\"\n"
393 },
394 // ignore bogus no-cache value
395 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
396 "HTTP/1.1 200 OK\n"
397 "Foo: 2\n"
398 "Cache-Control: private,no-cache=foo\n",
399
400 "HTTP/1.1 200 OK\n"
401 "Foo: 2\n"
402 "Cache-Control: private,no-cache=foo\n"
403 },
404 // ignore bogus no-cache value
405 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
406 "HTTP/1.1 200 OK\n"
407 "Foo: 2\n"
408 "Cache-Control: private, no-cache=\n",
409
410 "HTTP/1.1 200 OK\n"
411 "Foo: 2\n"
412 "Cache-Control: private, no-cache=\n"
413 },
414 // ignore empty no-cache value
415 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
416 "HTTP/1.1 200 OK\n"
417 "Foo: 2\n"
418 "Cache-Control: private, no-cache=\"\"\n",
419
420 "HTTP/1.1 200 OK\n"
421 "Foo: 2\n"
422 "Cache-Control: private, no-cache=\"\"\n"
423 },
424 // ignore wrong quotes no-cache value
425 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
426 "HTTP/1.1 200 OK\n"
427 "Foo: 2\n"
428 "Cache-Control: private, no-cache=\'foo\'\n",
429
430 "HTTP/1.1 200 OK\n"
431 "Foo: 2\n"
432 "Cache-Control: private, no-cache=\'foo\'\n"
433 },
434 // ignore unterminated quotes no-cache value
435 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
436 "HTTP/1.1 200 OK\n"
437 "Foo: 2\n"
438 "Cache-Control: private, no-cache=\"foo\n",
439
440 "HTTP/1.1 200 OK\n"
441 "Foo: 2\n"
442 "Cache-Control: private, no-cache=\"foo\n"
443 },
444 // accept sloppy LWS
445 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
446 "HTTP/1.1 200 OK\n"
447 "Foo: 2\n"
448 "Cache-Control: private, no-cache=\" foo\t, bar\"\n",
449
450 "HTTP/1.1 200 OK\n"
451 "Cache-Control: private, no-cache=\" foo\t, bar\"\n"
452 },
453 // header name appears twice, separated by another header
454 { net::HttpResponseHeaders::PERSIST_ALL,
455 "HTTP/1.1 200 OK\n"
456 "Foo: 1\n"
457 "Bar: 2\n"
458 "Foo: 3\n",
459
460 "HTTP/1.1 200 OK\n"
461 "Foo: 1, 3\n"
462 "Bar: 2\n"
463 },
464 // header name appears twice, separated by another header (type 2)
465 { net::HttpResponseHeaders::PERSIST_ALL,
466 "HTTP/1.1 200 OK\n"
467 "Foo: 1, 3\n"
468 "Bar: 2\n"
469 "Foo: 4\n",
470
471 "HTTP/1.1 200 OK\n"
472 "Foo: 1, 3, 4\n"
473 "Bar: 2\n"
474 },
475 // Test filtering of cookie headers.
476 { net::HttpResponseHeaders::PERSIST_SANS_COOKIES,
477 "HTTP/1.1 200 OK\n"
478 "Set-Cookie: foo=bar; httponly\n"
479 "Set-Cookie: bar=foo\n"
480 "Bar: 1\n"
481 "Set-Cookie2: bar2=foo2\n",
482
483 "HTTP/1.1 200 OK\n"
484 "Bar: 1\n"
485 },
486 // Test LWS at the end of a header.
487 { net::HttpResponseHeaders::PERSIST_ALL,
488 "HTTP/1.1 200 OK\n"
489 "Content-Length: 450 \n"
490 "Content-Encoding: gzip\n",
491
492 "HTTP/1.1 200 OK\n"
493 "Content-Length: 450\n"
494 "Content-Encoding: gzip\n"
495 },
496 // Test LWS at the end of a header.
497 { net::HttpResponseHeaders::PERSIST_RAW,
498 "HTTP/1.1 200 OK\n"
499 "Content-Length: 450 \n"
500 "Content-Encoding: gzip\n",
501
502 "HTTP/1.1 200 OK\n"
503 "Content-Length: 450\n"
504 "Content-Encoding: gzip\n"
505 },
506 // Test filtering of transport security state headers.
507 { net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE,
508 "HTTP/1.1 200 OK\n"
509 "Strict-Transport-Security: max-age=1576800\n"
510 "Bar: 1\n"
511 "Public-Key-Pins: max-age=100000; "
512 "pin-sha1=\"ObT42aoSpAqWdY9WfRfL7i0HsVk=\";"
513 "pin-sha1=\"7kW49EVwZG0hSNx41ZO/fUPN0ek=\"",
514
515 "HTTP/1.1 200 OK\n"
516 "Bar: 1\n"
517 },
518 };
519
520 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
521 std::string headers = tests[i].raw_headers;
522 HeadersToRaw(&headers);
523 scoped_refptr<net::HttpResponseHeaders> parsed1(
524 new net::HttpResponseHeaders(headers));
525
526 Pickle pickle;
527 parsed1->Persist(&pickle, tests[i].options);
528
529 PickleIterator iter(pickle);
530 scoped_refptr<net::HttpResponseHeaders> parsed2(
531 new net::HttpResponseHeaders(pickle, &iter));
532
533 std::string h2;
534 parsed2->GetNormalizedHeaders(&h2);
535 EXPECT_EQ(std::string(tests[i].expected_headers), h2);
536 }
537 } 353 }
538 354
355 const struct PersistData persistence_tests[] = {
356 { net::HttpResponseHeaders::PERSIST_ALL,
357 "HTTP/1.1 200 OK\n"
358 "Cache-control:private\n"
359 "cache-Control:no-store\n",
360
361 "HTTP/1.1 200 OK\n"
362 "Cache-control: private, no-store\n"
363 },
364 { net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP,
365 "HTTP/1.1 200 OK\n"
366 "connection: keep-alive\n"
367 "server: blah\n",
368
369 "HTTP/1.1 200 OK\n"
370 "server: blah\n"
371 },
372 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE |
373 net::HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP,
374 "HTTP/1.1 200 OK\n"
375 "fOo: 1\n"
376 "Foo: 2\n"
377 "Transfer-Encoding: chunked\n"
378 "CoNnection: keep-alive\n"
379 "cache-control: private, no-cache=\"foo\"\n",
380
381 "HTTP/1.1 200 OK\n"
382 "cache-control: private, no-cache=\"foo\"\n"
383 },
384 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
385 "HTTP/1.1 200 OK\n"
386 "Foo: 2\n"
387 "Cache-Control: private,no-cache=\"foo, bar\"\n"
388 "bar",
389
390 "HTTP/1.1 200 OK\n"
391 "Cache-Control: private,no-cache=\"foo, bar\"\n"
392 },
393 // Ignore bogus no-cache value.
394 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
395 "HTTP/1.1 200 OK\n"
396 "Foo: 2\n"
397 "Cache-Control: private,no-cache=foo\n",
398
399 "HTTP/1.1 200 OK\n"
400 "Foo: 2\n"
401 "Cache-Control: private,no-cache=foo\n"
402 },
403 // Ignore bogus no-cache value.
404 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
405 "HTTP/1.1 200 OK\n"
406 "Foo: 2\n"
407 "Cache-Control: private, no-cache=\n",
408
409 "HTTP/1.1 200 OK\n"
410 "Foo: 2\n"
411 "Cache-Control: private, no-cache=\n"
412 },
413 // Ignore empty no-cache value.
414 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
415 "HTTP/1.1 200 OK\n"
416 "Foo: 2\n"
417 "Cache-Control: private, no-cache=\"\"\n",
418
419 "HTTP/1.1 200 OK\n"
420 "Foo: 2\n"
421 "Cache-Control: private, no-cache=\"\"\n"
422 },
423 // Ignore wrong quotes no-cache value.
424 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
425 "HTTP/1.1 200 OK\n"
426 "Foo: 2\n"
427 "Cache-Control: private, no-cache=\'foo\'\n",
428
429 "HTTP/1.1 200 OK\n"
430 "Foo: 2\n"
431 "Cache-Control: private, no-cache=\'foo\'\n"
432 },
433 // Ignore unterminated quotes no-cache value.
434 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
435 "HTTP/1.1 200 OK\n"
436 "Foo: 2\n"
437 "Cache-Control: private, no-cache=\"foo\n",
438
439 "HTTP/1.1 200 OK\n"
440 "Foo: 2\n"
441 "Cache-Control: private, no-cache=\"foo\n"
442 },
443 // Accept sloppy LWS.
444 { net::HttpResponseHeaders::PERSIST_SANS_NON_CACHEABLE,
445 "HTTP/1.1 200 OK\n"
446 "Foo: 2\n"
447 "Cache-Control: private, no-cache=\" foo\t, bar\"\n",
448
449 "HTTP/1.1 200 OK\n"
450 "Cache-Control: private, no-cache=\" foo\t, bar\"\n"
451 },
452 // Header name appears twice, separated by another header.
453 { net::HttpResponseHeaders::PERSIST_ALL,
454 "HTTP/1.1 200 OK\n"
455 "Foo: 1\n"
456 "Bar: 2\n"
457 "Foo: 3\n",
458
459 "HTTP/1.1 200 OK\n"
460 "Foo: 1, 3\n"
461 "Bar: 2\n"
462 },
463 // Header name appears twice, separated by another header (type 2).
464 { net::HttpResponseHeaders::PERSIST_ALL,
465 "HTTP/1.1 200 OK\n"
466 "Foo: 1, 3\n"
467 "Bar: 2\n"
468 "Foo: 4\n",
469
470 "HTTP/1.1 200 OK\n"
471 "Foo: 1, 3, 4\n"
472 "Bar: 2\n"
473 },
474 // Test filtering of cookie headers.
475 { net::HttpResponseHeaders::PERSIST_SANS_COOKIES,
476 "HTTP/1.1 200 OK\n"
477 "Set-Cookie: foo=bar; httponly\n"
478 "Set-Cookie: bar=foo\n"
479 "Bar: 1\n"
480 "Set-Cookie2: bar2=foo2\n",
481
482 "HTTP/1.1 200 OK\n"
483 "Bar: 1\n"
484 },
485 // Test LWS at the end of a header.
486 { net::HttpResponseHeaders::PERSIST_ALL,
487 "HTTP/1.1 200 OK\n"
488 "Content-Length: 450 \n"
489 "Content-Encoding: gzip\n",
490
491 "HTTP/1.1 200 OK\n"
492 "Content-Length: 450\n"
493 "Content-Encoding: gzip\n"
494 },
495 // Test LWS at the end of a header.
496 { net::HttpResponseHeaders::PERSIST_RAW,
497 "HTTP/1.1 200 OK\n"
498 "Content-Length: 450 \n"
499 "Content-Encoding: gzip\n",
500
501 "HTTP/1.1 200 OK\n"
502 "Content-Length: 450\n"
503 "Content-Encoding: gzip\n"
504 },
505 // Test filtering of transport security state headers.
506 { net::HttpResponseHeaders::PERSIST_SANS_SECURITY_STATE,
507 "HTTP/1.1 200 OK\n"
508 "Strict-Transport-Security: max-age=1576800\n"
509 "Bar: 1\n"
510 "Public-Key-Pins: max-age=100000; "
511 "pin-sha1=\"ObT42aoSpAqWdY9WfRfL7i0HsVk=\";"
512 "pin-sha1=\"7kW49EVwZG0hSNx41ZO/fUPN0ek=\"",
513
514 "HTTP/1.1 200 OK\n"
515 "Bar: 1\n"
516 },
517 };
518
519 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
520 PersistenceTest,
521 testing::ValuesIn(persistence_tests));
522
539 TEST(HttpResponseHeadersTest, EnumerateHeader_Coalesced) { 523 TEST(HttpResponseHeadersTest, EnumerateHeader_Coalesced) {
540 // Ensure that commas in quoted strings are not regarded as value separators. 524 // Ensure that commas in quoted strings are not regarded as value separators.
541 // Ensure that whitespace following a value is trimmed properly 525 // Ensure that whitespace following a value is trimmed properly.
542 std::string headers = 526 std::string headers =
543 "HTTP/1.1 200 OK\n" 527 "HTTP/1.1 200 OK\n"
544 "Cache-control:private , no-cache=\"set-cookie,server\" \n" 528 "Cache-control:private , no-cache=\"set-cookie,server\" \n"
545 "cache-Control: no-store\n"; 529 "cache-Control: no-store\n";
546 HeadersToRaw(&headers); 530 HeadersToRaw(&headers);
547 scoped_refptr<net::HttpResponseHeaders> parsed( 531 scoped_refptr<net::HttpResponseHeaders> parsed(
548 new net::HttpResponseHeaders(headers)); 532 new net::HttpResponseHeaders(headers));
549 533
550 void* iter = NULL; 534 void* iter = NULL;
551 std::string value; 535 std::string value;
(...skipping 21 matching lines...) Expand all
573 std::string value; 557 std::string value;
574 EXPECT_TRUE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value)); 558 EXPECT_TRUE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
575 EXPECT_EQ("Digest realm=foobar, nonce=x, domain=y", value); 559 EXPECT_EQ("Digest realm=foobar, nonce=x, domain=y", value);
576 EXPECT_TRUE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value)); 560 EXPECT_TRUE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
577 EXPECT_EQ("Basic realm=quatar", value); 561 EXPECT_EQ("Basic realm=quatar", value);
578 EXPECT_FALSE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value)); 562 EXPECT_FALSE(parsed->EnumerateHeader(&iter, "WWW-Authenticate", &value));
579 } 563 }
580 564
581 TEST(HttpResponseHeadersTest, EnumerateHeader_DateValued) { 565 TEST(HttpResponseHeadersTest, EnumerateHeader_DateValued) {
582 // The comma in a date valued header should not be treated as a 566 // The comma in a date valued header should not be treated as a
583 // field-value separator 567 // field-value separator.
584 std::string headers = 568 std::string headers =
585 "HTTP/1.1 200 OK\n" 569 "HTTP/1.1 200 OK\n"
586 "Date: Tue, 07 Aug 2007 23:10:55 GMT\n" 570 "Date: Tue, 07 Aug 2007 23:10:55 GMT\n"
587 "Last-Modified: Wed, 01 Aug 2007 23:23:45 GMT\n"; 571 "Last-Modified: Wed, 01 Aug 2007 23:23:45 GMT\n";
588 HeadersToRaw(&headers); 572 HeadersToRaw(&headers);
589 scoped_refptr<net::HttpResponseHeaders> parsed( 573 scoped_refptr<net::HttpResponseHeaders> parsed(
590 new net::HttpResponseHeaders(headers)); 574 new net::HttpResponseHeaders(headers));
591 575
592 std::string value; 576 std::string value;
593 EXPECT_TRUE(parsed->EnumerateHeader(NULL, "date", &value)); 577 EXPECT_TRUE(parsed->EnumerateHeader(NULL, "date", &value));
(...skipping 25 matching lines...) Expand all
619 // If GMT is missing but an RFC822-conforming one is present, use that. 603 // If GMT is missing but an RFC822-conforming one is present, use that.
620 EXPECT_TRUE(parsed->GetLastModifiedValue(&value)); 604 EXPECT_TRUE(parsed->GetLastModifiedValue(&value));
621 EXPECT_EQ(expected_value, value); 605 EXPECT_EQ(expected_value, value);
622 // If an unknown timezone is present, treat like a missing timezone and 606 // If an unknown timezone is present, treat like a missing timezone and
623 // default to GMT. The only example of a web server not specifying "GMT" 607 // default to GMT. The only example of a web server not specifying "GMT"
624 // used "UTC" which is equivalent to GMT. 608 // used "UTC" which is equivalent to GMT.
625 if (parsed->GetExpiresValue(&value)) 609 if (parsed->GetExpiresValue(&value))
626 EXPECT_EQ(expected_value, value); 610 EXPECT_EQ(expected_value, value);
627 } 611 }
628 612
629 TEST(HttpResponseHeadersTest, GetMimeType) { 613 struct ContentTypeTestData {
630 const ContentTypeTestData tests[] = { 614 const std::string raw_headers;
631 { "HTTP/1.1 200 OK\n" 615 const std::string mime_type;
632 "Content-type: text/html\n", 616 const bool has_mimetype;
633 "text/html", true, 617 const std::string charset;
634 "", false, 618 const bool has_charset;
635 "text/html" }, 619 const std::string all_content_type;
636 // Multiple content-type headers should give us the last one. 620 };
637 { "HTTP/1.1 200 OK\n" 621
638 "Content-type: text/html\n" 622 class ContentTypeTest
639 "Content-type: text/html\n", 623 : public HttpResponseHeadersTest,
640 "text/html", true, 624 public ::testing::WithParamInterface<ContentTypeTestData> {
641 "", false, 625 };
642 "text/html, text/html" }, 626
643 { "HTTP/1.1 200 OK\n" 627 TEST_P(ContentTypeTest, GetMimeType) {
644 "Content-type: text/plain\n" 628 const ContentTypeTestData test = GetParam();
645 "Content-type: text/html\n" 629
646 "Content-type: text/plain\n" 630 std::string headers(test.raw_headers);
647 "Content-type: text/html\n", 631 HeadersToRaw(&headers);
648 "text/html", true, 632 scoped_refptr<net::HttpResponseHeaders> parsed(
649 "", false, 633 new net::HttpResponseHeaders(headers));
650 "text/plain, text/html, text/plain, text/html" }, 634
651 // Test charset parsing. 635 std::string value;
652 { "HTTP/1.1 200 OK\n" 636 EXPECT_EQ(test.has_mimetype, parsed->GetMimeType(&value));
653 "Content-type: text/html\n" 637 EXPECT_EQ(test.mime_type, value);
654 "Content-type: text/html; charset=ISO-8859-1\n", 638 value.clear();
655 "text/html", true, 639 EXPECT_EQ(test.has_charset, parsed->GetCharset(&value));
656 "iso-8859-1", true, 640 EXPECT_EQ(test.charset, value);
657 "text/html, text/html; charset=ISO-8859-1" }, 641 EXPECT_TRUE(parsed->GetNormalizedHeader("content-type", &value));
658 // Test charset in double quotes. 642 EXPECT_EQ(test.all_content_type, value);
659 { "HTTP/1.1 200 OK\n"
660 "Content-type: text/html\n"
661 "Content-type: text/html; charset=\"ISO-8859-1\"\n",
662 "text/html", true,
663 "iso-8859-1", true,
664 "text/html, text/html; charset=\"ISO-8859-1\"" },
665 // If there are multiple matching content-type headers, we carry
666 // over the charset value.
667 { "HTTP/1.1 200 OK\n"
668 "Content-type: text/html;charset=utf-8\n"
669 "Content-type: text/html\n",
670 "text/html", true,
671 "utf-8", true,
672 "text/html;charset=utf-8, text/html" },
673 // Test single quotes.
674 { "HTTP/1.1 200 OK\n"
675 "Content-type: text/html;charset='utf-8'\n"
676 "Content-type: text/html\n",
677 "text/html", true,
678 "utf-8", true,
679 "text/html;charset='utf-8', text/html" },
680 // Last charset wins if matching content-type.
681 { "HTTP/1.1 200 OK\n"
682 "Content-type: text/html;charset=utf-8\n"
683 "Content-type: text/html;charset=iso-8859-1\n",
684 "text/html", true,
685 "iso-8859-1", true,
686 "text/html;charset=utf-8, text/html;charset=iso-8859-1" },
687 // Charset is ignored if the content types change.
688 { "HTTP/1.1 200 OK\n"
689 "Content-type: text/plain;charset=utf-8\n"
690 "Content-type: text/html\n",
691 "text/html", true,
692 "", false,
693 "text/plain;charset=utf-8, text/html" },
694 // Empty content-type
695 { "HTTP/1.1 200 OK\n"
696 "Content-type: \n",
697 "", false,
698 "", false,
699 "" },
700 // Emtpy charset
701 { "HTTP/1.1 200 OK\n"
702 "Content-type: text/html;charset=\n",
703 "text/html", true,
704 "", false,
705 "text/html;charset=" },
706 // Multiple charsets, last one wins.
707 { "HTTP/1.1 200 OK\n"
708 "Content-type: text/html;charset=utf-8; charset=iso-8859-1\n",
709 "text/html", true,
710 "iso-8859-1", true,
711 "text/html;charset=utf-8; charset=iso-8859-1" },
712 // Multiple params.
713 { "HTTP/1.1 200 OK\n"
714 "Content-type: text/html; foo=utf-8; charset=iso-8859-1\n",
715 "text/html", true,
716 "iso-8859-1", true,
717 "text/html; foo=utf-8; charset=iso-8859-1" },
718 { "HTTP/1.1 200 OK\n"
719 "Content-type: text/html ; charset=utf-8 ; bar=iso-8859-1\n",
720 "text/html", true,
721 "utf-8", true,
722 "text/html ; charset=utf-8 ; bar=iso-8859-1" },
723 // Comma embeded in quotes.
724 { "HTTP/1.1 200 OK\n"
725 "Content-type: text/html ; charset='utf-8,text/plain' ;\n",
726 "text/html", true,
727 "utf-8,text/plain", true,
728 "text/html ; charset='utf-8,text/plain' ;" },
729 // Charset with leading spaces.
730 { "HTTP/1.1 200 OK\n"
731 "Content-type: text/html ; charset= 'utf-8' ;\n",
732 "text/html", true,
733 "utf-8", true,
734 "text/html ; charset= 'utf-8' ;" },
735 // Media type comments in mime-type.
736 { "HTTP/1.1 200 OK\n"
737 "Content-type: text/html (html)\n",
738 "text/html", true,
739 "", false,
740 "text/html (html)" },
741 // Incomplete charset= param
742 { "HTTP/1.1 200 OK\n"
743 "Content-type: text/html; char=\n",
744 "text/html", true,
745 "", false,
746 "text/html; char=" },
747 // Invalid media type: no slash
748 { "HTTP/1.1 200 OK\n"
749 "Content-type: texthtml\n",
750 "", false,
751 "", false,
752 "texthtml" },
753 // Invalid media type: */*
754 { "HTTP/1.1 200 OK\n"
755 "Content-type: */*\n",
756 "", false,
757 "", false,
758 "*/*" },
759 };
760
761 for (size_t i = 0; i < arraysize(tests); ++i) {
762 std::string headers(tests[i].raw_headers);
763 HeadersToRaw(&headers);
764 scoped_refptr<net::HttpResponseHeaders> parsed(
765 new net::HttpResponseHeaders(headers));
766
767 std::string value;
768 EXPECT_EQ(tests[i].has_mimetype, parsed->GetMimeType(&value));
769 EXPECT_EQ(tests[i].mime_type, value);
770 value.clear();
771 EXPECT_EQ(tests[i].has_charset, parsed->GetCharset(&value));
772 EXPECT_EQ(tests[i].charset, value);
773 EXPECT_TRUE(parsed->GetNormalizedHeader("content-type", &value));
774 EXPECT_EQ(tests[i].all_content_type, value);
775 }
776 } 643 }
777 644
778 TEST(HttpResponseHeadersTest, RequiresValidation) { 645 const ContentTypeTestData mimetype_tests[] = {
779 const struct { 646 { "HTTP/1.1 200 OK\n"
780 const char* headers; 647 "Content-type: text/html\n",
781 bool requires_validation; 648 "text/html", true,
782 } tests[] = { 649 "", false,
783 // no expiry info: expires immediately 650 "text/html" },
784 { "HTTP/1.1 200 OK\n" 651 // Multiple content-type headers should give us the last one.
785 "\n", 652 { "HTTP/1.1 200 OK\n"
786 true 653 "Content-type: text/html\n"
787 }, 654 "Content-type: text/html\n",
788 // valid for a little while 655 "text/html", true,
789 { "HTTP/1.1 200 OK\n" 656 "", false,
790 "cache-control: max-age=10000\n" 657 "text/html, text/html" },
791 "\n", 658 { "HTTP/1.1 200 OK\n"
792 false 659 "Content-type: text/plain\n"
793 }, 660 "Content-type: text/html\n"
794 // expires in the future 661 "Content-type: text/plain\n"
795 { "HTTP/1.1 200 OK\n" 662 "Content-type: text/html\n",
796 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 663 "text/html", true,
797 "expires: Wed, 28 Nov 2007 01:00:00 GMT\n" 664 "", false,
798 "\n", 665 "text/plain, text/html, text/plain, text/html" },
799 false 666 // Test charset parsing.
800 }, 667 { "HTTP/1.1 200 OK\n"
801 // expired already 668 "Content-type: text/html\n"
802 { "HTTP/1.1 200 OK\n" 669 "Content-type: text/html; charset=ISO-8859-1\n",
803 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 670 "text/html", true,
804 "expires: Wed, 28 Nov 2007 00:00:00 GMT\n" 671 "iso-8859-1", true,
805 "\n", 672 "text/html, text/html; charset=ISO-8859-1" },
806 true 673 // Test charset in double quotes.
807 }, 674 { "HTTP/1.1 200 OK\n"
808 // max-age trumps expires 675 "Content-type: text/html\n"
809 { "HTTP/1.1 200 OK\n" 676 "Content-type: text/html; charset=\"ISO-8859-1\"\n",
810 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 677 "text/html", true,
811 "expires: Wed, 28 Nov 2007 00:00:00 GMT\n" 678 "iso-8859-1", true,
812 "cache-control: max-age=10000\n" 679 "text/html, text/html; charset=\"ISO-8859-1\"" },
813 "\n", 680 // If there are multiple matching content-type headers, we carry
814 false 681 // over the charset value.
815 }, 682 { "HTTP/1.1 200 OK\n"
816 // last-modified heuristic: modified a while ago 683 "Content-type: text/html;charset=utf-8\n"
817 { "HTTP/1.1 200 OK\n" 684 "Content-type: text/html\n",
818 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 685 "text/html", true,
819 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n" 686 "utf-8", true,
820 "\n", 687 "text/html;charset=utf-8, text/html" },
821 false 688 // Test single quotes.
822 }, 689 { "HTTP/1.1 200 OK\n"
823 { "HTTP/1.1 203 Non-Authoritative Information\n" 690 "Content-type: text/html;charset='utf-8'\n"
824 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 691 "Content-type: text/html\n",
825 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n" 692 "text/html", true,
826 "\n", 693 "utf-8", true,
827 false 694 "text/html;charset='utf-8', text/html" },
828 }, 695 // Last charset wins if matching content-type.
829 { "HTTP/1.1 206 Partial Content\n" 696 { "HTTP/1.1 200 OK\n"
830 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 697 "Content-type: text/html;charset=utf-8\n"
831 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n" 698 "Content-type: text/html;charset=iso-8859-1\n",
832 "\n", 699 "text/html", true,
833 false 700 "iso-8859-1", true,
834 }, 701 "text/html;charset=utf-8, text/html;charset=iso-8859-1" },
835 // last-modified heuristic: modified recently 702 // Charset is ignored if the content types change.
836 { "HTTP/1.1 200 OK\n" 703 { "HTTP/1.1 200 OK\n"
837 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 704 "Content-type: text/plain;charset=utf-8\n"
838 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n" 705 "Content-type: text/html\n",
839 "\n", 706 "text/html", true,
840 true 707 "", false,
841 }, 708 "text/plain;charset=utf-8, text/html" },
842 { "HTTP/1.1 203 Non-Authoritative Information\n" 709 // Empty content-type.
843 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 710 { "HTTP/1.1 200 OK\n"
844 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n" 711 "Content-type: \n",
845 "\n", 712 "", false,
846 true 713 "", false,
847 }, 714 "" },
848 { "HTTP/1.1 206 Partial Content\n" 715 // Emtpy charset.
849 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 716 { "HTTP/1.1 200 OK\n"
850 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n" 717 "Content-type: text/html;charset=\n",
851 "\n", 718 "text/html", true,
852 true 719 "", false,
853 }, 720 "text/html;charset=" },
854 // cached permanent redirect 721 // Multiple charsets, last one wins.
855 { "HTTP/1.1 301 Moved Permanently\n" 722 { "HTTP/1.1 200 OK\n"
856 "\n", 723 "Content-type: text/html;charset=utf-8; charset=iso-8859-1\n",
857 false 724 "text/html", true,
858 }, 725 "iso-8859-1", true,
859 // another cached permanent redirect 726 "text/html;charset=utf-8; charset=iso-8859-1" },
860 { "HTTP/1.1 308 Permanent Redirect\n" 727 // Multiple params.
861 "\n", 728 { "HTTP/1.1 200 OK\n"
862 false 729 "Content-type: text/html; foo=utf-8; charset=iso-8859-1\n",
863 }, 730 "text/html", true,
864 // cached redirect: not reusable even though by default it would be 731 "iso-8859-1", true,
865 { "HTTP/1.1 300 Multiple Choices\n" 732 "text/html; foo=utf-8; charset=iso-8859-1" },
866 "Cache-Control: no-cache\n" 733 { "HTTP/1.1 200 OK\n"
867 "\n", 734 "Content-type: text/html ; charset=utf-8 ; bar=iso-8859-1\n",
868 true 735 "text/html", true,
869 }, 736 "utf-8", true,
870 // cached forever by default 737 "text/html ; charset=utf-8 ; bar=iso-8859-1" },
871 { "HTTP/1.1 410 Gone\n" 738 // Comma embeded in quotes.
872 "\n", 739 { "HTTP/1.1 200 OK\n"
873 false 740 "Content-type: text/html ; charset='utf-8,text/plain' ;\n",
874 }, 741 "text/html", true,
875 // cached temporary redirect: not reusable 742 "utf-8,text/plain", true,
876 { "HTTP/1.1 302 Found\n" 743 "text/html ; charset='utf-8,text/plain' ;" },
877 "\n", 744 // Charset with leading spaces.
878 true 745 { "HTTP/1.1 200 OK\n"
879 }, 746 "Content-type: text/html ; charset= 'utf-8' ;\n",
880 // cached temporary redirect: reusable 747 "text/html", true,
881 { "HTTP/1.1 302 Found\n" 748 "utf-8", true,
882 "cache-control: max-age=10000\n" 749 "text/html ; charset= 'utf-8' ;" },
883 "\n", 750 // Media type comments in mime-type.
884 false 751 { "HTTP/1.1 200 OK\n"
885 }, 752 "Content-type: text/html (html)\n",
886 // cache-control: max-age=N overrides expires: date in the past 753 "text/html", true,
887 { "HTTP/1.1 200 OK\n" 754 "", false,
888 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 755 "text/html (html)" },
889 "expires: Wed, 28 Nov 2007 00:20:11 GMT\n" 756 // Incomplete charset= param.
890 "cache-control: max-age=10000\n" 757 { "HTTP/1.1 200 OK\n"
891 "\n", 758 "Content-type: text/html; char=\n",
892 false 759 "text/html", true,
893 }, 760 "", false,
894 // cache-control: no-store overrides expires: in the future 761 "text/html; char=" },
895 { "HTTP/1.1 200 OK\n" 762 // Invalid media type: no slash.
896 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 763 { "HTTP/1.1 200 OK\n"
897 "expires: Wed, 29 Nov 2007 00:40:11 GMT\n" 764 "Content-type: texthtml\n",
898 "cache-control: no-store,private,no-cache=\"foo\"\n" 765 "", false,
899 "\n", 766 "", false,
900 true 767 "texthtml" },
901 }, 768 // Invalid media type: "*/*".
902 // pragma: no-cache overrides last-modified heuristic 769 { "HTTP/1.1 200 OK\n"
903 { "HTTP/1.1 200 OK\n" 770 "Content-type: */*\n",
904 "date: Wed, 28 Nov 2007 00:40:11 GMT\n" 771 "", false,
905 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n" 772 "", false,
906 "pragma: no-cache\n" 773 "*/*" },
907 "\n", 774 };
908 true 775
909 }, 776 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
910 // TODO(darin): add many many more tests here 777 ContentTypeTest,
911 }; 778 testing::ValuesIn(mimetype_tests));
779
780 struct RequiresValidationTestData {
781 const char* headers;
782 bool requires_validation;
783 };
784
785 class RequiresValidationTest
786 : public HttpResponseHeadersTest,
787 public ::testing::WithParamInterface<RequiresValidationTestData> {
788 };
789
790 TEST_P(RequiresValidationTest, RequiresValidation) {
791 const RequiresValidationTestData test = GetParam();
792
912 base::Time request_time, response_time, current_time; 793 base::Time request_time, response_time, current_time;
913 base::Time::FromString("Wed, 28 Nov 2007 00:40:09 GMT", &request_time); 794 base::Time::FromString("Wed, 28 Nov 2007 00:40:09 GMT", &request_time);
914 base::Time::FromString("Wed, 28 Nov 2007 00:40:12 GMT", &response_time); 795 base::Time::FromString("Wed, 28 Nov 2007 00:40:12 GMT", &response_time);
915 base::Time::FromString("Wed, 28 Nov 2007 00:45:20 GMT", &current_time); 796 base::Time::FromString("Wed, 28 Nov 2007 00:45:20 GMT", &current_time);
916 797
917 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 798 std::string headers(test.headers);
918 std::string headers(tests[i].headers); 799 HeadersToRaw(&headers);
919 HeadersToRaw(&headers); 800 scoped_refptr<net::HttpResponseHeaders> parsed(
920 scoped_refptr<net::HttpResponseHeaders> parsed( 801 new net::HttpResponseHeaders(headers));
921 new net::HttpResponseHeaders(headers)); 802
922 803 bool requires_validation =
923 bool requires_validation = 804 parsed->RequiresValidation(request_time, response_time, current_time);
924 parsed->RequiresValidation(request_time, response_time, current_time); 805 EXPECT_EQ(test.requires_validation, requires_validation);
925 EXPECT_EQ(tests[i].requires_validation, requires_validation); 806 }
807
808 const struct RequiresValidationTestData requires_validation_tests[] = {
809 // No expiry info: expires immediately.
810 { "HTTP/1.1 200 OK\n"
811 "\n",
812 true
813 },
814 // No expiry info: expires immediately.
815 { "HTTP/1.1 200 OK\n"
816 "\n",
817 true
818 },
819 // Valid for a little while.
820 { "HTTP/1.1 200 OK\n"
821 "cache-control: max-age=10000\n"
822 "\n",
823 false
824 },
825 // Expires in the future.
826 { "HTTP/1.1 200 OK\n"
827 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
828 "expires: Wed, 28 Nov 2007 01:00:00 GMT\n"
829 "\n",
830 false
831 },
832 // Already expired.
833 { "HTTP/1.1 200 OK\n"
834 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
835 "expires: Wed, 28 Nov 2007 00:00:00 GMT\n"
836 "\n",
837 true
838 },
839 // Max-age trumps expires.
840 { "HTTP/1.1 200 OK\n"
841 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
842 "expires: Wed, 28 Nov 2007 00:00:00 GMT\n"
843 "cache-control: max-age=10000\n"
844 "\n",
845 false
846 },
847 // Last-modified heuristic: modified a while ago.
848 { "HTTP/1.1 200 OK\n"
849 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
850 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
851 "\n",
852 false
853 },
854 { "HTTP/1.1 203 Non-Authoritative Information\n"
855 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
856 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
857 "\n",
858 false
859 },
860 { "HTTP/1.1 206 Partial Content\n"
861 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
862 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
863 "\n",
864 false
865 },
866 // Last-modified heuristic: modified recently.
867 { "HTTP/1.1 200 OK\n"
868 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
869 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
870 "\n",
871 true
872 },
873 { "HTTP/1.1 203 Non-Authoritative Information\n"
874 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
875 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
876 "\n",
877 true
878 },
879 { "HTTP/1.1 206 Partial Content\n"
880 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
881 "last-modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
882 "\n",
883 true
884 },
885 // Cached permanent redirect.
886 { "HTTP/1.1 301 Moved Permanently\n"
887 "\n",
888 false
889 },
890 // Another cached permanent redirect.
891 { "HTTP/1.1 308 Permanent Redirect\n"
892 "\n",
893 false
894 },
895 // Cached redirect: not reusable even though by default it would be.
896 { "HTTP/1.1 300 Multiple Choices\n"
897 "Cache-Control: no-cache\n"
898 "\n",
899 true
900 },
901 // Cached forever by default.
902 { "HTTP/1.1 410 Gone\n"
903 "\n",
904 false
905 },
906 // Cached temporary redirect: not reusable.
907 { "HTTP/1.1 302 Found\n"
908 "\n",
909 true
910 },
911 // Cached temporary redirect: reusable.
912 { "HTTP/1.1 302 Found\n"
913 "cache-control: max-age=10000\n"
914 "\n",
915 false
916 },
917 // Cache-control: max-age=N overrides expires: date in the past.
918 { "HTTP/1.1 200 OK\n"
919 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
920 "expires: Wed, 28 Nov 2007 00:20:11 GMT\n"
921 "cache-control: max-age=10000\n"
922 "\n",
923 false
924 },
925 // Cache-control: no-store overrides expires: in the future.
926 { "HTTP/1.1 200 OK\n"
927 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
928 "expires: Wed, 29 Nov 2007 00:40:11 GMT\n"
929 "cache-control: no-store,private,no-cache=\"foo\"\n"
930 "\n",
931 true
932 },
933 // Pragma: no-cache overrides last-modified heuristic.
934 { "HTTP/1.1 200 OK\n"
935 "date: Wed, 28 Nov 2007 00:40:11 GMT\n"
936 "last-modified: Wed, 27 Nov 2007 08:00:00 GMT\n"
937 "pragma: no-cache\n"
938 "\n",
939 true
940 },
941
942 // TODO(darin): Add many many more tests here.
943 };
944
945 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
946 RequiresValidationTest,
947 testing::ValuesIn(requires_validation_tests));
948
949 struct UpdateTestData {
950 const char* orig_headers;
951 const char* new_headers;
952 const char* expected_headers;
953 };
954
955 class UpdateTest
956 : public HttpResponseHeadersTest,
957 public ::testing::WithParamInterface<UpdateTestData> {
958 };
959
960 TEST_P(UpdateTest, Update) {
961 const UpdateTestData test = GetParam();
962
963 std::string orig_headers(test.orig_headers);
964 HeadersToRaw(&orig_headers);
965 scoped_refptr<net::HttpResponseHeaders> parsed(
966 new net::HttpResponseHeaders(orig_headers));
967
968 std::string new_headers(test.new_headers);
969 HeadersToRaw(&new_headers);
970 scoped_refptr<net::HttpResponseHeaders> new_parsed(
971 new net::HttpResponseHeaders(new_headers));
972
973 parsed->Update(*new_parsed.get());
974
975 std::string resulting_headers;
976 parsed->GetNormalizedHeaders(&resulting_headers);
977 EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
978 }
979
980 const UpdateTestData update_tests[] = {
981 { "HTTP/1.1 200 OK\n",
982
983 "HTTP/1/1 304 Not Modified\n"
984 "connection: keep-alive\n"
985 "Cache-control: max-age=10000\n",
986
987 "HTTP/1.1 200 OK\n"
988 "Cache-control: max-age=10000\n"
989 },
990 { "HTTP/1.1 200 OK\n"
991 "Foo: 1\n"
992 "Cache-control: private\n",
993
994 "HTTP/1/1 304 Not Modified\n"
995 "connection: keep-alive\n"
996 "Cache-control: max-age=10000\n",
997
998 "HTTP/1.1 200 OK\n"
999 "Cache-control: max-age=10000\n"
1000 "Foo: 1\n"
1001 },
1002 { "HTTP/1.1 200 OK\n"
1003 "Foo: 1\n"
1004 "Cache-control: private\n",
1005
1006 "HTTP/1/1 304 Not Modified\n"
1007 "connection: keep-alive\n"
1008 "Cache-CONTROL: max-age=10000\n",
1009
1010 "HTTP/1.1 200 OK\n"
1011 "Cache-CONTROL: max-age=10000\n"
1012 "Foo: 1\n"
1013 },
1014 { "HTTP/1.1 200 OK\n"
1015 "Content-Length: 450\n",
1016
1017 "HTTP/1/1 304 Not Modified\n"
1018 "connection: keep-alive\n"
1019 "Cache-control: max-age=10001 \n",
1020
1021 "HTTP/1.1 200 OK\n"
1022 "Cache-control: max-age=10001\n"
1023 "Content-Length: 450\n"
1024 },
1025 { "HTTP/1.1 200 OK\n"
1026 "X-Frame-Options: DENY\n",
1027
1028 "HTTP/1/1 304 Not Modified\n"
1029 "X-Frame-Options: ALLOW\n",
1030
1031 "HTTP/1.1 200 OK\n"
1032 "X-Frame-Options: DENY\n",
1033 },
1034 { "HTTP/1.1 200 OK\n"
1035 "X-WebKit-CSP: default-src 'none'\n",
1036
1037 "HTTP/1/1 304 Not Modified\n"
1038 "X-WebKit-CSP: default-src *\n",
1039
1040 "HTTP/1.1 200 OK\n"
1041 "X-WebKit-CSP: default-src 'none'\n",
1042 },
1043 { "HTTP/1.1 200 OK\n"
1044 "X-XSS-Protection: 1\n",
1045
1046 "HTTP/1/1 304 Not Modified\n"
1047 "X-XSS-Protection: 0\n",
1048
1049 "HTTP/1.1 200 OK\n"
1050 "X-XSS-Protection: 1\n",
1051 },
1052 { "HTTP/1.1 200 OK\n",
1053
1054 "HTTP/1/1 304 Not Modified\n"
1055 "X-Content-Type-Options: nosniff\n",
1056
1057 "HTTP/1.1 200 OK\n"
1058 },
1059 };
1060
1061 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1062 UpdateTest,
1063 testing::ValuesIn(update_tests));
1064
1065 struct EnumerateHeaderTestData {
1066 const char* headers;
1067 const char* expected_lines;
1068 };
1069
1070 class EnumerateHeaderLinesTest
1071 : public HttpResponseHeadersTest,
1072 public ::testing::WithParamInterface<EnumerateHeaderTestData> {
1073 };
1074
1075 TEST_P(EnumerateHeaderLinesTest, EnumerateHeaderLines) {
1076 const EnumerateHeaderTestData test = GetParam();
1077
1078 std::string headers(test.headers);
1079 HeadersToRaw(&headers);
1080 scoped_refptr<net::HttpResponseHeaders> parsed(
1081 new net::HttpResponseHeaders(headers));
1082
1083 std::string name, value, lines;
1084
1085 void* iter = NULL;
1086 while (parsed->EnumerateHeaderLines(&iter, &name, &value)) {
1087 lines.append(name);
1088 lines.append(": ");
1089 lines.append(value);
1090 lines.append("\n");
926 } 1091 }
1092
1093 EXPECT_EQ(std::string(test.expected_lines), lines);
927 } 1094 }
928 1095
929 TEST(HttpResponseHeadersTest, Update) { 1096 const EnumerateHeaderTestData enumerate_header_tests[] = {
930 const struct { 1097 { "HTTP/1.1 200 OK\n",
931 const char* orig_headers; 1098
932 const char* new_headers; 1099 ""
933 const char* expected_headers; 1100 },
934 } tests[] = { 1101 { "HTTP/1.1 200 OK\n"
935 { "HTTP/1.1 200 OK\n", 1102 "Foo: 1\n",
936 1103
937 "HTTP/1/1 304 Not Modified\n" 1104 "Foo: 1\n"
938 "connection: keep-alive\n" 1105 },
939 "Cache-control: max-age=10000\n", 1106 { "HTTP/1.1 200 OK\n"
940 1107 "Foo: 1\n"
941 "HTTP/1.1 200 OK\n" 1108 "Bar: 2\n"
942 "Cache-control: max-age=10000\n" 1109 "Foo: 3\n",
943 }, 1110
944 { "HTTP/1.1 200 OK\n" 1111 "Foo: 1\nBar: 2\nFoo: 3\n"
945 "Foo: 1\n" 1112 },
946 "Cache-control: private\n", 1113 { "HTTP/1.1 200 OK\n"
947 1114 "Foo: 1, 2, 3\n",
948 "HTTP/1/1 304 Not Modified\n" 1115
949 "connection: keep-alive\n" 1116 "Foo: 1, 2, 3\n"
950 "Cache-control: max-age=10000\n", 1117 },
951 1118 };
952 "HTTP/1.1 200 OK\n" 1119
953 "Cache-control: max-age=10000\n" 1120 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
954 "Foo: 1\n" 1121 EnumerateHeaderLinesTest,
955 }, 1122 testing::ValuesIn(enumerate_header_tests));
956 { "HTTP/1.1 200 OK\n" 1123
957 "Foo: 1\n" 1124 struct IsRedirectTestData {
958 "Cache-control: private\n", 1125 const char* headers;
959 1126 const char* location;
960 "HTTP/1/1 304 Not Modified\n" 1127 bool is_redirect;
961 "connection: keep-alive\n" 1128 };
962 "Cache-CONTROL: max-age=10000\n", 1129
963 1130 class IsRedirectTest
964 "HTTP/1.1 200 OK\n" 1131 : public HttpResponseHeadersTest,
965 "Cache-CONTROL: max-age=10000\n" 1132 public ::testing::WithParamInterface<IsRedirectTestData> {
966 "Foo: 1\n" 1133 };
967 }, 1134
968 { "HTTP/1.1 200 OK\n" 1135 TEST_P(IsRedirectTest, IsRedirect) {
969 "Content-Length: 450\n", 1136 const IsRedirectTestData test = GetParam();
970 1137
971 "HTTP/1/1 304 Not Modified\n" 1138 std::string headers(test.headers);
972 "connection: keep-alive\n" 1139 HeadersToRaw(&headers);
973 "Cache-control: max-age=10001 \n", 1140 scoped_refptr<net::HttpResponseHeaders> parsed(
974 1141 new net::HttpResponseHeaders(headers));
975 "HTTP/1.1 200 OK\n" 1142
976 "Cache-control: max-age=10001\n" 1143 std::string location;
977 "Content-Length: 450\n" 1144 EXPECT_EQ(parsed->IsRedirect(&location), test.is_redirect);
978 }, 1145 EXPECT_EQ(location, test.location);
979 { "HTTP/1.1 200 OK\n" 1146 }
980 "X-Frame-Options: DENY\n", 1147
981 1148 const IsRedirectTestData is_redirect_tests[] = {
982 "HTTP/1/1 304 Not Modified\n" 1149 { "HTTP/1.1 200 OK\n",
983 "X-Frame-Options: ALLOW\n", 1150 "",
984 1151 false
985 "HTTP/1.1 200 OK\n" 1152 },
986 "X-Frame-Options: DENY\n", 1153 { "HTTP/1.1 301 Moved\n"
987 }, 1154 "Location: http://foopy/\n",
988 { "HTTP/1.1 200 OK\n" 1155 "http://foopy/",
989 "X-WebKit-CSP: default-src 'none'\n", 1156 true
990 1157 },
991 "HTTP/1/1 304 Not Modified\n" 1158 { "HTTP/1.1 301 Moved\n"
992 "X-WebKit-CSP: default-src *\n", 1159 "Location: \t \n",
993 1160 "",
994 "HTTP/1.1 200 OK\n" 1161 false
995 "X-WebKit-CSP: default-src 'none'\n", 1162 },
996 }, 1163 // We use the first location header as the target of the redirect.
997 { "HTTP/1.1 200 OK\n" 1164 { "HTTP/1.1 301 Moved\n"
998 "X-XSS-Protection: 1\n", 1165 "Location: http://foo/\n"
999 1166 "Location: http://bar/\n",
1000 "HTTP/1/1 304 Not Modified\n" 1167 "http://foo/",
1001 "X-XSS-Protection: 0\n", 1168 true
1002 1169 },
1003 "HTTP/1.1 200 OK\n" 1170 // We use the first _valid_ location header as the target of the redirect.
1004 "X-XSS-Protection: 1\n", 1171 { "HTTP/1.1 301 Moved\n"
1005 }, 1172 "Location: \n"
1006 { "HTTP/1.1 200 OK\n", 1173 "Location: http://bar/\n",
1007 1174 "http://bar/",
1008 "HTTP/1/1 304 Not Modified\n" 1175 true
1009 "X-Content-Type-Options: nosniff\n", 1176 },
1010 1177 // Bug 1050541 (location header with an unescaped comma).
1011 "HTTP/1.1 200 OK\n" 1178 { "HTTP/1.1 301 Moved\n"
1012 }, 1179 "Location: http://foo/bar,baz.html\n",
1013 }; 1180 "http://foo/bar,baz.html",
1014 1181 true
1015 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 1182 },
1016 std::string orig_headers(tests[i].orig_headers); 1183 // Bug 1224617 (location header with non-ASCII bytes).
1017 HeadersToRaw(&orig_headers); 1184 { "HTTP/1.1 301 Moved\n"
1018 scoped_refptr<net::HttpResponseHeaders> parsed( 1185 "Location: http://foo/bar?key=\xE4\xF6\xFC\n",
1019 new net::HttpResponseHeaders(orig_headers)); 1186 "http://foo/bar?key=%E4%F6%FC",
1020 1187 true
1021 std::string new_headers(tests[i].new_headers); 1188 },
1022 HeadersToRaw(&new_headers); 1189 // Shift_JIS, Big5, and GBK contain multibyte characters with the trailing
1023 scoped_refptr<net::HttpResponseHeaders> new_parsed( 1190 // byte falling in the ASCII range.
1024 new net::HttpResponseHeaders(new_headers)); 1191 { "HTTP/1.1 301 Moved\n"
1025 1192 "Location: http://foo/bar?key=\x81\x5E\xD8\xBF\n",
1026 parsed->Update(*new_parsed.get()); 1193 "http://foo/bar?key=%81^%D8%BF",
1027 1194 true
1028 std::string resulting_headers; 1195 },
1029 parsed->GetNormalizedHeaders(&resulting_headers); 1196 { "HTTP/1.1 301 Moved\n"
1030 EXPECT_EQ(std::string(tests[i].expected_headers), resulting_headers); 1197 "Location: http://foo/bar?key=\x82\x40\xBD\xC4\n",
1198 "http://foo/bar?key=%82@%BD%C4",
1199 true
1200 },
1201 { "HTTP/1.1 301 Moved\n"
1202 "Location: http://foo/bar?key=\x83\x5C\x82\x5D\xCB\xD7\n",
1203 "http://foo/bar?key=%83\\%82]%CB%D7",
1204 true
1205 },
1206 };
1207
1208 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1209 IsRedirectTest,
1210 testing::ValuesIn(is_redirect_tests));
1211
1212 struct ContentLengthTestData {
1213 const char* headers;
1214 int64 expected_len;
1215 };
1216
1217 class GetContentLengthTest
1218 : public HttpResponseHeadersTest,
1219 public ::testing::WithParamInterface<ContentLengthTestData> {
1220 };
1221
1222 TEST_P(GetContentLengthTest, GetContentLength) {
1223 const ContentLengthTestData test = GetParam();
1224
1225 std::string headers(test.headers);
1226 HeadersToRaw(&headers);
1227 scoped_refptr<net::HttpResponseHeaders> parsed(
1228 new net::HttpResponseHeaders(headers));
1229
1230 EXPECT_EQ(test.expected_len, parsed->GetContentLength());
1231 }
1232
1233 const ContentLengthTestData content_length_tests[] = {
1234 { "HTTP/1.1 200 OK\n",
1235 -1
1236 },
1237 { "HTTP/1.1 200 OK\n"
1238 "Content-Length: 10\n",
1239 10
1240 },
1241 { "HTTP/1.1 200 OK\n"
1242 "Content-Length: \n",
1243 -1
1244 },
1245 { "HTTP/1.1 200 OK\n"
1246 "Content-Length: abc\n",
1247 -1
1248 },
1249 { "HTTP/1.1 200 OK\n"
1250 "Content-Length: -10\n",
1251 -1
1252 },
1253 { "HTTP/1.1 200 OK\n"
1254 "Content-Length: +10\n",
1255 -1
1256 },
1257 { "HTTP/1.1 200 OK\n"
1258 "Content-Length: 23xb5\n",
1259 -1
1260 },
1261 { "HTTP/1.1 200 OK\n"
1262 "Content-Length: 0xA\n",
1263 -1
1264 },
1265 { "HTTP/1.1 200 OK\n"
1266 "Content-Length: 010\n",
1267 10
1268 },
1269 // Content-Length too big, will overflow an int64.
1270 { "HTTP/1.1 200 OK\n"
1271 "Content-Length: 40000000000000000000\n",
1272 -1
1273 },
1274 { "HTTP/1.1 200 OK\n"
1275 "Content-Length: 10\n",
1276 10
1277 },
1278 { "HTTP/1.1 200 OK\n"
1279 "Content-Length: 10 \n",
1280 10
1281 },
1282 { "HTTP/1.1 200 OK\n"
1283 "Content-Length: \t10\n",
1284 10
1285 },
1286 { "HTTP/1.1 200 OK\n"
1287 "Content-Length: \v10\n",
1288 -1
1289 },
1290 { "HTTP/1.1 200 OK\n"
1291 "Content-Length: \f10\n",
1292 -1
1293 },
1294 { "HTTP/1.1 200 OK\n"
1295 "cOnTeNt-LENgth: 33\n",
1296 33
1297 },
1298 { "HTTP/1.1 200 OK\n"
1299 "Content-Length: 34\r\n",
1300 -1
1301 },
1302 };
1303
1304 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1305 GetContentLengthTest,
1306 testing::ValuesIn(content_length_tests));
1307
1308 struct ContentRangeTestData {
1309 const char* headers;
1310 bool expected_return_value;
1311 int64 expected_first_byte_position;
1312 int64 expected_last_byte_position;
1313 int64 expected_instance_size;
1314 };
1315
1316 class ContentRangeTest
1317 : public HttpResponseHeadersTest,
1318 public ::testing::WithParamInterface<ContentRangeTestData> {
1319 };
1320
1321 TEST_P(ContentRangeTest, GetContentRange) {
1322 const ContentRangeTestData test = GetParam();
1323
1324 std::string headers(test.headers);
1325 HeadersToRaw(&headers);
1326 scoped_refptr<net::HttpResponseHeaders> parsed(
1327 new net::HttpResponseHeaders(headers));
1328
1329 int64 first_byte_position;
1330 int64 last_byte_position;
1331 int64 instance_size;
1332 bool return_value = parsed->GetContentRange(&first_byte_position,
1333 &last_byte_position,
1334 &instance_size);
1335 EXPECT_EQ(test.expected_return_value, return_value);
1336 EXPECT_EQ(test.expected_first_byte_position, first_byte_position);
1337 EXPECT_EQ(test.expected_last_byte_position, last_byte_position);
1338 EXPECT_EQ(test.expected_instance_size, instance_size);
1339 }
1340
1341 const ContentRangeTestData content_range_tests[] = {
1342 { "HTTP/1.1 206 Partial Content",
1343 false,
1344 -1,
1345 -1,
1346 -1
1347 },
1348 { "HTTP/1.1 206 Partial Content\n"
1349 "Content-Range:",
1350 false,
1351 -1,
1352 -1,
1353 -1
1354 },
1355 { "HTTP/1.1 206 Partial Content\n"
1356 "Content-Range: megabytes 0-10/50",
1357 false,
1358 -1,
1359 -1,
1360 -1
1361 },
1362 { "HTTP/1.1 206 Partial Content\n"
1363 "Content-Range: 0-10/50",
1364 false,
1365 -1,
1366 -1,
1367 -1
1368 },
1369 { "HTTP/1.1 206 Partial Content\n"
1370 "Content-Range: Bytes 0-50/51",
1371 true,
1372 0,
1373 50,
1374 51
1375 },
1376 { "HTTP/1.1 206 Partial Content\n"
1377 "Content-Range: bytes 0-50/51",
1378 true,
1379 0,
1380 50,
1381 51
1382 },
1383 { "HTTP/1.1 206 Partial Content\n"
1384 "Content-Range: bytes\t0-50/51",
1385 false,
1386 -1,
1387 -1,
1388 -1
1389 },
1390 { "HTTP/1.1 206 Partial Content\n"
1391 "Content-Range: bytes 0-50/51",
1392 true,
1393 0,
1394 50,
1395 51
1396 },
1397 { "HTTP/1.1 206 Partial Content\n"
1398 "Content-Range: bytes 0 - 50 \t / \t51",
1399 true,
1400 0,
1401 50,
1402 51
1403 },
1404 { "HTTP/1.1 206 Partial Content\n"
1405 "Content-Range: bytes 0\t-\t50\t/\t51\t",
1406 true,
1407 0,
1408 50,
1409 51
1410 },
1411 { "HTTP/1.1 206 Partial Content\n"
1412 "Content-Range: \tbytes\t\t\t 0\t-\t50\t/\t51\t",
1413 true,
1414 0,
1415 50,
1416 51
1417 },
1418 { "HTTP/1.1 206 Partial Content\n"
1419 "Content-Range: \t bytes \t 0 - 50 / 5 1",
1420 false,
1421 0,
1422 50,
1423 -1
1424 },
1425 { "HTTP/1.1 206 Partial Content\n"
1426 "Content-Range: \t bytes \t 0 - 5 0 / 51",
1427 false,
1428 -1,
1429 -1,
1430 -1
1431 },
1432 { "HTTP/1.1 206 Partial Content\n"
1433 "Content-Range: bytes 50-0/51",
1434 false,
1435 50,
1436 0,
1437 -1
1438 },
1439 { "HTTP/1.1 416 Requested range not satisfiable\n"
1440 "Content-Range: bytes * /*",
1441 false,
1442 -1,
1443 -1,
1444 -1
1445 },
1446 { "HTTP/1.1 416 Requested range not satisfiable\n"
1447 "Content-Range: bytes * / * ",
1448 false,
1449 -1,
1450 -1,
1451 -1
1452 },
1453 { "HTTP/1.1 206 Partial Content\n"
1454 "Content-Range: bytes 0-50/*",
1455 false,
1456 0,
1457 50,
1458 -1
1459 },
1460 { "HTTP/1.1 206 Partial Content\n"
1461 "Content-Range: bytes 0-50 / * ",
1462 false,
1463 0,
1464 50,
1465 -1
1466 },
1467 { "HTTP/1.1 206 Partial Content\n"
1468 "Content-Range: bytes 0-10000000000/10000000001",
1469 true,
1470 0,
1471 10000000000ll,
1472 10000000001ll
1473 },
1474 { "HTTP/1.1 206 Partial Content\n"
1475 "Content-Range: bytes 0-10000000000/10000000000",
1476 false,
1477 0,
1478 10000000000ll,
1479 10000000000ll
1480 },
1481 // 64 bit wraparound.
1482 { "HTTP/1.1 206 Partial Content\n"
1483 "Content-Range: bytes 0 - 9223372036854775807 / 100",
1484 false,
1485 0,
1486 kint64max,
1487 100
1488 },
1489 // 64 bit wraparound.
1490 { "HTTP/1.1 206 Partial Content\n"
1491 "Content-Range: bytes 0 - 100 / -9223372036854775808",
1492 false,
1493 0,
1494 100,
1495 kint64min
1496 },
1497 { "HTTP/1.1 206 Partial Content\n"
1498 "Content-Range: bytes */50",
1499 false,
1500 -1,
1501 -1,
1502 50
1503 },
1504 { "HTTP/1.1 206 Partial Content\n"
1505 "Content-Range: bytes 0-50/10",
1506 false,
1507 0,
1508 50,
1509 10
1510 },
1511 { "HTTP/1.1 206 Partial Content\n"
1512 "Content-Range: bytes 40-50/45",
1513 false,
1514 40,
1515 50,
1516 45
1517 },
1518 { "HTTP/1.1 206 Partial Content\n"
1519 "Content-Range: bytes 0-50/-10",
1520 false,
1521 0,
1522 50,
1523 -10
1524 },
1525 { "HTTP/1.1 206 Partial Content\n"
1526 "Content-Range: bytes 0-0/1",
1527 true,
1528 0,
1529 0,
1530 1
1531 },
1532 { "HTTP/1.1 206 Partial Content\n"
1533 "Content-Range: bytes 0-40000000000000000000/40000000000000000001",
1534 false,
1535 -1,
1536 -1,
1537 -1
1538 },
1539 { "HTTP/1.1 206 Partial Content\n"
1540 "Content-Range: bytes 1-/100",
1541 false,
1542 -1,
1543 -1,
1544 -1
1545 },
1546 { "HTTP/1.1 206 Partial Content\n"
1547 "Content-Range: bytes -/100",
1548 false,
1549 -1,
1550 -1,
1551 -1
1552 },
1553 { "HTTP/1.1 206 Partial Content\n"
1554 "Content-Range: bytes -1/100",
1555 false,
1556 -1,
1557 -1,
1558 -1
1559 },
1560 { "HTTP/1.1 206 Partial Content\n"
1561 "Content-Range: bytes 0-1233/*",
1562 false,
1563 0,
1564 1233,
1565 -1
1566 },
1567 { "HTTP/1.1 206 Partial Content\n"
1568 "Content-Range: bytes -123 - -1/100",
1569 false,
1570 -1,
1571 -1,
1572 -1
1573 },
1574 };
1575
1576 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1577 ContentRangeTest,
1578 testing::ValuesIn(content_range_tests));
1579
1580 struct KeepAliveTestData {
1581 const char* headers;
1582 bool expected_keep_alive;
1583 };
1584
1585 class IsKeepAliveTest
1586 : public HttpResponseHeadersTest,
1587 public ::testing::WithParamInterface<KeepAliveTestData> {
1588 };
1589
1590 TEST_P(IsKeepAliveTest, IsKeepAlive) {
1591 const KeepAliveTestData test = GetParam();
1592
1593 std::string headers(test.headers);
1594 HeadersToRaw(&headers);
1595 scoped_refptr<net::HttpResponseHeaders> parsed(
1596 new net::HttpResponseHeaders(headers));
1597
1598 EXPECT_EQ(test.expected_keep_alive, parsed->IsKeepAlive());
1599 }
1600
1601 const KeepAliveTestData keepalive_tests[] = {
1602 // The status line fabricated by HttpNetworkTransaction for a 0.9 response.
1603 // Treated as 0.9.
1604 { "HTTP/0.9 200 OK",
1605 false
1606 },
1607 // This could come from a broken server. Treated as 1.0 because it has a
1608 // header.
1609 { "HTTP/0.9 200 OK\n"
1610 "connection: keep-alive\n",
1611 true
1612 },
1613 { "HTTP/1.1 200 OK\n",
1614 true
1615 },
1616 { "HTTP/1.0 200 OK\n",
1617 false
1618 },
1619 { "HTTP/1.0 200 OK\n"
1620 "connection: close\n",
1621 false
1622 },
1623 { "HTTP/1.0 200 OK\n"
1624 "connection: keep-alive\n",
1625 true
1626 },
1627 { "HTTP/1.0 200 OK\n"
1628 "connection: kEeP-AliVe\n",
1629 true
1630 },
1631 { "HTTP/1.0 200 OK\n"
1632 "connection: keep-aliveX\n",
1633 false
1634 },
1635 { "HTTP/1.1 200 OK\n"
1636 "connection: close\n",
1637 false
1638 },
1639 { "HTTP/1.1 200 OK\n"
1640 "connection: keep-alive\n",
1641 true
1642 },
1643 { "HTTP/1.0 200 OK\n"
1644 "proxy-connection: close\n",
1645 false
1646 },
1647 { "HTTP/1.0 200 OK\n"
1648 "proxy-connection: keep-alive\n",
1649 true
1650 },
1651 { "HTTP/1.1 200 OK\n"
1652 "proxy-connection: close\n",
1653 false
1654 },
1655 { "HTTP/1.1 200 OK\n"
1656 "proxy-connection: keep-alive\n",
1657 true
1658 },
1659 };
1660
1661 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1662 IsKeepAliveTest,
1663 testing::ValuesIn(keepalive_tests));
1664
1665 struct HasStrongValidatorsTestData {
1666 const char* headers;
1667 bool expected_result;
1668 };
1669
1670 class HasStrongValidatorsTest
1671 : public HttpResponseHeadersTest,
1672 public ::testing::WithParamInterface<HasStrongValidatorsTestData> {
1673 };
1674
1675 TEST_P(HasStrongValidatorsTest, HasStrongValidators) {
1676 const HasStrongValidatorsTestData test = GetParam();
1677
1678 std::string headers(test.headers);
1679 HeadersToRaw(&headers);
1680 scoped_refptr<net::HttpResponseHeaders> parsed(
1681 new net::HttpResponseHeaders(headers));
1682
1683 EXPECT_EQ(test.expected_result, parsed->HasStrongValidators());
1684 }
1685
1686 const HasStrongValidatorsTestData strong_validators_tests[] = {
1687 { "HTTP/0.9 200 OK",
1688 false
1689 },
1690 { "HTTP/1.0 200 OK\n"
1691 "Date: Wed, 28 Nov 2007 01:40:10 GMT\n"
1692 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
1693 "ETag: \"foo\"\n",
1694 false
1695 },
1696 { "HTTP/1.1 200 OK\n"
1697 "Date: Wed, 28 Nov 2007 01:40:10 GMT\n"
1698 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
1699 "ETag: \"foo\"\n",
1700 true
1701 },
1702 { "HTTP/1.1 200 OK\n"
1703 "Date: Wed, 28 Nov 2007 00:41:10 GMT\n"
1704 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
1705 true
1706 },
1707 { "HTTP/1.1 200 OK\n"
1708 "Date: Wed, 28 Nov 2007 00:41:09 GMT\n"
1709 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
1710 false
1711 },
1712 { "HTTP/1.1 200 OK\n"
1713 "ETag: \"foo\"\n",
1714 true
1715 },
1716 // This is not really a weak etag:
1717 { "HTTP/1.1 200 OK\n"
1718 "etag: \"w/foo\"\n",
1719 true
1720 },
1721 // This is a weak etag:
1722 { "HTTP/1.1 200 OK\n"
1723 "etag: w/\"foo\"\n",
1724 false
1725 },
1726 { "HTTP/1.1 200 OK\n"
1727 "etag: W / \"foo\"\n",
1728 false
1031 } 1729 }
1032 } 1730 };
1033 1731
1034 TEST(HttpResponseHeadersTest, EnumerateHeaderLines) { 1732 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1035 const struct { 1733 HasStrongValidatorsTest,
1036 const char* headers; 1734 testing::ValuesIn(strong_validators_tests));
1037 const char* expected_lines;
1038 } tests[] = {
1039 { "HTTP/1.1 200 OK\n",
1040
1041 ""
1042 },
1043 { "HTTP/1.1 200 OK\n"
1044 "Foo: 1\n",
1045
1046 "Foo: 1\n"
1047 },
1048 { "HTTP/1.1 200 OK\n"
1049 "Foo: 1\n"
1050 "Bar: 2\n"
1051 "Foo: 3\n",
1052
1053 "Foo: 1\nBar: 2\nFoo: 3\n"
1054 },
1055 { "HTTP/1.1 200 OK\n"
1056 "Foo: 1, 2, 3\n",
1057
1058 "Foo: 1, 2, 3\n"
1059 },
1060 };
1061 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1062 std::string headers(tests[i].headers);
1063 HeadersToRaw(&headers);
1064 scoped_refptr<net::HttpResponseHeaders> parsed(
1065 new net::HttpResponseHeaders(headers));
1066
1067 std::string name, value, lines;
1068
1069 void* iter = NULL;
1070 while (parsed->EnumerateHeaderLines(&iter, &name, &value)) {
1071 lines.append(name);
1072 lines.append(": ");
1073 lines.append(value);
1074 lines.append("\n");
1075 }
1076
1077 EXPECT_EQ(std::string(tests[i].expected_lines), lines);
1078 }
1079 }
1080
1081 TEST(HttpResponseHeadersTest, IsRedirect) {
1082 const struct {
1083 const char* headers;
1084 const char* location;
1085 bool is_redirect;
1086 } tests[] = {
1087 { "HTTP/1.1 200 OK\n",
1088 "",
1089 false
1090 },
1091 { "HTTP/1.1 301 Moved\n"
1092 "Location: http://foopy/\n",
1093 "http://foopy/",
1094 true
1095 },
1096 { "HTTP/1.1 301 Moved\n"
1097 "Location: \t \n",
1098 "",
1099 false
1100 },
1101 // we use the first location header as the target of the redirect
1102 { "HTTP/1.1 301 Moved\n"
1103 "Location: http://foo/\n"
1104 "Location: http://bar/\n",
1105 "http://foo/",
1106 true
1107 },
1108 // we use the first _valid_ location header as the target of the redirect
1109 { "HTTP/1.1 301 Moved\n"
1110 "Location: \n"
1111 "Location: http://bar/\n",
1112 "http://bar/",
1113 true
1114 },
1115 // bug 1050541 (location header w/ an unescaped comma)
1116 { "HTTP/1.1 301 Moved\n"
1117 "Location: http://foo/bar,baz.html\n",
1118 "http://foo/bar,baz.html",
1119 true
1120 },
1121 // bug 1224617 (location header w/ non-ASCII bytes)
1122 { "HTTP/1.1 301 Moved\n"
1123 "Location: http://foo/bar?key=\xE4\xF6\xFC\n",
1124 "http://foo/bar?key=%E4%F6%FC",
1125 true
1126 },
1127 // Shift_JIS, Big5, and GBK contain multibyte characters with the trailing
1128 // byte falling in the ASCII range.
1129 { "HTTP/1.1 301 Moved\n"
1130 "Location: http://foo/bar?key=\x81\x5E\xD8\xBF\n",
1131 "http://foo/bar?key=%81^%D8%BF",
1132 true
1133 },
1134 { "HTTP/1.1 301 Moved\n"
1135 "Location: http://foo/bar?key=\x82\x40\xBD\xC4\n",
1136 "http://foo/bar?key=%82@%BD%C4",
1137 true
1138 },
1139 { "HTTP/1.1 301 Moved\n"
1140 "Location: http://foo/bar?key=\x83\x5C\x82\x5D\xCB\xD7\n",
1141 "http://foo/bar?key=%83\\%82]%CB%D7",
1142 true
1143 },
1144 };
1145 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1146 std::string headers(tests[i].headers);
1147 HeadersToRaw(&headers);
1148 scoped_refptr<net::HttpResponseHeaders> parsed(
1149 new net::HttpResponseHeaders(headers));
1150
1151 std::string location;
1152 EXPECT_EQ(parsed->IsRedirect(&location), tests[i].is_redirect);
1153 EXPECT_EQ(location, tests[i].location);
1154 }
1155 }
1156
1157 TEST(HttpResponseHeadersTest, GetContentLength) {
1158 const struct {
1159 const char* headers;
1160 int64 expected_len;
1161 } tests[] = {
1162 { "HTTP/1.1 200 OK\n",
1163 -1
1164 },
1165 { "HTTP/1.1 200 OK\n"
1166 "Content-Length: 10\n",
1167 10
1168 },
1169 { "HTTP/1.1 200 OK\n"
1170 "Content-Length: \n",
1171 -1
1172 },
1173 { "HTTP/1.1 200 OK\n"
1174 "Content-Length: abc\n",
1175 -1
1176 },
1177 { "HTTP/1.1 200 OK\n"
1178 "Content-Length: -10\n",
1179 -1
1180 },
1181 { "HTTP/1.1 200 OK\n"
1182 "Content-Length: +10\n",
1183 -1
1184 },
1185 { "HTTP/1.1 200 OK\n"
1186 "Content-Length: 23xb5\n",
1187 -1
1188 },
1189 { "HTTP/1.1 200 OK\n"
1190 "Content-Length: 0xA\n",
1191 -1
1192 },
1193 { "HTTP/1.1 200 OK\n"
1194 "Content-Length: 010\n",
1195 10
1196 },
1197 // Content-Length too big, will overflow an int64
1198 { "HTTP/1.1 200 OK\n"
1199 "Content-Length: 40000000000000000000\n",
1200 -1
1201 },
1202 { "HTTP/1.1 200 OK\n"
1203 "Content-Length: 10\n",
1204 10
1205 },
1206 { "HTTP/1.1 200 OK\n"
1207 "Content-Length: 10 \n",
1208 10
1209 },
1210 { "HTTP/1.1 200 OK\n"
1211 "Content-Length: \t10\n",
1212 10
1213 },
1214 { "HTTP/1.1 200 OK\n"
1215 "Content-Length: \v10\n",
1216 -1
1217 },
1218 { "HTTP/1.1 200 OK\n"
1219 "Content-Length: \f10\n",
1220 -1
1221 },
1222 { "HTTP/1.1 200 OK\n"
1223 "cOnTeNt-LENgth: 33\n",
1224 33
1225 },
1226 { "HTTP/1.1 200 OK\n"
1227 "Content-Length: 34\r\n",
1228 -1
1229 },
1230 };
1231 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1232 std::string headers(tests[i].headers);
1233 HeadersToRaw(&headers);
1234 scoped_refptr<net::HttpResponseHeaders> parsed(
1235 new net::HttpResponseHeaders(headers));
1236
1237 EXPECT_EQ(tests[i].expected_len, parsed->GetContentLength());
1238 }
1239 }
1240
1241 TEST(HttpResponseHeaders, GetContentRange) {
1242 const struct {
1243 const char* headers;
1244 bool expected_return_value;
1245 int64 expected_first_byte_position;
1246 int64 expected_last_byte_position;
1247 int64 expected_instance_size;
1248 } tests[] = {
1249 { "HTTP/1.1 206 Partial Content",
1250 false,
1251 -1,
1252 -1,
1253 -1
1254 },
1255 { "HTTP/1.1 206 Partial Content\n"
1256 "Content-Range:",
1257 false,
1258 -1,
1259 -1,
1260 -1
1261 },
1262 { "HTTP/1.1 206 Partial Content\n"
1263 "Content-Range: megabytes 0-10/50",
1264 false,
1265 -1,
1266 -1,
1267 -1
1268 },
1269 { "HTTP/1.1 206 Partial Content\n"
1270 "Content-Range: 0-10/50",
1271 false,
1272 -1,
1273 -1,
1274 -1
1275 },
1276 { "HTTP/1.1 206 Partial Content\n"
1277 "Content-Range: Bytes 0-50/51",
1278 true,
1279 0,
1280 50,
1281 51
1282 },
1283 { "HTTP/1.1 206 Partial Content\n"
1284 "Content-Range: bytes 0-50/51",
1285 true,
1286 0,
1287 50,
1288 51
1289 },
1290 { "HTTP/1.1 206 Partial Content\n"
1291 "Content-Range: bytes\t0-50/51",
1292 false,
1293 -1,
1294 -1,
1295 -1
1296 },
1297 { "HTTP/1.1 206 Partial Content\n"
1298 "Content-Range: bytes 0-50/51",
1299 true,
1300 0,
1301 50,
1302 51
1303 },
1304 { "HTTP/1.1 206 Partial Content\n"
1305 "Content-Range: bytes 0 - 50 \t / \t51",
1306 true,
1307 0,
1308 50,
1309 51
1310 },
1311 { "HTTP/1.1 206 Partial Content\n"
1312 "Content-Range: bytes 0\t-\t50\t/\t51\t",
1313 true,
1314 0,
1315 50,
1316 51
1317 },
1318 { "HTTP/1.1 206 Partial Content\n"
1319 "Content-Range: \tbytes\t\t\t 0\t-\t50\t/\t51\t",
1320 true,
1321 0,
1322 50,
1323 51
1324 },
1325 { "HTTP/1.1 206 Partial Content\n"
1326 "Content-Range: \t bytes \t 0 - 50 / 5 1",
1327 false,
1328 0,
1329 50,
1330 -1
1331 },
1332 { "HTTP/1.1 206 Partial Content\n"
1333 "Content-Range: \t bytes \t 0 - 5 0 / 51",
1334 false,
1335 -1,
1336 -1,
1337 -1
1338 },
1339 { "HTTP/1.1 206 Partial Content\n"
1340 "Content-Range: bytes 50-0/51",
1341 false,
1342 50,
1343 0,
1344 -1
1345 },
1346 { "HTTP/1.1 416 Requested range not satisfiable\n"
1347 "Content-Range: bytes * /*",
1348 false,
1349 -1,
1350 -1,
1351 -1
1352 },
1353 { "HTTP/1.1 416 Requested range not satisfiable\n"
1354 "Content-Range: bytes * / * ",
1355 false,
1356 -1,
1357 -1,
1358 -1
1359 },
1360 { "HTTP/1.1 206 Partial Content\n"
1361 "Content-Range: bytes 0-50/*",
1362 false,
1363 0,
1364 50,
1365 -1
1366 },
1367 { "HTTP/1.1 206 Partial Content\n"
1368 "Content-Range: bytes 0-50 / * ",
1369 false,
1370 0,
1371 50,
1372 -1
1373 },
1374 { "HTTP/1.1 206 Partial Content\n"
1375 "Content-Range: bytes 0-10000000000/10000000001",
1376 true,
1377 0,
1378 10000000000ll,
1379 10000000001ll
1380 },
1381 { "HTTP/1.1 206 Partial Content\n"
1382 "Content-Range: bytes 0-10000000000/10000000000",
1383 false,
1384 0,
1385 10000000000ll,
1386 10000000000ll
1387 },
1388 // 64 bits wraparound.
1389 { "HTTP/1.1 206 Partial Content\n"
1390 "Content-Range: bytes 0 - 9223372036854775807 / 100",
1391 false,
1392 0,
1393 kint64max,
1394 100
1395 },
1396 // 64 bits wraparound.
1397 { "HTTP/1.1 206 Partial Content\n"
1398 "Content-Range: bytes 0 - 100 / -9223372036854775808",
1399 false,
1400 0,
1401 100,
1402 kint64min
1403 },
1404 { "HTTP/1.1 206 Partial Content\n"
1405 "Content-Range: bytes */50",
1406 false,
1407 -1,
1408 -1,
1409 50
1410 },
1411 { "HTTP/1.1 206 Partial Content\n"
1412 "Content-Range: bytes 0-50/10",
1413 false,
1414 0,
1415 50,
1416 10
1417 },
1418 { "HTTP/1.1 206 Partial Content\n"
1419 "Content-Range: bytes 40-50/45",
1420 false,
1421 40,
1422 50,
1423 45
1424 },
1425 { "HTTP/1.1 206 Partial Content\n"
1426 "Content-Range: bytes 0-50/-10",
1427 false,
1428 0,
1429 50,
1430 -10
1431 },
1432 { "HTTP/1.1 206 Partial Content\n"
1433 "Content-Range: bytes 0-0/1",
1434 true,
1435 0,
1436 0,
1437 1
1438 },
1439 { "HTTP/1.1 206 Partial Content\n"
1440 "Content-Range: bytes 0-40000000000000000000/40000000000000000001",
1441 false,
1442 -1,
1443 -1,
1444 -1
1445 },
1446 { "HTTP/1.1 206 Partial Content\n"
1447 "Content-Range: bytes 1-/100",
1448 false,
1449 -1,
1450 -1,
1451 -1
1452 },
1453 { "HTTP/1.1 206 Partial Content\n"
1454 "Content-Range: bytes -/100",
1455 false,
1456 -1,
1457 -1,
1458 -1
1459 },
1460 { "HTTP/1.1 206 Partial Content\n"
1461 "Content-Range: bytes -1/100",
1462 false,
1463 -1,
1464 -1,
1465 -1
1466 },
1467 { "HTTP/1.1 206 Partial Content\n"
1468 "Content-Range: bytes 0-1233/*",
1469 false,
1470 0,
1471 1233,
1472 -1
1473 },
1474 { "HTTP/1.1 206 Partial Content\n"
1475 "Content-Range: bytes -123 - -1/100",
1476 false,
1477 -1,
1478 -1,
1479 -1
1480 },
1481 };
1482 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1483 std::string headers(tests[i].headers);
1484 HeadersToRaw(&headers);
1485 scoped_refptr<net::HttpResponseHeaders> parsed(
1486 new net::HttpResponseHeaders(headers));
1487
1488 int64 first_byte_position;
1489 int64 last_byte_position;
1490 int64 instance_size;
1491 bool return_value = parsed->GetContentRange(&first_byte_position,
1492 &last_byte_position,
1493 &instance_size);
1494 EXPECT_EQ(tests[i].expected_return_value, return_value);
1495 EXPECT_EQ(tests[i].expected_first_byte_position, first_byte_position);
1496 EXPECT_EQ(tests[i].expected_last_byte_position, last_byte_position);
1497 EXPECT_EQ(tests[i].expected_instance_size, instance_size);
1498 }
1499 }
1500
1501 TEST(HttpResponseHeadersTest, IsKeepAlive) {
1502 const struct {
1503 const char* headers;
1504 bool expected_keep_alive;
1505 } tests[] = {
1506 // The status line fabricated by HttpNetworkTransaction for a 0.9 response.
1507 // Treated as 0.9.
1508 { "HTTP/0.9 200 OK",
1509 false
1510 },
1511 // This could come from a broken server. Treated as 1.0 because it has a
1512 // header.
1513 { "HTTP/0.9 200 OK\n"
1514 "connection: keep-alive\n",
1515 true
1516 },
1517 { "HTTP/1.1 200 OK\n",
1518 true
1519 },
1520 { "HTTP/1.0 200 OK\n",
1521 false
1522 },
1523 { "HTTP/1.0 200 OK\n"
1524 "connection: close\n",
1525 false
1526 },
1527 { "HTTP/1.0 200 OK\n"
1528 "connection: keep-alive\n",
1529 true
1530 },
1531 { "HTTP/1.0 200 OK\n"
1532 "connection: kEeP-AliVe\n",
1533 true
1534 },
1535 { "HTTP/1.0 200 OK\n"
1536 "connection: keep-aliveX\n",
1537 false
1538 },
1539 { "HTTP/1.1 200 OK\n"
1540 "connection: close\n",
1541 false
1542 },
1543 { "HTTP/1.1 200 OK\n"
1544 "connection: keep-alive\n",
1545 true
1546 },
1547 { "HTTP/1.0 200 OK\n"
1548 "proxy-connection: close\n",
1549 false
1550 },
1551 { "HTTP/1.0 200 OK\n"
1552 "proxy-connection: keep-alive\n",
1553 true
1554 },
1555 { "HTTP/1.1 200 OK\n"
1556 "proxy-connection: close\n",
1557 false
1558 },
1559 { "HTTP/1.1 200 OK\n"
1560 "proxy-connection: keep-alive\n",
1561 true
1562 },
1563 };
1564 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1565 std::string headers(tests[i].headers);
1566 HeadersToRaw(&headers);
1567 scoped_refptr<net::HttpResponseHeaders> parsed(
1568 new net::HttpResponseHeaders(headers));
1569
1570 EXPECT_EQ(tests[i].expected_keep_alive, parsed->IsKeepAlive());
1571 }
1572 }
1573
1574 TEST(HttpResponseHeadersTest, HasStrongValidators) {
1575 const struct {
1576 const char* headers;
1577 bool expected_result;
1578 } tests[] = {
1579 { "HTTP/0.9 200 OK",
1580 false
1581 },
1582 { "HTTP/1.0 200 OK\n"
1583 "Date: Wed, 28 Nov 2007 01:40:10 GMT\n"
1584 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
1585 "ETag: \"foo\"\n",
1586 false
1587 },
1588 { "HTTP/1.1 200 OK\n"
1589 "Date: Wed, 28 Nov 2007 01:40:10 GMT\n"
1590 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n"
1591 "ETag: \"foo\"\n",
1592 true
1593 },
1594 { "HTTP/1.1 200 OK\n"
1595 "Date: Wed, 28 Nov 2007 00:41:10 GMT\n"
1596 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
1597 true
1598 },
1599 { "HTTP/1.1 200 OK\n"
1600 "Date: Wed, 28 Nov 2007 00:41:09 GMT\n"
1601 "Last-Modified: Wed, 28 Nov 2007 00:40:10 GMT\n",
1602 false
1603 },
1604 { "HTTP/1.1 200 OK\n"
1605 "ETag: \"foo\"\n",
1606 true
1607 },
1608 // This is not really a weak etag:
1609 { "HTTP/1.1 200 OK\n"
1610 "etag: \"w/foo\"\n",
1611 true
1612 },
1613 // This is a weak etag:
1614 { "HTTP/1.1 200 OK\n"
1615 "etag: w/\"foo\"\n",
1616 false
1617 },
1618 { "HTTP/1.1 200 OK\n"
1619 "etag: W / \"foo\"\n",
1620 false
1621 }
1622 };
1623 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1624 std::string headers(tests[i].headers);
1625 HeadersToRaw(&headers);
1626 scoped_refptr<net::HttpResponseHeaders> parsed(
1627 new net::HttpResponseHeaders(headers));
1628
1629 EXPECT_EQ(tests[i].expected_result, parsed->HasStrongValidators()) <<
1630 "Failed test case " << i;
1631 }
1632 }
1633 1735
1634 TEST(HttpResponseHeadersTest, GetStatusText) { 1736 TEST(HttpResponseHeadersTest, GetStatusText) {
1635 std::string headers("HTTP/1.1 404 Not Found"); 1737 std::string headers("HTTP/1.1 404 Not Found");
1636 HeadersToRaw(&headers); 1738 HeadersToRaw(&headers);
1637 scoped_refptr<net::HttpResponseHeaders> parsed( 1739 scoped_refptr<net::HttpResponseHeaders> parsed(
1638 new net::HttpResponseHeaders(headers)); 1740 new net::HttpResponseHeaders(headers));
1639 EXPECT_EQ(std::string("Not Found"), parsed->GetStatusText()); 1741 EXPECT_EQ(std::string("Not Found"), parsed->GetStatusText());
1640 } 1742 }
1641 1743
1642 TEST(HttpResponseHeadersTest, GetStatusTextMissing) { 1744 TEST(HttpResponseHeadersTest, GetStatusTextMissing) {
1643 std::string headers("HTTP/1.1 404"); 1745 std::string headers("HTTP/1.1 404");
1644 HeadersToRaw(&headers); 1746 HeadersToRaw(&headers);
1645 scoped_refptr<net::HttpResponseHeaders> parsed( 1747 scoped_refptr<net::HttpResponseHeaders> parsed(
1646 new net::HttpResponseHeaders(headers)); 1748 new net::HttpResponseHeaders(headers));
1647 // Since the status line gets normalized, we have OK 1749 // Since the status line gets normalized, we have OK.
1648 EXPECT_EQ(std::string("OK"), parsed->GetStatusText()); 1750 EXPECT_EQ(std::string("OK"), parsed->GetStatusText());
1649 } 1751 }
1650 1752
1651 TEST(HttpResponseHeadersTest, GetStatusTextMultiSpace) { 1753 TEST(HttpResponseHeadersTest, GetStatusTextMultiSpace) {
1652 std::string headers("HTTP/1.0 404 Not Found"); 1754 std::string headers("HTTP/1.0 404 Not Found");
1653 HeadersToRaw(&headers); 1755 HeadersToRaw(&headers);
1654 scoped_refptr<net::HttpResponseHeaders> parsed( 1756 scoped_refptr<net::HttpResponseHeaders> parsed(
1655 new net::HttpResponseHeaders(headers)); 1757 new net::HttpResponseHeaders(headers));
1656 EXPECT_EQ(std::string("Not Found"), parsed->GetStatusText()); 1758 EXPECT_EQ(std::string("Not Found"), parsed->GetStatusText());
1657 } 1759 }
1658 1760
1659 TEST(HttpResponseHeadersTest, GetStatusBadStatusLine) { 1761 TEST(HttpResponseHeadersTest, GetStatusBadStatusLine) {
1660 std::string headers("Foo bar."); 1762 std::string headers("Foo bar.");
1661 HeadersToRaw(&headers); 1763 HeadersToRaw(&headers);
1662 scoped_refptr<net::HttpResponseHeaders> parsed( 1764 scoped_refptr<net::HttpResponseHeaders> parsed(
1663 new net::HttpResponseHeaders(headers)); 1765 new net::HttpResponseHeaders(headers));
1664 // The bad status line would have gotten rewritten as 1766 // The bad status line would have gotten rewritten as
1665 // HTTP/1.0 200 OK. 1767 // HTTP/1.0 200 OK.
1666 EXPECT_EQ(std::string("OK"), parsed->GetStatusText()); 1768 EXPECT_EQ(std::string("OK"), parsed->GetStatusText());
1667 } 1769 }
1668 1770
1669 TEST(HttpResponseHeadersTest, AddHeader) { 1771 struct AddHeaderTestData {
1670 const struct { 1772 const char* orig_headers;
1671 const char* orig_headers; 1773 const char* new_header;
1672 const char* new_header; 1774 const char* expected_headers;
1673 const char* expected_headers; 1775 };
1674 } tests[] = { 1776
1675 { "HTTP/1.1 200 OK\n" 1777 class AddHeaderTest
1676 "connection: keep-alive\n" 1778 : public HttpResponseHeadersTest,
1677 "Cache-control: max-age=10000\n", 1779 public ::testing::WithParamInterface<AddHeaderTestData> {
1678 1780 };
1679 "Content-Length: 450", 1781
1680 1782 TEST_P(AddHeaderTest, AddHeader) {
1681 "HTTP/1.1 200 OK\n" 1783 const AddHeaderTestData test = GetParam();
1682 "connection: keep-alive\n" 1784
1683 "Cache-control: max-age=10000\n" 1785 std::string orig_headers(test.orig_headers);
1684 "Content-Length: 450\n" 1786 HeadersToRaw(&orig_headers);
1685 }, 1787 scoped_refptr<net::HttpResponseHeaders> parsed(
1686 { "HTTP/1.1 200 OK\n" 1788 new net::HttpResponseHeaders(orig_headers));
1687 "connection: keep-alive\n" 1789
1688 "Cache-control: max-age=10000 \n", 1790 std::string new_header(test.new_header);
1689 1791 parsed->AddHeader(new_header);
1690 "Content-Length: 450 ", 1792
1691 1793 std::string resulting_headers;
1692 "HTTP/1.1 200 OK\n" 1794 parsed->GetNormalizedHeaders(&resulting_headers);
1693 "connection: keep-alive\n" 1795 EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
1694 "Cache-control: max-age=10000\n" 1796 }
1695 "Content-Length: 450\n" 1797
1696 }, 1798 const AddHeaderTestData add_header_tests[] = {
1697 }; 1799 { "HTTP/1.1 200 OK\n"
1698 1800 "connection: keep-alive\n"
1699 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 1801 "Cache-control: max-age=10000\n",
1700 std::string orig_headers(tests[i].orig_headers); 1802
1701 HeadersToRaw(&orig_headers); 1803 "Content-Length: 450",
1702 scoped_refptr<net::HttpResponseHeaders> parsed( 1804
1703 new net::HttpResponseHeaders(orig_headers)); 1805 "HTTP/1.1 200 OK\n"
1704 1806 "connection: keep-alive\n"
1705 std::string new_header(tests[i].new_header); 1807 "Cache-control: max-age=10000\n"
1706 parsed->AddHeader(new_header); 1808 "Content-Length: 450\n"
1707 1809 },
1708 std::string resulting_headers; 1810 { "HTTP/1.1 200 OK\n"
1709 parsed->GetNormalizedHeaders(&resulting_headers); 1811 "connection: keep-alive\n"
1710 EXPECT_EQ(std::string(tests[i].expected_headers), resulting_headers); 1812 "Cache-control: max-age=10000 \n",
1711 } 1813
1712 } 1814 "Content-Length: 450 ",
1713 1815
1714 TEST(HttpResponseHeadersTest, RemoveHeader) { 1816 "HTTP/1.1 200 OK\n"
1715 const struct { 1817 "connection: keep-alive\n"
1716 const char* orig_headers; 1818 "Cache-control: max-age=10000\n"
1717 const char* to_remove; 1819 "Content-Length: 450\n"
1718 const char* expected_headers; 1820 },
1719 } tests[] = { 1821 };
1720 { "HTTP/1.1 200 OK\n" 1822
1721 "connection: keep-alive\n" 1823 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1722 "Cache-control: max-age=10000\n" 1824 AddHeaderTest,
1723 "Content-Length: 450\n", 1825 testing::ValuesIn(add_header_tests));
1724 1826
1725 "Content-Length", 1827 struct RemoveHeaderTestData {
1726 1828 const char* orig_headers;
1727 "HTTP/1.1 200 OK\n" 1829 const char* to_remove;
1728 "connection: keep-alive\n" 1830 const char* expected_headers;
1729 "Cache-control: max-age=10000\n" 1831 };
1730 }, 1832
1731 { "HTTP/1.1 200 OK\n" 1833 class RemoveHeaderTest
1732 "connection: keep-alive \n" 1834 : public HttpResponseHeadersTest,
1733 "Content-Length : 450 \n" 1835 public ::testing::WithParamInterface<RemoveHeaderTestData> {
1734 "Cache-control: max-age=10000\n", 1836 };
1735 1837
1736 "Content-Length", 1838 TEST_P(RemoveHeaderTest, RemoveHeader) {
1737 1839 const RemoveHeaderTestData test = GetParam();
1738 "HTTP/1.1 200 OK\n" 1840
1739 "connection: keep-alive\n" 1841 std::string orig_headers(test.orig_headers);
1740 "Cache-control: max-age=10000\n" 1842 HeadersToRaw(&orig_headers);
1741 }, 1843 scoped_refptr<net::HttpResponseHeaders> parsed(
1742 }; 1844 new net::HttpResponseHeaders(orig_headers));
1743 1845
1744 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 1846 std::string name(test.to_remove);
1745 std::string orig_headers(tests[i].orig_headers); 1847 parsed->RemoveHeader(name);
1746 HeadersToRaw(&orig_headers); 1848
1747 scoped_refptr<net::HttpResponseHeaders> parsed( 1849 std::string resulting_headers;
1748 new net::HttpResponseHeaders(orig_headers)); 1850 parsed->GetNormalizedHeaders(&resulting_headers);
1749 1851 EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
1750 std::string name(tests[i].to_remove); 1852 }
1751 parsed->RemoveHeader(name); 1853
1752 1854 const RemoveHeaderTestData remove_header_tests[] = {
1753 std::string resulting_headers; 1855 { "HTTP/1.1 200 OK\n"
1754 parsed->GetNormalizedHeaders(&resulting_headers); 1856 "connection: keep-alive\n"
1755 EXPECT_EQ(std::string(tests[i].expected_headers), resulting_headers); 1857 "Cache-control: max-age=10000\n"
1756 } 1858 "Content-Length: 450\n",
1757 } 1859
1758 1860 "Content-Length",
1759 TEST(HttpResponseHeadersTest, RemoveIndividualHeader) { 1861
1760 const struct { 1862 "HTTP/1.1 200 OK\n"
1761 const char* orig_headers; 1863 "connection: keep-alive\n"
1762 const char* to_remove_name; 1864 "Cache-control: max-age=10000\n"
1763 const char* to_remove_value; 1865 },
1764 const char* expected_headers; 1866 { "HTTP/1.1 200 OK\n"
1765 } tests[] = { 1867 "connection: keep-alive \n"
1766 { "HTTP/1.1 200 OK\n" 1868 "Content-Length : 450 \n"
1767 "connection: keep-alive\n" 1869 "Cache-control: max-age=10000\n",
1768 "Cache-control: max-age=10000\n" 1870
1769 "Content-Length: 450\n", 1871 "Content-Length",
1770 1872
1771 "Content-Length", 1873 "HTTP/1.1 200 OK\n"
1772 1874 "connection: keep-alive\n"
1773 "450", 1875 "Cache-control: max-age=10000\n"
1774 1876 },
1775 "HTTP/1.1 200 OK\n" 1877 };
1776 "connection: keep-alive\n" 1878
1777 "Cache-control: max-age=10000\n" 1879 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1778 }, 1880 RemoveHeaderTest,
1779 { "HTTP/1.1 200 OK\n" 1881 testing::ValuesIn(remove_header_tests));
1780 "connection: keep-alive \n" 1882
1781 "Content-Length : 450 \n" 1883 struct RemoveIndividualHeaderTestData {
1782 "Cache-control: max-age=10000\n", 1884 const char* orig_headers;
1783 1885 const char* to_remove_name;
1784 "Content-Length", 1886 const char* to_remove_value;
1785 1887 const char* expected_headers;
1786 "450", 1888 };
1787 1889
1788 "HTTP/1.1 200 OK\n" 1890 class RemoveIndividualHeaderTest
1789 "connection: keep-alive\n" 1891 : public HttpResponseHeadersTest,
1790 "Cache-control: max-age=10000\n" 1892 public ::testing::WithParamInterface<RemoveIndividualHeaderTestData> {
1791 }, 1893 };
1792 { "HTTP/1.1 200 OK\n" 1894
1793 "connection: keep-alive \n" 1895 TEST_P(RemoveIndividualHeaderTest, RemoveIndividualHeader) {
1794 "Content-Length: 450\n" 1896 const RemoveIndividualHeaderTestData test = GetParam();
1795 "Cache-control: max-age=10000\n", 1897
1796 1898 std::string orig_headers(test.orig_headers);
1797 "Content-Length", // Matching name. 1899 HeadersToRaw(&orig_headers);
1798 1900 scoped_refptr<net::HttpResponseHeaders> parsed(
1799 "999", // Mismatching value. 1901 new net::HttpResponseHeaders(orig_headers));
1800 1902
1801 "HTTP/1.1 200 OK\n" 1903 std::string name(test.to_remove_name);
1802 "connection: keep-alive\n" 1904 std::string value(test.to_remove_value);
1803 "Content-Length: 450\n" 1905 parsed->RemoveHeaderLine(name, value);
1804 "Cache-control: max-age=10000\n" 1906
1805 }, 1907 std::string resulting_headers;
1806 { "HTTP/1.1 200 OK\n" 1908 parsed->GetNormalizedHeaders(&resulting_headers);
1807 "connection: keep-alive \n" 1909 EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
1808 "Foo: bar, baz\n" 1910 }
1809 "Foo: bar\n" 1911
1810 "Cache-control: max-age=10000\n", 1912 const RemoveIndividualHeaderTestData remove_individual_header_tests[] = {
1811 1913 { "HTTP/1.1 200 OK\n"
1812 "Foo", 1914 "connection: keep-alive\n"
1813 1915 "Cache-control: max-age=10000\n"
1814 "bar, baz", // Space in value. 1916 "Content-Length: 450\n",
1815 1917
1816 "HTTP/1.1 200 OK\n" 1918 "Content-Length",
1817 "connection: keep-alive\n" 1919
1818 "Foo: bar\n" 1920 "450",
1819 "Cache-control: max-age=10000\n" 1921
1820 }, 1922 "HTTP/1.1 200 OK\n"
1821 { "HTTP/1.1 200 OK\n" 1923 "connection: keep-alive\n"
1822 "connection: keep-alive \n" 1924 "Cache-control: max-age=10000\n"
1823 "Foo: bar, baz\n" 1925 },
1824 "Cache-control: max-age=10000\n", 1926 { "HTTP/1.1 200 OK\n"
1825 1927 "connection: keep-alive \n"
1826 "Foo", 1928 "Content-Length : 450 \n"
1827 1929 "Cache-control: max-age=10000\n",
1828 "baz", // Only partial match -> ignored. 1930
1829 1931 "Content-Length",
1830 "HTTP/1.1 200 OK\n" 1932
1831 "connection: keep-alive\n" 1933 "450",
1832 "Foo: bar, baz\n" 1934
1833 "Cache-control: max-age=10000\n" 1935 "HTTP/1.1 200 OK\n"
1834 }, 1936 "connection: keep-alive\n"
1835 }; 1937 "Cache-control: max-age=10000\n"
1836 1938 },
1837 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 1939 { "HTTP/1.1 200 OK\n"
1838 std::string orig_headers(tests[i].orig_headers); 1940 "connection: keep-alive \n"
1839 HeadersToRaw(&orig_headers); 1941 "Content-Length: 450\n"
1840 scoped_refptr<net::HttpResponseHeaders> parsed( 1942 "Cache-control: max-age=10000\n",
1841 new net::HttpResponseHeaders(orig_headers)); 1943
1842 1944 "Content-Length", // Matching name.
1843 std::string name(tests[i].to_remove_name); 1945
1844 std::string value(tests[i].to_remove_value); 1946 "999", // Mismatching value.
1845 parsed->RemoveHeaderLine(name, value); 1947
1846 1948 "HTTP/1.1 200 OK\n"
1847 std::string resulting_headers; 1949 "connection: keep-alive\n"
1848 parsed->GetNormalizedHeaders(&resulting_headers); 1950 "Content-Length: 450\n"
1849 EXPECT_EQ(std::string(tests[i].expected_headers), resulting_headers); 1951 "Cache-control: max-age=10000\n"
1850 } 1952 },
1851 } 1953 { "HTTP/1.1 200 OK\n"
1852 1954 "connection: keep-alive \n"
1853 TEST(HttpResponseHeadersTest, ReplaceStatus) { 1955 "Foo: bar, baz\n"
1854 const struct { 1956 "Foo: bar\n"
1855 const char* orig_headers; 1957 "Cache-control: max-age=10000\n",
1856 const char* new_status; 1958
1857 const char* expected_headers; 1959 "Foo",
1858 } tests[] = { 1960
1859 { "HTTP/1.1 206 Partial Content\n" 1961 "bar, baz", // Space in value.
1860 "connection: keep-alive\n" 1962
1861 "Cache-control: max-age=10000\n" 1963 "HTTP/1.1 200 OK\n"
1862 "Content-Length: 450\n", 1964 "connection: keep-alive\n"
1863 1965 "Foo: bar\n"
1864 "HTTP/1.1 200 OK", 1966 "Cache-control: max-age=10000\n"
1865 1967 },
1866 "HTTP/1.1 200 OK\n" 1968 { "HTTP/1.1 200 OK\n"
1867 "connection: keep-alive\n" 1969 "connection: keep-alive \n"
1868 "Cache-control: max-age=10000\n" 1970 "Foo: bar, baz\n"
1869 "Content-Length: 450\n" 1971 "Cache-control: max-age=10000\n",
1870 }, 1972
1871 { "HTTP/1.1 200 OK\n" 1973 "Foo",
1872 "connection: keep-alive\n", 1974
1873 1975 "baz", // Only partial match -> ignored.
1874 "HTTP/1.1 304 Not Modified", 1976
1875 1977 "HTTP/1.1 200 OK\n"
1876 "HTTP/1.1 304 Not Modified\n" 1978 "connection: keep-alive\n"
1877 "connection: keep-alive\n" 1979 "Foo: bar, baz\n"
1878 }, 1980 "Cache-control: max-age=10000\n"
1879 { "HTTP/1.1 200 OK\n" 1981 },
1880 "connection: keep-alive \n" 1982 };
1881 "Content-Length : 450 \n" 1983
1882 "Cache-control: max-age=10000\n", 1984 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
1883 1985 RemoveIndividualHeaderTest,
1884 "HTTP/1//1 304 Not Modified", 1986 testing::ValuesIn(remove_individual_header_tests));
1885 1987
1886 "HTTP/1.0 304 Not Modified\n" 1988 struct ReplaceStatusTestData {
1887 "connection: keep-alive\n" 1989 const char* orig_headers;
1888 "Content-Length: 450\n" 1990 const char* new_status;
1889 "Cache-control: max-age=10000\n" 1991 const char* expected_headers;
1890 }, 1992 };
1891 }; 1993
1892 1994 class ReplaceStatusTest
1893 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 1995 : public HttpResponseHeadersTest,
1894 std::string orig_headers(tests[i].orig_headers); 1996 public ::testing::WithParamInterface<ReplaceStatusTestData> {
1895 HeadersToRaw(&orig_headers); 1997 };
1896 scoped_refptr<net::HttpResponseHeaders> parsed( 1998
1897 new net::HttpResponseHeaders(orig_headers)); 1999 TEST_P(ReplaceStatusTest, ReplaceStatus) {
1898 2000 const ReplaceStatusTestData test = GetParam();
1899 std::string name(tests[i].new_status); 2001
1900 parsed->ReplaceStatusLine(name); 2002 std::string orig_headers(test.orig_headers);
1901 2003 HeadersToRaw(&orig_headers);
1902 std::string resulting_headers; 2004 scoped_refptr<net::HttpResponseHeaders> parsed(
1903 parsed->GetNormalizedHeaders(&resulting_headers); 2005 new net::HttpResponseHeaders(orig_headers));
1904 EXPECT_EQ(std::string(tests[i].expected_headers), resulting_headers); 2006
1905 } 2007 std::string name(test.new_status);
1906 } 2008 parsed->ReplaceStatusLine(name);
1907 2009
1908 TEST(HttpResponseHeadersTest, UpdateWithNewRange) { 2010 std::string resulting_headers;
1909 const struct { 2011 parsed->GetNormalizedHeaders(&resulting_headers);
1910 const char* orig_headers; 2012 EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
1911 const char* expected_headers; 2013 }
1912 const char* expected_headers_with_replaced_status; 2014
1913 } tests[] = { 2015 const ReplaceStatusTestData replace_status_tests[] = {
1914 { "HTTP/1.1 200 OK\n" 2016 { "HTTP/1.1 206 Partial Content\n"
1915 "Content-Length: 450\n", 2017 "connection: keep-alive\n"
1916 2018 "Cache-control: max-age=10000\n"
1917 "HTTP/1.1 200 OK\n" 2019 "Content-Length: 450\n",
1918 "Content-Range: bytes 3-5/450\n" 2020
1919 "Content-Length: 3\n", 2021 "HTTP/1.1 200 OK",
1920 2022
1921 "HTTP/1.1 206 Partial Content\n" 2023 "HTTP/1.1 200 OK\n"
1922 "Content-Range: bytes 3-5/450\n" 2024 "connection: keep-alive\n"
1923 "Content-Length: 3\n", 2025 "Cache-control: max-age=10000\n"
1924 }, 2026 "Content-Length: 450\n"
1925 { "HTTP/1.1 200 OK\n" 2027 },
1926 "Content-Length: 5\n", 2028 { "HTTP/1.1 200 OK\n"
1927 2029 "connection: keep-alive\n",
1928 "HTTP/1.1 200 OK\n" 2030
1929 "Content-Range: bytes 3-5/5\n" 2031 "HTTP/1.1 304 Not Modified",
1930 "Content-Length: 3\n", 2032
1931 2033 "HTTP/1.1 304 Not Modified\n"
1932 "HTTP/1.1 206 Partial Content\n" 2034 "connection: keep-alive\n"
1933 "Content-Range: bytes 3-5/5\n" 2035 },
1934 "Content-Length: 3\n", 2036 { "HTTP/1.1 200 OK\n"
1935 }, 2037 "connection: keep-alive \n"
1936 }; 2038 "Content-Length : 450 \n"
2039 "Cache-control: max-age=10000\n",
2040
2041 "HTTP/1//1 304 Not Modified",
2042
2043 "HTTP/1.0 304 Not Modified\n"
2044 "connection: keep-alive\n"
2045 "Content-Length: 450\n"
2046 "Cache-control: max-age=10000\n"
2047 },
2048 };
2049
2050 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
2051 ReplaceStatusTest,
2052 testing::ValuesIn(replace_status_tests));
2053
2054 struct UpdateWithNewRangeTestData {
2055 const char* orig_headers;
2056 const char* expected_headers;
2057 const char* expected_headers_with_replaced_status;
2058 };
2059
2060 class UpdateWithNewRangeTest
2061 : public HttpResponseHeadersTest,
2062 public ::testing::WithParamInterface<UpdateWithNewRangeTestData> {
2063 };
2064
2065 TEST_P(UpdateWithNewRangeTest, UpdateWithNewRange) {
2066 const UpdateWithNewRangeTestData test = GetParam();
2067
1937 const net::HttpByteRange range = net::HttpByteRange::Bounded(3, 5); 2068 const net::HttpByteRange range = net::HttpByteRange::Bounded(3, 5);
1938 2069
1939 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 2070 std::string orig_headers(test.orig_headers);
1940 std::string orig_headers(tests[i].orig_headers); 2071 std::replace(orig_headers.begin(), orig_headers.end(), '\n', '\0');
1941 std::replace(orig_headers.begin(), orig_headers.end(), '\n', '\0'); 2072 scoped_refptr<net::HttpResponseHeaders> parsed(
1942 scoped_refptr<net::HttpResponseHeaders> parsed( 2073 new net::HttpResponseHeaders(orig_headers + '\0'));
1943 new net::HttpResponseHeaders(orig_headers + '\0')); 2074 int64 content_size = parsed->GetContentLength();
1944 int64 content_size = parsed->GetContentLength(); 2075 std::string resulting_headers;
1945 std::string resulting_headers; 2076
1946 2077 // Update headers without replacing status line.
1947 // Update headers without replacing status line. 2078 parsed->UpdateWithNewRange(range, content_size, false);
1948 parsed->UpdateWithNewRange(range, content_size, false); 2079 parsed->GetNormalizedHeaders(&resulting_headers);
1949 parsed->GetNormalizedHeaders(&resulting_headers); 2080 EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
1950 EXPECT_EQ(std::string(tests[i].expected_headers), resulting_headers); 2081
1951 2082 // Replace status line too.
1952 // Replace status line too. 2083 parsed->UpdateWithNewRange(range, content_size, true);
1953 parsed->UpdateWithNewRange(range, content_size, true); 2084 parsed->GetNormalizedHeaders(&resulting_headers);
1954 parsed->GetNormalizedHeaders(&resulting_headers); 2085 EXPECT_EQ(std::string(test.expected_headers_with_replaced_status),
1955 EXPECT_EQ(std::string(tests[i].expected_headers_with_replaced_status), 2086 resulting_headers);
1956 resulting_headers); 2087 }
1957 } 2088
1958 } 2089 const UpdateWithNewRangeTestData update_range_tests[] = {
2090 { "HTTP/1.1 200 OK\n"
2091 "Content-Length: 450\n",
2092
2093 "HTTP/1.1 200 OK\n"
2094 "Content-Range: bytes 3-5/450\n"
2095 "Content-Length: 3\n",
2096
2097 "HTTP/1.1 206 Partial Content\n"
2098 "Content-Range: bytes 3-5/450\n"
2099 "Content-Length: 3\n",
2100 },
2101 { "HTTP/1.1 200 OK\n"
2102 "Content-Length: 5\n",
2103
2104 "HTTP/1.1 200 OK\n"
2105 "Content-Range: bytes 3-5/5\n"
2106 "Content-Length: 3\n",
2107
2108 "HTTP/1.1 206 Partial Content\n"
2109 "Content-Range: bytes 3-5/5\n"
2110 "Content-Length: 3\n",
2111 },
2112 };
2113
2114 INSTANTIATE_TEST_CASE_P(HttpResponseHeaders,
2115 UpdateWithNewRangeTest,
2116 testing::ValuesIn(update_range_tests));
1959 2117
1960 TEST(HttpResponseHeadersTest, ToNetLogParamAndBackAgain) { 2118 TEST(HttpResponseHeadersTest, ToNetLogParamAndBackAgain) {
1961 std::string headers("HTTP/1.1 404\n" 2119 std::string headers("HTTP/1.1 404\n"
1962 "Content-Length: 450\n" 2120 "Content-Length: 450\n"
1963 "Connection: keep-alive\n"); 2121 "Connection: keep-alive\n");
1964 HeadersToRaw(&headers); 2122 HeadersToRaw(&headers);
1965 scoped_refptr<net::HttpResponseHeaders> parsed( 2123 scoped_refptr<net::HttpResponseHeaders> parsed(
1966 new net::HttpResponseHeaders(headers)); 2124 new net::HttpResponseHeaders(headers));
1967 2125
1968 scoped_ptr<base::Value> event_param( 2126 scoped_ptr<base::Value> event_param(
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2004 InitializeHeadersWithCacheControl("max-age = 7"); 2162 InitializeHeadersWithCacheControl("max-age = 7");
2005 EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer())); 2163 EXPECT_FALSE(headers()->GetMaxAgeValue(TimeDeltaPointer()));
2006 } 2164 }
2007 2165
2008 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeFirstMatchUsed) { 2166 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeFirstMatchUsed) {
2009 InitializeHeadersWithCacheControl("max-age=10, max-age=20"); 2167 InitializeHeadersWithCacheControl("max-age=10, max-age=20");
2010 EXPECT_EQ(TimeDelta::FromSeconds(10), GetMaxAgeValue()); 2168 EXPECT_EQ(TimeDelta::FromSeconds(10), GetMaxAgeValue());
2011 } 2169 }
2012 2170
2013 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeBogusFirstMatchUsed) { 2171 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeBogusFirstMatchUsed) {
2014 // max-age10 isn't parsed as max-age; max-age=now is parsed as max-age=0 and 2172 // "max-age10" isn't parsed as "max-age"; "max-age=now" is parsed as
2015 // so max-age=20 is not used. 2173 // "max-age=0" and so "max-age=20" is not used.
2016 InitializeHeadersWithCacheControl("max-age10, max-age=now, max-age=20"); 2174 InitializeHeadersWithCacheControl("max-age10, max-age=now, max-age=20");
2017 EXPECT_EQ(TimeDelta::FromSeconds(0), GetMaxAgeValue()); 2175 EXPECT_EQ(TimeDelta::FromSeconds(0), GetMaxAgeValue());
2018 } 2176 }
2019 2177
2020 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeCaseInsensitive) { 2178 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeCaseInsensitive) {
2021 InitializeHeadersWithCacheControl("Max-aGe=15"); 2179 InitializeHeadersWithCacheControl("Max-aGe=15");
2022 EXPECT_EQ(TimeDelta::FromSeconds(15), GetMaxAgeValue()); 2180 EXPECT_EQ(TimeDelta::FromSeconds(15), GetMaxAgeValue());
2023 } 2181 }
2024 2182
2025 TEST_F(HttpResponseHeadersCacheControlTest, MaxAgeEdgeCases) { 2183 struct MaxAgeTestData {
2026 // This test doesn't use TEST_P() for consistency with the rest of the tests 2184 const char* max_age_string;
2027 // in this file. 2185 const int64 expected_seconds;
2028 // TODO(ricea): Port the tests in this file to use TEST_P(). 2186 };
2029 const struct { 2187
2030 const char* max_age_string; 2188 class MaxAgeEdgeCasesTest
2031 int64 expected_seconds; 2189 : public HttpResponseHeadersCacheControlTest,
2032 } tests[] = { 2190 public ::testing::WithParamInterface<MaxAgeTestData> {
2033 {" 1 ", 1}, // Spaces are ignored 2191 };
2034 {"-1", -1}, // Negative numbers are passed through 2192
2035 {"--1", 0}, // Leading junk gives 0 2193 TEST_P(MaxAgeEdgeCasesTest, MaxAgeEdgeCases) {
2036 {"2s", 2}, // trailing junk is ignored 2194 const MaxAgeTestData test = GetParam();
2037 {"3 days", 3}, 2195
2038 {"'4'", 0}, // single quotes don't work
2039 {"\"5\"", 0}, // double quotes don't work
2040 {"0x6", 0}, // hex not parsed as hex
2041 {"7F", 7}, // hex without 0x still not parsed as hex
2042 {"010", 10}, // octal not parsed as octal
2043 {"9223372036854", 9223372036854},
2044 // {"9223372036855", -9223372036854}, // undefined behaviour
2045 // {"9223372036854775806", -2}, // undefined behaviour
2046 {"9223372036854775807", 9223372036854775807},
2047 {"20000000000000000000",
2048 std::numeric_limits<int64>::max()}, // overflow int64
2049 };
2050 std::string max_age = "max-age="; 2196 std::string max_age = "max-age=";
2051 for (size_t i = 0; i < arraysize(tests); ++i) { 2197 InitializeHeadersWithCacheControl(
2052 InitializeHeadersWithCacheControl( 2198 (max_age + test.max_age_string).c_str());
2053 (max_age + tests[i].max_age_string).c_str()); 2199 EXPECT_EQ(test.expected_seconds, GetMaxAgeValue().InSeconds())
2054 EXPECT_EQ(tests[i].expected_seconds, GetMaxAgeValue().InSeconds()) 2200 << " for max-age=" << test.max_age_string;
2055 << " for max-age=" << tests[i].max_age_string;
2056 }
2057 } 2201 }
2058 2202
2203 const MaxAgeTestData max_age_tests[] = {
2204 {" 1 ", 1}, // Spaces are ignored.
2205 {"-1", -1}, // Negative numbers are passed through.
2206 {"--1", 0}, // Leading junk gives 0.
2207 {"2s", 2}, // Trailing junk is ignored.
2208 {"3 days", 3},
2209 {"'4'", 0}, // Single quotes don't work.
2210 {"\"5\"", 0}, // Double quotes don't work.
2211 {"0x6", 0}, // Hex not parsed as hex.
2212 {"7F", 7}, // Hex without 0x still not parsed as hex.
2213 {"010", 10}, // Octal not parsed as octal.
2214 {"9223372036854", 9223372036854},
2215 // {"9223372036855", -9223372036854}, // Undefined behaviour.
2216 // {"9223372036854775806", -2}, // Undefined behaviour.
2217 {"9223372036854775807", 9223372036854775807},
2218 {"20000000000000000000",
2219 std::numeric_limits<int64>::max()}, // Overflow int64.
2220 };
2221
2222 INSTANTIATE_TEST_CASE_P(HttpResponseHeadersCacheControl,
2223 MaxAgeEdgeCasesTest,
2224 testing::ValuesIn(max_age_tests));
2225
2059 TEST_F(HttpResponseHeadersCacheControlTest, 2226 TEST_F(HttpResponseHeadersCacheControlTest,
2060 AbsentStaleWhileRevalidateReturnsFalse) { 2227 AbsentStaleWhileRevalidateReturnsFalse) {
2061 InitializeHeadersWithCacheControl("max-age=3600"); 2228 InitializeHeadersWithCacheControl("max-age=3600");
2062 EXPECT_FALSE(headers()->GetStaleWhileRevalidateValue(TimeDeltaPointer())); 2229 EXPECT_FALSE(headers()->GetStaleWhileRevalidateValue(TimeDeltaPointer()));
2063 } 2230 }
2064 2231
2065 TEST_F(HttpResponseHeadersCacheControlTest, 2232 TEST_F(HttpResponseHeadersCacheControlTest,
2066 StaleWhileRevalidateWithoutValueRejected) { 2233 StaleWhileRevalidateWithoutValueRejected) {
2067 InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate="); 2234 InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=");
2068 EXPECT_FALSE(headers()->GetStaleWhileRevalidateValue(TimeDeltaPointer())); 2235 EXPECT_FALSE(headers()->GetStaleWhileRevalidateValue(TimeDeltaPointer()));
2069 } 2236 }
2070 2237
2071 TEST_F(HttpResponseHeadersCacheControlTest, 2238 TEST_F(HttpResponseHeadersCacheControlTest,
2072 StaleWhileRevalidateWithInvalidValueTreatedAsZero) { 2239 StaleWhileRevalidateWithInvalidValueTreatedAsZero) {
2073 InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=true"); 2240 InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=true");
2074 EXPECT_EQ(TimeDelta(), GetStaleWhileRevalidateValue()); 2241 EXPECT_EQ(TimeDelta(), GetStaleWhileRevalidateValue());
2075 } 2242 }
2076 2243
2077 TEST_F(HttpResponseHeadersCacheControlTest, StaleWhileRevalidateValueReturned) { 2244 TEST_F(HttpResponseHeadersCacheControlTest, StaleWhileRevalidateValueReturned) {
2078 InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=7200"); 2245 InitializeHeadersWithCacheControl("max-age=3600,stale-while-revalidate=7200");
2079 EXPECT_EQ(TimeDelta::FromSeconds(7200), GetStaleWhileRevalidateValue()); 2246 EXPECT_EQ(TimeDelta::FromSeconds(7200), GetStaleWhileRevalidateValue());
2080 } 2247 }
2081 2248
2082 TEST_F(HttpResponseHeadersCacheControlTest, 2249 TEST_F(HttpResponseHeadersCacheControlTest,
2083 FirstStaleWhileRevalidateValueUsed) { 2250 FirstStaleWhileRevalidateValueUsed) {
2084 InitializeHeadersWithCacheControl( 2251 InitializeHeadersWithCacheControl(
2085 "stale-while-revalidate=1,stale-while-revalidate=7200"); 2252 "stale-while-revalidate=1,stale-while-revalidate=7200");
2086 EXPECT_EQ(TimeDelta::FromSeconds(1), GetStaleWhileRevalidateValue()); 2253 EXPECT_EQ(TimeDelta::FromSeconds(1), GetStaleWhileRevalidateValue());
2087 } 2254 }
2255
2256 } // end namespace
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698