| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <algorithm> | |
| 6 | |
| 7 #include "base/basictypes.h" | |
| 8 #include "base/strings/string_util.h" | |
| 9 #include "net/http/http_util.h" | |
| 10 #include "testing/gtest/include/gtest/gtest.h" | |
| 11 | |
| 12 using net::HttpUtil; | |
| 13 | |
| 14 namespace { | |
| 15 class HttpUtilTest : public testing::Test {}; | |
| 16 } | |
| 17 | |
| 18 TEST(HttpUtilTest, IsSafeHeader) { | |
| 19 static const char* const unsafe_headers[] = { | |
| 20 "sec-", | |
| 21 "sEc-", | |
| 22 "sec-foo", | |
| 23 "sEc-FoO", | |
| 24 "proxy-", | |
| 25 "pRoXy-", | |
| 26 "proxy-foo", | |
| 27 "pRoXy-FoO", | |
| 28 "accept-charset", | |
| 29 "accept-encoding", | |
| 30 "access-control-request-headers", | |
| 31 "access-control-request-method", | |
| 32 "connection", | |
| 33 "content-length", | |
| 34 "cookie", | |
| 35 "cookie2", | |
| 36 "content-transfer-encoding", | |
| 37 "date", | |
| 38 "expect", | |
| 39 "host", | |
| 40 "keep-alive", | |
| 41 "origin", | |
| 42 "referer", | |
| 43 "te", | |
| 44 "trailer", | |
| 45 "transfer-encoding", | |
| 46 "upgrade", | |
| 47 "user-agent", | |
| 48 "via", | |
| 49 }; | |
| 50 for (size_t i = 0; i < arraysize(unsafe_headers); ++i) { | |
| 51 EXPECT_FALSE(HttpUtil::IsSafeHeader(unsafe_headers[i])) | |
| 52 << unsafe_headers[i]; | |
| 53 EXPECT_FALSE(HttpUtil::IsSafeHeader(StringToUpperASCII(std::string( | |
| 54 unsafe_headers[i])))) << unsafe_headers[i]; | |
| 55 } | |
| 56 static const char* const safe_headers[] = { | |
| 57 "foo", | |
| 58 "x-", | |
| 59 "x-foo", | |
| 60 "content-disposition", | |
| 61 "update", | |
| 62 "accept-charseta", | |
| 63 "accept_charset", | |
| 64 "accept-encodinga", | |
| 65 "accept_encoding", | |
| 66 "access-control-request-headersa", | |
| 67 "access-control-request-header", | |
| 68 "access_control_request_header", | |
| 69 "access-control-request-methoda", | |
| 70 "access_control_request_method", | |
| 71 "connectiona", | |
| 72 "content-lengtha", | |
| 73 "content_length", | |
| 74 "cookiea", | |
| 75 "cookie2a", | |
| 76 "cookie3", | |
| 77 "content-transfer-encodinga", | |
| 78 "content_transfer_encoding", | |
| 79 "datea", | |
| 80 "expecta", | |
| 81 "hosta", | |
| 82 "keep-alivea", | |
| 83 "keep_alive", | |
| 84 "origina", | |
| 85 "referera", | |
| 86 "referrer", | |
| 87 "tea", | |
| 88 "trailera", | |
| 89 "transfer-encodinga", | |
| 90 "transfer_encoding", | |
| 91 "upgradea", | |
| 92 "user-agenta", | |
| 93 "user_agent", | |
| 94 "viaa", | |
| 95 }; | |
| 96 for (size_t i = 0; i < arraysize(safe_headers); ++i) { | |
| 97 EXPECT_TRUE(HttpUtil::IsSafeHeader(safe_headers[i])) << safe_headers[i]; | |
| 98 EXPECT_TRUE(HttpUtil::IsSafeHeader(StringToUpperASCII(std::string( | |
| 99 safe_headers[i])))) << safe_headers[i]; | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 TEST(HttpUtilTest, HasHeader) { | |
| 104 static const struct { | |
| 105 const char* const headers; | |
| 106 const char* const name; | |
| 107 bool expected_result; | |
| 108 } tests[] = { | |
| 109 { "", "foo", false }, | |
| 110 { "foo\r\nbar", "foo", false }, | |
| 111 { "ffoo: 1", "foo", false }, | |
| 112 { "foo: 1", "foo", true }, | |
| 113 { "foo: 1\r\nbar: 2", "foo", true }, | |
| 114 { "fOO: 1\r\nbar: 2", "foo", true }, | |
| 115 { "g: 0\r\nfoo: 1\r\nbar: 2", "foo", true }, | |
| 116 }; | |
| 117 for (size_t i = 0; i < arraysize(tests); ++i) { | |
| 118 bool result = HttpUtil::HasHeader(tests[i].headers, tests[i].name); | |
| 119 EXPECT_EQ(tests[i].expected_result, result); | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 TEST(HttpUtilTest, StripHeaders) { | |
| 124 static const char* const headers = | |
| 125 "Origin: origin\r\n" | |
| 126 "Content-Type: text/plain\r\n" | |
| 127 "Cookies: foo1\r\n" | |
| 128 "Custom: baz\r\n" | |
| 129 "COOKIES: foo2\r\n" | |
| 130 "Server: Apache\r\n" | |
| 131 "OrIGin: origin2\r\n"; | |
| 132 | |
| 133 static const char* const header_names[] = { | |
| 134 "origin", "content-type", "cookies" | |
| 135 }; | |
| 136 | |
| 137 static const char* const expected_stripped_headers = | |
| 138 "Custom: baz\r\n" | |
| 139 "Server: Apache\r\n"; | |
| 140 | |
| 141 EXPECT_EQ(expected_stripped_headers, | |
| 142 HttpUtil::StripHeaders(headers, header_names, | |
| 143 arraysize(header_names))); | |
| 144 } | |
| 145 | |
| 146 TEST(HttpUtilTest, HeadersIterator) { | |
| 147 std::string headers = "foo: 1\t\r\nbar: hello world\r\nbaz: 3 \r\n"; | |
| 148 | |
| 149 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); | |
| 150 | |
| 151 ASSERT_TRUE(it.GetNext()); | |
| 152 EXPECT_EQ(std::string("foo"), it.name()); | |
| 153 EXPECT_EQ(std::string("1"), it.values()); | |
| 154 | |
| 155 ASSERT_TRUE(it.GetNext()); | |
| 156 EXPECT_EQ(std::string("bar"), it.name()); | |
| 157 EXPECT_EQ(std::string("hello world"), it.values()); | |
| 158 | |
| 159 ASSERT_TRUE(it.GetNext()); | |
| 160 EXPECT_EQ(std::string("baz"), it.name()); | |
| 161 EXPECT_EQ(std::string("3"), it.values()); | |
| 162 | |
| 163 EXPECT_FALSE(it.GetNext()); | |
| 164 } | |
| 165 | |
| 166 TEST(HttpUtilTest, HeadersIterator_MalformedLine) { | |
| 167 std::string headers = "foo: 1\n: 2\n3\nbar: 4"; | |
| 168 | |
| 169 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\n"); | |
| 170 | |
| 171 ASSERT_TRUE(it.GetNext()); | |
| 172 EXPECT_EQ(std::string("foo"), it.name()); | |
| 173 EXPECT_EQ(std::string("1"), it.values()); | |
| 174 | |
| 175 ASSERT_TRUE(it.GetNext()); | |
| 176 EXPECT_EQ(std::string("bar"), it.name()); | |
| 177 EXPECT_EQ(std::string("4"), it.values()); | |
| 178 | |
| 179 EXPECT_FALSE(it.GetNext()); | |
| 180 } | |
| 181 | |
| 182 TEST(HttpUtilTest, HeadersIterator_AdvanceTo) { | |
| 183 std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4"; | |
| 184 | |
| 185 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); | |
| 186 EXPECT_TRUE(it.AdvanceTo("foo")); | |
| 187 EXPECT_EQ("foo", it.name()); | |
| 188 EXPECT_TRUE(it.AdvanceTo("bar")); | |
| 189 EXPECT_EQ("bar", it.name()); | |
| 190 EXPECT_FALSE(it.AdvanceTo("blat")); | |
| 191 EXPECT_FALSE(it.GetNext()); // should be at end of headers | |
| 192 } | |
| 193 | |
| 194 TEST(HttpUtilTest, HeadersIterator_Reset) { | |
| 195 std::string headers = "foo: 1\r\n: 2\r\n3\r\nbar: 4"; | |
| 196 HttpUtil::HeadersIterator it(headers.begin(), headers.end(), "\r\n"); | |
| 197 // Search past "foo". | |
| 198 EXPECT_TRUE(it.AdvanceTo("bar")); | |
| 199 // Now try advancing to "foo". This time it should fail since the iterator | |
| 200 // position is past it. | |
| 201 EXPECT_FALSE(it.AdvanceTo("foo")); | |
| 202 it.Reset(); | |
| 203 // Now that we reset the iterator position, we should find 'foo' | |
| 204 EXPECT_TRUE(it.AdvanceTo("foo")); | |
| 205 } | |
| 206 | |
| 207 TEST(HttpUtilTest, ValuesIterator) { | |
| 208 std::string values = " must-revalidate, no-cache=\"foo, bar\"\t, private "; | |
| 209 | |
| 210 HttpUtil::ValuesIterator it(values.begin(), values.end(), ','); | |
| 211 | |
| 212 ASSERT_TRUE(it.GetNext()); | |
| 213 EXPECT_EQ(std::string("must-revalidate"), it.value()); | |
| 214 | |
| 215 ASSERT_TRUE(it.GetNext()); | |
| 216 EXPECT_EQ(std::string("no-cache=\"foo, bar\""), it.value()); | |
| 217 | |
| 218 ASSERT_TRUE(it.GetNext()); | |
| 219 EXPECT_EQ(std::string("private"), it.value()); | |
| 220 | |
| 221 EXPECT_FALSE(it.GetNext()); | |
| 222 } | |
| 223 | |
| 224 TEST(HttpUtilTest, ValuesIterator_Blanks) { | |
| 225 std::string values = " \t "; | |
| 226 | |
| 227 HttpUtil::ValuesIterator it(values.begin(), values.end(), ','); | |
| 228 | |
| 229 EXPECT_FALSE(it.GetNext()); | |
| 230 } | |
| 231 | |
| 232 TEST(HttpUtilTest, Unquote) { | |
| 233 // Replace <backslash> " with ". | |
| 234 EXPECT_STREQ("xyz\"abc", HttpUtil::Unquote("\"xyz\\\"abc\"").c_str()); | |
| 235 | |
| 236 // Replace <backslash> <backslash> with <backslash> | |
| 237 EXPECT_STREQ("xyz\\abc", HttpUtil::Unquote("\"xyz\\\\abc\"").c_str()); | |
| 238 EXPECT_STREQ("xyz\\\\\\abc", | |
| 239 HttpUtil::Unquote("\"xyz\\\\\\\\\\\\abc\"").c_str()); | |
| 240 | |
| 241 // Replace <backslash> X with X | |
| 242 EXPECT_STREQ("xyzXabc", HttpUtil::Unquote("\"xyz\\Xabc\"").c_str()); | |
| 243 | |
| 244 // Act as identity function on unquoted inputs. | |
| 245 EXPECT_STREQ("X", HttpUtil::Unquote("X").c_str()); | |
| 246 EXPECT_STREQ("\"", HttpUtil::Unquote("\"").c_str()); | |
| 247 | |
| 248 // Allow single quotes to act as quote marks. | |
| 249 // Not part of RFC 2616. | |
| 250 EXPECT_STREQ("x\"", HttpUtil::Unquote("'x\"'").c_str()); | |
| 251 } | |
| 252 | |
| 253 TEST(HttpUtilTest, Quote) { | |
| 254 EXPECT_STREQ("\"xyz\\\"abc\"", HttpUtil::Quote("xyz\"abc").c_str()); | |
| 255 | |
| 256 // Replace <backslash> <backslash> with <backslash> | |
| 257 EXPECT_STREQ("\"xyz\\\\abc\"", HttpUtil::Quote("xyz\\abc").c_str()); | |
| 258 | |
| 259 // Replace <backslash> X with X | |
| 260 EXPECT_STREQ("\"xyzXabc\"", HttpUtil::Quote("xyzXabc").c_str()); | |
| 261 } | |
| 262 | |
| 263 TEST(HttpUtilTest, LocateEndOfHeaders) { | |
| 264 struct { | |
| 265 const char* const input; | |
| 266 int expected_result; | |
| 267 } tests[] = { | |
| 268 { "foo\r\nbar\r\n\r\n", 12 }, | |
| 269 { "foo\nbar\n\n", 9 }, | |
| 270 { "foo\r\nbar\r\n\r\njunk", 12 }, | |
| 271 { "foo\nbar\n\njunk", 9 }, | |
| 272 { "foo\nbar\n\r\njunk", 10 }, | |
| 273 { "foo\nbar\r\n\njunk", 10 }, | |
| 274 }; | |
| 275 for (size_t i = 0; i < arraysize(tests); ++i) { | |
| 276 int input_len = static_cast<int>(strlen(tests[i].input)); | |
| 277 int eoh = HttpUtil::LocateEndOfHeaders(tests[i].input, input_len); | |
| 278 EXPECT_EQ(tests[i].expected_result, eoh); | |
| 279 } | |
| 280 } | |
| 281 | |
| 282 TEST(HttpUtilTest, AssembleRawHeaders) { | |
| 283 struct { | |
| 284 const char* const input; // with '|' representing '\0' | |
| 285 const char* const expected_result; // with '\0' changed to '|' | |
| 286 } tests[] = { | |
| 287 { "HTTP/1.0 200 OK\r\nFoo: 1\r\nBar: 2\r\n\r\n", | |
| 288 "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" }, | |
| 289 | |
| 290 { "HTTP/1.0 200 OK\nFoo: 1\nBar: 2\n\n", | |
| 291 "HTTP/1.0 200 OK|Foo: 1|Bar: 2||" }, | |
| 292 | |
| 293 // Valid line continuation (single SP). | |
| 294 { | |
| 295 "HTTP/1.0 200 OK\n" | |
| 296 "Foo: 1\n" | |
| 297 " continuation\n" | |
| 298 "Bar: 2\n\n", | |
| 299 | |
| 300 "HTTP/1.0 200 OK|" | |
| 301 "Foo: 1 continuation|" | |
| 302 "Bar: 2||" | |
| 303 }, | |
| 304 | |
| 305 // Valid line continuation (single HT). | |
| 306 { | |
| 307 "HTTP/1.0 200 OK\n" | |
| 308 "Foo: 1\n" | |
| 309 "\tcontinuation\n" | |
| 310 "Bar: 2\n\n", | |
| 311 | |
| 312 "HTTP/1.0 200 OK|" | |
| 313 "Foo: 1 continuation|" | |
| 314 "Bar: 2||" | |
| 315 }, | |
| 316 | |
| 317 // Valid line continuation (multiple SP). | |
| 318 { | |
| 319 "HTTP/1.0 200 OK\n" | |
| 320 "Foo: 1\n" | |
| 321 " continuation\n" | |
| 322 "Bar: 2\n\n", | |
| 323 | |
| 324 "HTTP/1.0 200 OK|" | |
| 325 "Foo: 1 continuation|" | |
| 326 "Bar: 2||" | |
| 327 }, | |
| 328 | |
| 329 // Valid line continuation (multiple HT). | |
| 330 { | |
| 331 "HTTP/1.0 200 OK\n" | |
| 332 "Foo: 1\n" | |
| 333 "\t\t\tcontinuation\n" | |
| 334 "Bar: 2\n\n", | |
| 335 | |
| 336 "HTTP/1.0 200 OK|" | |
| 337 "Foo: 1 continuation|" | |
| 338 "Bar: 2||" | |
| 339 }, | |
| 340 | |
| 341 // Valid line continuation (mixed HT, SP). | |
| 342 { | |
| 343 "HTTP/1.0 200 OK\n" | |
| 344 "Foo: 1\n" | |
| 345 " \t \t continuation\n" | |
| 346 "Bar: 2\n\n", | |
| 347 | |
| 348 "HTTP/1.0 200 OK|" | |
| 349 "Foo: 1 continuation|" | |
| 350 "Bar: 2||" | |
| 351 }, | |
| 352 | |
| 353 // Valid multi-line continuation | |
| 354 { | |
| 355 "HTTP/1.0 200 OK\n" | |
| 356 "Foo: 1\n" | |
| 357 " continuation1\n" | |
| 358 "\tcontinuation2\n" | |
| 359 " continuation3\n" | |
| 360 "Bar: 2\n\n", | |
| 361 | |
| 362 "HTTP/1.0 200 OK|" | |
| 363 "Foo: 1 continuation1 continuation2 continuation3|" | |
| 364 "Bar: 2||" | |
| 365 }, | |
| 366 | |
| 367 // Continuation of quoted value. | |
| 368 // This is different from what Firefox does, since it | |
| 369 // will preserve the LWS. | |
| 370 { | |
| 371 "HTTP/1.0 200 OK\n" | |
| 372 "Etag: \"34534-d3\n" | |
| 373 " 134q\"\n" | |
| 374 "Bar: 2\n\n", | |
| 375 | |
| 376 "HTTP/1.0 200 OK|" | |
| 377 "Etag: \"34534-d3 134q\"|" | |
| 378 "Bar: 2||" | |
| 379 }, | |
| 380 | |
| 381 // Valid multi-line continuation, full LWS lines | |
| 382 { | |
| 383 "HTTP/1.0 200 OK\n" | |
| 384 "Foo: 1\n" | |
| 385 " \n" | |
| 386 "\t\t\t\t\n" | |
| 387 "\t continuation\n" | |
| 388 "Bar: 2\n\n", | |
| 389 | |
| 390 // One SP per continued line = 3. | |
| 391 "HTTP/1.0 200 OK|" | |
| 392 "Foo: 1 continuation|" | |
| 393 "Bar: 2||" | |
| 394 }, | |
| 395 | |
| 396 // Valid multi-line continuation, all LWS | |
| 397 { | |
| 398 "HTTP/1.0 200 OK\n" | |
| 399 "Foo: 1\n" | |
| 400 " \n" | |
| 401 "\t\t\t\t\n" | |
| 402 "\t \n" | |
| 403 "Bar: 2\n\n", | |
| 404 | |
| 405 // One SP per continued line = 3. | |
| 406 "HTTP/1.0 200 OK|" | |
| 407 "Foo: 1 |" | |
| 408 "Bar: 2||" | |
| 409 }, | |
| 410 | |
| 411 // Valid line continuation (No value bytes in first line). | |
| 412 { | |
| 413 "HTTP/1.0 200 OK\n" | |
| 414 "Foo:\n" | |
| 415 " value\n" | |
| 416 "Bar: 2\n\n", | |
| 417 | |
| 418 "HTTP/1.0 200 OK|" | |
| 419 "Foo: value|" | |
| 420 "Bar: 2||" | |
| 421 }, | |
| 422 | |
| 423 // Not a line continuation (can't continue status line). | |
| 424 { | |
| 425 "HTTP/1.0 200 OK\n" | |
| 426 " Foo: 1\n" | |
| 427 "Bar: 2\n\n", | |
| 428 | |
| 429 "HTTP/1.0 200 OK|" | |
| 430 " Foo: 1|" | |
| 431 "Bar: 2||" | |
| 432 }, | |
| 433 | |
| 434 // Not a line continuation (can't continue status line). | |
| 435 { | |
| 436 "HTTP/1.0\n" | |
| 437 " 200 OK\n" | |
| 438 "Foo: 1\n" | |
| 439 "Bar: 2\n\n", | |
| 440 | |
| 441 "HTTP/1.0|" | |
| 442 " 200 OK|" | |
| 443 "Foo: 1|" | |
| 444 "Bar: 2||" | |
| 445 }, | |
| 446 | |
| 447 // Not a line continuation (can't continue status line). | |
| 448 { | |
| 449 "HTTP/1.0 404\n" | |
| 450 " Not Found\n" | |
| 451 "Foo: 1\n" | |
| 452 "Bar: 2\n\n", | |
| 453 | |
| 454 "HTTP/1.0 404|" | |
| 455 " Not Found|" | |
| 456 "Foo: 1|" | |
| 457 "Bar: 2||" | |
| 458 }, | |
| 459 | |
| 460 // Unterminated status line. | |
| 461 { | |
| 462 "HTTP/1.0 200 OK", | |
| 463 | |
| 464 "HTTP/1.0 200 OK||" | |
| 465 }, | |
| 466 | |
| 467 // Single terminated, with headers | |
| 468 { | |
| 469 "HTTP/1.0 200 OK\n" | |
| 470 "Foo: 1\n" | |
| 471 "Bar: 2\n", | |
| 472 | |
| 473 "HTTP/1.0 200 OK|" | |
| 474 "Foo: 1|" | |
| 475 "Bar: 2||" | |
| 476 }, | |
| 477 | |
| 478 // Not terminated, with headers | |
| 479 { | |
| 480 "HTTP/1.0 200 OK\n" | |
| 481 "Foo: 1\n" | |
| 482 "Bar: 2", | |
| 483 | |
| 484 "HTTP/1.0 200 OK|" | |
| 485 "Foo: 1|" | |
| 486 "Bar: 2||" | |
| 487 }, | |
| 488 | |
| 489 // Not a line continuation (VT) | |
| 490 { | |
| 491 "HTTP/1.0 200 OK\n" | |
| 492 "Foo: 1\n" | |
| 493 "\vInvalidContinuation\n" | |
| 494 "Bar: 2\n\n", | |
| 495 | |
| 496 "HTTP/1.0 200 OK|" | |
| 497 "Foo: 1|" | |
| 498 "\vInvalidContinuation|" | |
| 499 "Bar: 2||" | |
| 500 }, | |
| 501 | |
| 502 // Not a line continuation (formfeed) | |
| 503 { | |
| 504 "HTTP/1.0 200 OK\n" | |
| 505 "Foo: 1\n" | |
| 506 "\fInvalidContinuation\n" | |
| 507 "Bar: 2\n\n", | |
| 508 | |
| 509 "HTTP/1.0 200 OK|" | |
| 510 "Foo: 1|" | |
| 511 "\fInvalidContinuation|" | |
| 512 "Bar: 2||" | |
| 513 }, | |
| 514 | |
| 515 // Not a line continuation -- can't continue header names. | |
| 516 { | |
| 517 "HTTP/1.0 200 OK\n" | |
| 518 "Serv\n" | |
| 519 " er: Apache\n" | |
| 520 "\tInvalidContinuation\n" | |
| 521 "Bar: 2\n\n", | |
| 522 | |
| 523 "HTTP/1.0 200 OK|" | |
| 524 "Serv|" | |
| 525 " er: Apache|" | |
| 526 "\tInvalidContinuation|" | |
| 527 "Bar: 2||" | |
| 528 }, | |
| 529 | |
| 530 // Not a line continuation -- no value to continue. | |
| 531 { | |
| 532 "HTTP/1.0 200 OK\n" | |
| 533 "Foo: 1\n" | |
| 534 "garbage\n" | |
| 535 " not-a-continuation\n" | |
| 536 "Bar: 2\n\n", | |
| 537 | |
| 538 "HTTP/1.0 200 OK|" | |
| 539 "Foo: 1|" | |
| 540 "garbage|" | |
| 541 " not-a-continuation|" | |
| 542 "Bar: 2||", | |
| 543 }, | |
| 544 | |
| 545 // Not a line continuation -- no valid name. | |
| 546 { | |
| 547 "HTTP/1.0 200 OK\n" | |
| 548 ": 1\n" | |
| 549 " garbage\n" | |
| 550 "Bar: 2\n\n", | |
| 551 | |
| 552 "HTTP/1.0 200 OK|" | |
| 553 ": 1|" | |
| 554 " garbage|" | |
| 555 "Bar: 2||", | |
| 556 }, | |
| 557 | |
| 558 // Not a line continuation -- no valid name (whitespace) | |
| 559 { | |
| 560 "HTTP/1.0 200 OK\n" | |
| 561 " : 1\n" | |
| 562 " garbage\n" | |
| 563 "Bar: 2\n\n", | |
| 564 | |
| 565 "HTTP/1.0 200 OK|" | |
| 566 " : 1|" | |
| 567 " garbage|" | |
| 568 "Bar: 2||", | |
| 569 }, | |
| 570 | |
| 571 // Embed NULLs in the status line. They should not be understood | |
| 572 // as line separators. | |
| 573 { | |
| 574 "HTTP/1.0 200 OK|Bar2:0|Baz2:1\r\nFoo: 1\r\nBar: 2\r\n\r\n", | |
| 575 "HTTP/1.0 200 OKBar2:0Baz2:1|Foo: 1|Bar: 2||" | |
| 576 }, | |
| 577 | |
| 578 // Embed NULLs in a header line. They should not be understood as | |
| 579 // line separators. | |
| 580 { | |
| 581 "HTTP/1.0 200 OK\nFoo: 1|Foo2: 3\nBar: 2\n\n", | |
| 582 "HTTP/1.0 200 OK|Foo: 1Foo2: 3|Bar: 2||" | |
| 583 }, | |
| 584 }; | |
| 585 for (size_t i = 0; i < arraysize(tests); ++i) { | |
| 586 std::string input = tests[i].input; | |
| 587 std::replace(input.begin(), input.end(), '|', '\0'); | |
| 588 std::string raw = HttpUtil::AssembleRawHeaders(input.data(), input.size()); | |
| 589 std::replace(raw.begin(), raw.end(), '\0', '|'); | |
| 590 EXPECT_EQ(tests[i].expected_result, raw); | |
| 591 } | |
| 592 } | |
| 593 | |
| 594 // Test SpecForRequest() and PathForRequest(). | |
| 595 TEST(HttpUtilTest, RequestUrlSanitize) { | |
| 596 struct { | |
| 597 const char* const url; | |
| 598 const char* const expected_spec; | |
| 599 const char* const expected_path; | |
| 600 } tests[] = { | |
| 601 { // Check that #hash is removed. | |
| 602 "http://www.google.com:78/foobar?query=1#hash", | |
| 603 "http://www.google.com:78/foobar?query=1", | |
| 604 "/foobar?query=1" | |
| 605 }, | |
| 606 { // The reference may itself contain # -- strip all of it. | |
| 607 "http://192.168.0.1?query=1#hash#10#11#13#14", | |
| 608 "http://192.168.0.1/?query=1", | |
| 609 "/?query=1" | |
| 610 }, | |
| 611 { // Strip username/password. | |
| 612 "http://user:pass@google.com", | |
| 613 "http://google.com/", | |
| 614 "/" | |
| 615 }, | |
| 616 { // https scheme | |
| 617 "https://www.google.com:78/foobar?query=1#hash", | |
| 618 "https://www.google.com:78/foobar?query=1", | |
| 619 "/foobar?query=1" | |
| 620 }, | |
| 621 { // WebSocket's ws scheme | |
| 622 "ws://www.google.com:78/foobar?query=1#hash", | |
| 623 "ws://www.google.com:78/foobar?query=1", | |
| 624 "/foobar?query=1" | |
| 625 }, | |
| 626 { // WebSocket's wss scheme | |
| 627 "wss://www.google.com:78/foobar?query=1#hash", | |
| 628 "wss://www.google.com:78/foobar?query=1", | |
| 629 "/foobar?query=1" | |
| 630 } | |
| 631 }; | |
| 632 for (size_t i = 0; i < arraysize(tests); ++i) { | |
| 633 GURL url(GURL(tests[i].url)); | |
| 634 std::string expected_spec(tests[i].expected_spec); | |
| 635 std::string expected_path(tests[i].expected_path); | |
| 636 | |
| 637 EXPECT_EQ(expected_spec, HttpUtil::SpecForRequest(url)); | |
| 638 EXPECT_EQ(expected_path, HttpUtil::PathForRequest(url)); | |
| 639 } | |
| 640 } | |
| 641 | |
| 642 // Test SpecForRequest() for "ftp" scheme. | |
| 643 TEST(HttpUtilTest, SpecForRequestForUrlWithFtpScheme) { | |
| 644 GURL ftp_url("ftp://user:pass@google.com/pub/chromium/"); | |
| 645 EXPECT_EQ("ftp://google.com/pub/chromium/", | |
| 646 HttpUtil::SpecForRequest(ftp_url)); | |
| 647 } | |
| 648 | |
| 649 TEST(HttpUtilTest, GenerateAcceptLanguageHeader) { | |
| 650 EXPECT_EQ(std::string("en-US,fr;q=0.8,de;q=0.6"), | |
| 651 HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de")); | |
| 652 EXPECT_EQ(std::string("en-US,fr;q=0.8,de;q=0.6,ko;q=0.4,zh-CN;q=0.2," | |
| 653 "ja;q=0.2"), | |
| 654 HttpUtil::GenerateAcceptLanguageHeader("en-US,fr,de,ko,zh-CN,ja")); | |
| 655 } | |
| 656 | |
| 657 // HttpResponseHeadersTest.GetMimeType also tests ParseContentType. | |
| 658 TEST(HttpUtilTest, ParseContentType) { | |
| 659 const struct { | |
| 660 const char* const content_type; | |
| 661 const char* const expected_mime_type; | |
| 662 const char* const expected_charset; | |
| 663 const bool expected_had_charset; | |
| 664 const char* const expected_boundary; | |
| 665 } tests[] = { | |
| 666 { "text/html; charset=utf-8", | |
| 667 "text/html", | |
| 668 "utf-8", | |
| 669 true, | |
| 670 "" | |
| 671 }, | |
| 672 { "text/html; charset =utf-8", | |
| 673 "text/html", | |
| 674 "utf-8", | |
| 675 true, | |
| 676 "" | |
| 677 }, | |
| 678 { "text/html; charset= utf-8", | |
| 679 "text/html", | |
| 680 "utf-8", | |
| 681 true, | |
| 682 "" | |
| 683 }, | |
| 684 { "text/html; charset=utf-8 ", | |
| 685 "text/html", | |
| 686 "utf-8", | |
| 687 true, | |
| 688 "" | |
| 689 }, | |
| 690 { "text/html; boundary=\"WebKit-ada-df-dsf-adsfadsfs\"", | |
| 691 "text/html", | |
| 692 "", | |
| 693 false, | |
| 694 "\"WebKit-ada-df-dsf-adsfadsfs\"" | |
| 695 }, | |
| 696 { "text/html; boundary =\"WebKit-ada-df-dsf-adsfadsfs\"", | |
| 697 "text/html", | |
| 698 "", | |
| 699 false, | |
| 700 "\"WebKit-ada-df-dsf-adsfadsfs\"" | |
| 701 }, | |
| 702 { "text/html; boundary= \"WebKit-ada-df-dsf-adsfadsfs\"", | |
| 703 "text/html", | |
| 704 "", | |
| 705 false, | |
| 706 "\"WebKit-ada-df-dsf-adsfadsfs\"" | |
| 707 }, | |
| 708 { "text/html; boundary= \"WebKit-ada-df-dsf-adsfadsfs\" ", | |
| 709 "text/html", | |
| 710 "", | |
| 711 false, | |
| 712 "\"WebKit-ada-df-dsf-adsfadsfs\"" | |
| 713 }, | |
| 714 { "text/html; boundary=\"WebKit-ada-df-dsf-adsfadsfs \"", | |
| 715 "text/html", | |
| 716 "", | |
| 717 false, | |
| 718 "\"WebKit-ada-df-dsf-adsfadsfs \"" | |
| 719 }, | |
| 720 { "text/html; boundary=WebKit-ada-df-dsf-adsfadsfs", | |
| 721 "text/html", | |
| 722 "", | |
| 723 false, | |
| 724 "WebKit-ada-df-dsf-adsfadsfs" | |
| 725 }, | |
| 726 // TODO(abarth): Add more interesting test cases. | |
| 727 }; | |
| 728 for (size_t i = 0; i < arraysize(tests); ++i) { | |
| 729 std::string mime_type; | |
| 730 std::string charset; | |
| 731 bool had_charset = false; | |
| 732 std::string boundary; | |
| 733 net::HttpUtil::ParseContentType(tests[i].content_type, &mime_type, | |
| 734 &charset, &had_charset, &boundary); | |
| 735 EXPECT_EQ(tests[i].expected_mime_type, mime_type) << "i=" << i; | |
| 736 EXPECT_EQ(tests[i].expected_charset, charset) << "i=" << i; | |
| 737 EXPECT_EQ(tests[i].expected_had_charset, had_charset) << "i=" << i; | |
| 738 EXPECT_EQ(tests[i].expected_boundary, boundary) << "i=" << i; | |
| 739 } | |
| 740 } | |
| 741 | |
| 742 TEST(HttpUtilTest, ParseRanges) { | |
| 743 const struct { | |
| 744 const char* const headers; | |
| 745 bool expected_return_value; | |
| 746 size_t expected_ranges_size; | |
| 747 const struct { | |
| 748 int64 expected_first_byte_position; | |
| 749 int64 expected_last_byte_position; | |
| 750 int64 expected_suffix_length; | |
| 751 } expected_ranges[10]; | |
| 752 } tests[] = { | |
| 753 { "Range: bytes=0-10", | |
| 754 true, | |
| 755 1, | |
| 756 { {0, 10, -1}, } | |
| 757 }, | |
| 758 { "Range: bytes=10-0", | |
| 759 false, | |
| 760 0, | |
| 761 {} | |
| 762 }, | |
| 763 { "Range: BytES=0-10", | |
| 764 true, | |
| 765 1, | |
| 766 { {0, 10, -1}, } | |
| 767 }, | |
| 768 { "Range: megabytes=0-10", | |
| 769 false, | |
| 770 0, | |
| 771 {} | |
| 772 }, | |
| 773 { "Range: bytes0-10", | |
| 774 false, | |
| 775 0, | |
| 776 {} | |
| 777 }, | |
| 778 { "Range: bytes=0-0,0-10,10-20,100-200,100-,-200", | |
| 779 true, | |
| 780 6, | |
| 781 { {0, 0, -1}, | |
| 782 {0, 10, -1}, | |
| 783 {10, 20, -1}, | |
| 784 {100, 200, -1}, | |
| 785 {100, -1, -1}, | |
| 786 {-1, -1, 200}, | |
| 787 } | |
| 788 }, | |
| 789 { "Range: bytes=0-10\r\n" | |
| 790 "Range: bytes=0-10,10-20,100-200,100-,-200", | |
| 791 true, | |
| 792 1, | |
| 793 { {0, 10, -1} | |
| 794 } | |
| 795 }, | |
| 796 { "Range: bytes=", | |
| 797 false, | |
| 798 0, | |
| 799 {} | |
| 800 }, | |
| 801 { "Range: bytes=-", | |
| 802 false, | |
| 803 0, | |
| 804 {} | |
| 805 }, | |
| 806 { "Range: bytes=0-10-", | |
| 807 false, | |
| 808 0, | |
| 809 {} | |
| 810 }, | |
| 811 { "Range: bytes=-0-10", | |
| 812 false, | |
| 813 0, | |
| 814 {} | |
| 815 }, | |
| 816 { "Range: bytes =0-10\r\n", | |
| 817 true, | |
| 818 1, | |
| 819 { {0, 10, -1} | |
| 820 } | |
| 821 }, | |
| 822 { "Range: bytes= 0-10 \r\n", | |
| 823 true, | |
| 824 1, | |
| 825 { {0, 10, -1} | |
| 826 } | |
| 827 }, | |
| 828 { "Range: bytes = 0 - 10 \r\n", | |
| 829 true, | |
| 830 1, | |
| 831 { {0, 10, -1} | |
| 832 } | |
| 833 }, | |
| 834 { "Range: bytes= 0-1 0\r\n", | |
| 835 false, | |
| 836 0, | |
| 837 {} | |
| 838 }, | |
| 839 { "Range: bytes= 0- -10\r\n", | |
| 840 false, | |
| 841 0, | |
| 842 {} | |
| 843 }, | |
| 844 { "Range: bytes= 0 - 1 , 10 -20, 100- 200 , 100-, -200 \r\n", | |
| 845 true, | |
| 846 5, | |
| 847 { {0, 1, -1}, | |
| 848 {10, 20, -1}, | |
| 849 {100, 200, -1}, | |
| 850 {100, -1, -1}, | |
| 851 {-1, -1, 200}, | |
| 852 } | |
| 853 }, | |
| 854 }; | |
| 855 | |
| 856 for (size_t i = 0; i < arraysize(tests); ++i) { | |
| 857 std::vector<net::HttpByteRange> ranges; | |
| 858 bool return_value = HttpUtil::ParseRanges(std::string(tests[i].headers), | |
| 859 &ranges); | |
| 860 EXPECT_EQ(tests[i].expected_return_value, return_value); | |
| 861 if (return_value) { | |
| 862 EXPECT_EQ(tests[i].expected_ranges_size, ranges.size()); | |
| 863 for (size_t j = 0; j < ranges.size(); ++j) { | |
| 864 EXPECT_EQ(tests[i].expected_ranges[j].expected_first_byte_position, | |
| 865 ranges[j].first_byte_position()); | |
| 866 EXPECT_EQ(tests[i].expected_ranges[j].expected_last_byte_position, | |
| 867 ranges[j].last_byte_position()); | |
| 868 EXPECT_EQ(tests[i].expected_ranges[j].expected_suffix_length, | |
| 869 ranges[j].suffix_length()); | |
| 870 } | |
| 871 } | |
| 872 } | |
| 873 } | |
| 874 | |
| 875 TEST(HttpUtilTest, ParseRetryAfterHeader) { | |
| 876 base::Time::Exploded now_exploded = { 2014, 11, -1, 5, 22, 39, 30, 0 }; | |
| 877 base::Time now = base::Time::FromUTCExploded(now_exploded); | |
| 878 | |
| 879 base::Time::Exploded later_exploded = { 2015, 1, -1, 1, 12, 34, 56, 0 }; | |
| 880 base::Time later = base::Time::FromUTCExploded(later_exploded); | |
| 881 | |
| 882 const struct { | |
| 883 const char* retry_after_string; | |
| 884 bool expected_return_value; | |
| 885 base::TimeDelta expected_retry_after; | |
| 886 } tests[] = { | |
| 887 { "", false, base::TimeDelta() }, | |
| 888 { "-3", false, base::TimeDelta() }, | |
| 889 { "-2", false, base::TimeDelta() }, | |
| 890 { "-1", false, base::TimeDelta() }, | |
| 891 { "0", true, base::TimeDelta::FromSeconds(0) }, | |
| 892 { "1", true, base::TimeDelta::FromSeconds(1) }, | |
| 893 { "2", true, base::TimeDelta::FromSeconds(2) }, | |
| 894 { "3", true, base::TimeDelta::FromSeconds(3) }, | |
| 895 { "60", true, base::TimeDelta::FromSeconds(60) }, | |
| 896 { "3600", true, base::TimeDelta::FromSeconds(3600) }, | |
| 897 { "86400", true, base::TimeDelta::FromSeconds(86400) }, | |
| 898 { "Thu, 1 Jan 2015 12:34:56 GMT", true, later - now }, | |
| 899 { "Mon, 1 Jan 1900 12:34:56 GMT", false, base::TimeDelta() } | |
| 900 }; | |
| 901 | |
| 902 for (size_t i = 0; i < arraysize(tests); ++i) { | |
| 903 base::TimeDelta retry_after; | |
| 904 bool return_value = HttpUtil::ParseRetryAfterHeader( | |
| 905 tests[i].retry_after_string, now, &retry_after); | |
| 906 EXPECT_EQ(tests[i].expected_return_value, return_value) | |
| 907 << "Test case " << i << ": expected " << tests[i].expected_return_value | |
| 908 << " but got " << return_value << "."; | |
| 909 if (tests[i].expected_return_value && return_value) { | |
| 910 EXPECT_EQ(tests[i].expected_retry_after, retry_after) | |
| 911 << "Test case " << i << ": expected " | |
| 912 << tests[i].expected_retry_after.InSeconds() << "s but got " | |
| 913 << retry_after.InSeconds() << "s."; | |
| 914 } | |
| 915 } | |
| 916 } | |
| 917 | |
| 918 namespace { | |
| 919 void CheckCurrentNameValuePair(HttpUtil::NameValuePairsIterator* parser, | |
| 920 bool expect_valid, | |
| 921 std::string expected_name, | |
| 922 std::string expected_value) { | |
| 923 ASSERT_EQ(expect_valid, parser->valid()); | |
| 924 if (!expect_valid) { | |
| 925 return; | |
| 926 } | |
| 927 | |
| 928 // Let's make sure that these never change (i.e., when a quoted value is | |
| 929 // unquoted, it should be cached on the first calls and not regenerated | |
| 930 // later). | |
| 931 std::string::const_iterator first_value_begin = parser->value_begin(); | |
| 932 std::string::const_iterator first_value_end = parser->value_end(); | |
| 933 | |
| 934 ASSERT_EQ(expected_name, std::string(parser->name_begin(), | |
| 935 parser->name_end())); | |
| 936 ASSERT_EQ(expected_name, parser->name()); | |
| 937 ASSERT_EQ(expected_value, std::string(parser->value_begin(), | |
| 938 parser->value_end())); | |
| 939 ASSERT_EQ(expected_value, parser->value()); | |
| 940 | |
| 941 // Make sure they didn't/don't change. | |
| 942 ASSERT_TRUE(first_value_begin == parser->value_begin()); | |
| 943 ASSERT_TRUE(first_value_end == parser->value_end()); | |
| 944 } | |
| 945 | |
| 946 void CheckNextNameValuePair(HttpUtil::NameValuePairsIterator* parser, | |
| 947 bool expect_next, | |
| 948 bool expect_valid, | |
| 949 std::string expected_name, | |
| 950 std::string expected_value) { | |
| 951 ASSERT_EQ(expect_next, parser->GetNext()); | |
| 952 ASSERT_EQ(expect_valid, parser->valid()); | |
| 953 if (!expect_next || !expect_valid) { | |
| 954 return; | |
| 955 } | |
| 956 | |
| 957 CheckCurrentNameValuePair(parser, | |
| 958 expect_valid, | |
| 959 expected_name, | |
| 960 expected_value); | |
| 961 } | |
| 962 | |
| 963 void CheckInvalidNameValuePair(std::string valid_part, | |
| 964 std::string invalid_part) { | |
| 965 std::string whole_string = valid_part + invalid_part; | |
| 966 | |
| 967 HttpUtil::NameValuePairsIterator valid_parser(valid_part.begin(), | |
| 968 valid_part.end(), | |
| 969 ';'); | |
| 970 HttpUtil::NameValuePairsIterator invalid_parser(whole_string.begin(), | |
| 971 whole_string.end(), | |
| 972 ';'); | |
| 973 | |
| 974 ASSERT_TRUE(valid_parser.valid()); | |
| 975 ASSERT_TRUE(invalid_parser.valid()); | |
| 976 | |
| 977 // Both parsers should return all the same values until "valid_parser" is | |
| 978 // exhausted. | |
| 979 while (valid_parser.GetNext()) { | |
| 980 ASSERT_TRUE(invalid_parser.GetNext()); | |
| 981 ASSERT_TRUE(valid_parser.valid()); | |
| 982 ASSERT_TRUE(invalid_parser.valid()); | |
| 983 ASSERT_EQ(valid_parser.name(), invalid_parser.name()); | |
| 984 ASSERT_EQ(valid_parser.value(), invalid_parser.value()); | |
| 985 } | |
| 986 | |
| 987 // valid_parser is exhausted and remains 'valid' | |
| 988 ASSERT_TRUE(valid_parser.valid()); | |
| 989 | |
| 990 // invalid_parser's corresponding call to GetNext also returns false... | |
| 991 ASSERT_FALSE(invalid_parser.GetNext()); | |
| 992 // ...but the parser is in an invalid state. | |
| 993 ASSERT_FALSE(invalid_parser.valid()); | |
| 994 } | |
| 995 | |
| 996 } // anonymous namespace | |
| 997 | |
| 998 TEST(HttpUtilTest, NameValuePairsIteratorCopyAndAssign) { | |
| 999 std::string data = "alpha='\\'a\\''; beta=\" b \"; cappa='c;'; delta=\"d\""; | |
| 1000 HttpUtil::NameValuePairsIterator parser_a(data.begin(), data.end(), ';'); | |
| 1001 | |
| 1002 EXPECT_TRUE(parser_a.valid()); | |
| 1003 ASSERT_NO_FATAL_FAILURE( | |
| 1004 CheckNextNameValuePair(&parser_a, true, true, "alpha", "'a'")); | |
| 1005 | |
| 1006 HttpUtil::NameValuePairsIterator parser_b(parser_a); | |
| 1007 // a and b now point to same location | |
| 1008 ASSERT_NO_FATAL_FAILURE( | |
| 1009 CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'")); | |
| 1010 ASSERT_NO_FATAL_FAILURE( | |
| 1011 CheckCurrentNameValuePair(&parser_a, true, "alpha", "'a'")); | |
| 1012 | |
| 1013 // advance a, no effect on b | |
| 1014 ASSERT_NO_FATAL_FAILURE( | |
| 1015 CheckNextNameValuePair(&parser_a, true, true, "beta", " b ")); | |
| 1016 ASSERT_NO_FATAL_FAILURE( | |
| 1017 CheckCurrentNameValuePair(&parser_b, true, "alpha", "'a'")); | |
| 1018 | |
| 1019 // assign b the current state of a, no effect on a | |
| 1020 parser_b = parser_a; | |
| 1021 ASSERT_NO_FATAL_FAILURE( | |
| 1022 CheckCurrentNameValuePair(&parser_b, true, "beta", " b ")); | |
| 1023 ASSERT_NO_FATAL_FAILURE( | |
| 1024 CheckCurrentNameValuePair(&parser_a, true, "beta", " b ")); | |
| 1025 | |
| 1026 // advance b, no effect on a | |
| 1027 ASSERT_NO_FATAL_FAILURE( | |
| 1028 CheckNextNameValuePair(&parser_b, true, true, "cappa", "c;")); | |
| 1029 ASSERT_NO_FATAL_FAILURE( | |
| 1030 CheckCurrentNameValuePair(&parser_a, true, "beta", " b ")); | |
| 1031 } | |
| 1032 | |
| 1033 TEST(HttpUtilTest, NameValuePairsIteratorEmptyInput) { | |
| 1034 std::string data; | |
| 1035 HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';'); | |
| 1036 | |
| 1037 EXPECT_TRUE(parser.valid()); | |
| 1038 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair( | |
| 1039 &parser, false, true, std::string(), std::string())); | |
| 1040 } | |
| 1041 | |
| 1042 TEST(HttpUtilTest, NameValuePairsIterator) { | |
| 1043 std::string data = "alpha=1; beta= 2 ;cappa =' 3; ';" | |
| 1044 "delta= \" \\\"4\\\" \"; e= \" '5'\"; e=6;" | |
| 1045 "f='\\'\\h\\e\\l\\l\\o\\ \\w\\o\\r\\l\\d\\'';" | |
| 1046 "g=''; h='hello'"; | |
| 1047 HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';'); | |
| 1048 EXPECT_TRUE(parser.valid()); | |
| 1049 | |
| 1050 ASSERT_NO_FATAL_FAILURE( | |
| 1051 CheckNextNameValuePair(&parser, true, true, "alpha", "1")); | |
| 1052 ASSERT_NO_FATAL_FAILURE( | |
| 1053 CheckNextNameValuePair(&parser, true, true, "beta", "2")); | |
| 1054 ASSERT_NO_FATAL_FAILURE( | |
| 1055 CheckNextNameValuePair(&parser, true, true, "cappa", " 3; ")); | |
| 1056 ASSERT_NO_FATAL_FAILURE( | |
| 1057 CheckNextNameValuePair(&parser, true, true, "delta", " \"4\" ")); | |
| 1058 ASSERT_NO_FATAL_FAILURE( | |
| 1059 CheckNextNameValuePair(&parser, true, true, "e", " '5'")); | |
| 1060 ASSERT_NO_FATAL_FAILURE( | |
| 1061 CheckNextNameValuePair(&parser, true, true, "e", "6")); | |
| 1062 ASSERT_NO_FATAL_FAILURE( | |
| 1063 CheckNextNameValuePair(&parser, true, true, "f", "'hello world'")); | |
| 1064 ASSERT_NO_FATAL_FAILURE( | |
| 1065 CheckNextNameValuePair(&parser, true, true, "g", std::string())); | |
| 1066 ASSERT_NO_FATAL_FAILURE( | |
| 1067 CheckNextNameValuePair(&parser, true, true, "h", "hello")); | |
| 1068 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair( | |
| 1069 &parser, false, true, std::string(), std::string())); | |
| 1070 } | |
| 1071 | |
| 1072 TEST(HttpUtilTest, NameValuePairsIteratorIllegalInputs) { | |
| 1073 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; beta")); | |
| 1074 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair(std::string(), "beta")); | |
| 1075 | |
| 1076 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", "; 'beta'=2")); | |
| 1077 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair(std::string(), "'beta'=2")); | |
| 1078 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";beta=")); | |
| 1079 ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", | |
| 1080 ";beta=;cappa=2")); | |
| 1081 | |
| 1082 // According to the spec this is an error, but it doesn't seem appropriate to | |
| 1083 // change our behaviour to be less permissive at this time. | |
| 1084 // See NameValuePairsIteratorExtraSeparators test | |
| 1085 // ASSERT_NO_FATAL_FAILURE(CheckInvalidNameValuePair("alpha=1", ";; beta=2")); | |
| 1086 } | |
| 1087 | |
| 1088 // If we are going to support extra separators against the spec, let's just make | |
| 1089 // sure they work rationally. | |
| 1090 TEST(HttpUtilTest, NameValuePairsIteratorExtraSeparators) { | |
| 1091 std::string data = " ; ;;alpha=1; ;; ; beta= 2;cappa=3;;; ; "; | |
| 1092 HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';'); | |
| 1093 EXPECT_TRUE(parser.valid()); | |
| 1094 | |
| 1095 ASSERT_NO_FATAL_FAILURE( | |
| 1096 CheckNextNameValuePair(&parser, true, true, "alpha", "1")); | |
| 1097 ASSERT_NO_FATAL_FAILURE( | |
| 1098 CheckNextNameValuePair(&parser, true, true, "beta", "2")); | |
| 1099 ASSERT_NO_FATAL_FAILURE( | |
| 1100 CheckNextNameValuePair(&parser, true, true, "cappa", "3")); | |
| 1101 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair( | |
| 1102 &parser, false, true, std::string(), std::string())); | |
| 1103 } | |
| 1104 | |
| 1105 // See comments on the implementation of NameValuePairsIterator::GetNext | |
| 1106 // regarding this derogation from the spec. | |
| 1107 TEST(HttpUtilTest, NameValuePairsIteratorMissingEndQuote) { | |
| 1108 std::string data = "name='value"; | |
| 1109 HttpUtil::NameValuePairsIterator parser(data.begin(), data.end(), ';'); | |
| 1110 EXPECT_TRUE(parser.valid()); | |
| 1111 | |
| 1112 ASSERT_NO_FATAL_FAILURE( | |
| 1113 CheckNextNameValuePair(&parser, true, true, "name", "value")); | |
| 1114 ASSERT_NO_FATAL_FAILURE(CheckNextNameValuePair( | |
| 1115 &parser, false, true, std::string(), std::string())); | |
| 1116 } | |
| OLD | NEW |