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

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