1 // Copyright (c) 2009 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 <math.h> // ceil 6 7 #include "base/compiler_specific.h" 8 #include "net/base/completion_callback.h" 9 #include "net/base/mock_host_resolver.h" 10 #include "net/base/request_priority.h" 11 #include "net/base/ssl_config_service_defaults.h" 12 #include "net/base/ssl_info.h" 13 #include "net/base/test_completion_callback.h" 14 #include "net/base/upload_data.h" 15 #include "net/flip/flip_session_pool.h" 16 #include "net/http/http_auth_handler_ntlm.h" 17 #include "net/http/http_basic_stream.h" 18 #include "net/http/http_network_session.h" 19 #include "net/http/http_network_transaction.h" 20 #include "net/http/http_stream.h" 21 #include "net/http/http_transaction_unittest.h" 22 #include "net/proxy/proxy_config_service_fixed.h" 23 #include "net/socket/client_socket_factory.h" 24 #include "net/socket/socket_test_util.h" 25 #include "net/socket/ssl_client_socket.h" 26 #include "testing/gtest/include/gtest/gtest.h" 27 #include "testing/platform_test.h" 28 29 //----------------------------------------------------------------------------- 30 31 // TODO(eroman): Add a regression test for http://crbug.com/32316 -- when the 32 // proxy service returns an error, we should fallback to DIRECT instead of 33 // failing with ERR_NO_SUPPORTED_PROXIES. 34 35 namespace net { 36 37 // Create a proxy service which fails on all requests (falls back to direct). 38 ProxyService* CreateNullProxyService() { 39 return ProxyService::CreateNull(); 40 } 41 42 // Helper to manage the lifetimes of the dependencies for a 43 // HttpNetworkTransaction. 44 class SessionDependencies { 45 public: 46 // Default set of dependencies -- "null" proxy service. 47 SessionDependencies() 48 : host_resolver(new MockHostResolver), 49 proxy_service(CreateNullProxyService()), 50 ssl_config_service(new SSLConfigServiceDefaults), 51 flip_session_pool(new FlipSessionPool) {} 52 53 // Custom proxy service dependency. 54 explicit SessionDependencies(ProxyService* proxy_service) 55 : host_resolver(new MockHostResolver), 56 proxy_service(proxy_service), 57 ssl_config_service(new SSLConfigServiceDefaults), 58 flip_session_pool(new FlipSessionPool) {} 59 60 scoped_refptr<MockHostResolverBase> host_resolver; 61 scoped_refptr<ProxyService> proxy_service; 62 scoped_refptr<SSLConfigService> ssl_config_service; 63 MockClientSocketFactory socket_factory; 64 scoped_refptr<FlipSessionPool> flip_session_pool; 65 }; 66 67 ProxyService* CreateFixedProxyService(const std::string& proxy) { 68 net::ProxyConfig proxy_config; 69 proxy_config.proxy_rules.ParseFromString(proxy); 70 return ProxyService::CreateFixed(proxy_config); 71 } 72 73 74 HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { 75 return new HttpNetworkSession(NULL, 76 session_deps->host_resolver, 77 session_deps->proxy_service, 78 &session_deps->socket_factory, 79 session_deps->ssl_config_service, 80 session_deps->flip_session_pool); 81 } 82 83 class HttpNetworkTransactionTest : public PlatformTest { 84 public: 85 virtual void TearDown() { 86 // Empty the current queue. 87 MessageLoop::current()->RunAllPending(); 88 PlatformTest::TearDown(); 89 } 90 91 protected: 92 void KeepAliveConnectionResendRequestTest(const MockRead& read_failure); 93 94 struct SimpleGetHelperResult { 95 int rv; 96 std::string status_line; 97 std::string response_data; 98 }; 99 100 SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[]) { 101 SimpleGetHelperResult out; 102 103 SessionDependencies session_deps; 104 scoped_ptr<HttpTransaction> trans( 105 new HttpNetworkTransaction(CreateSession(&session_deps))); 106 107 HttpRequestInfo request; 108 request.method = "GET"; 109 request.url = GURL("http://www.google.com/"); 110 request.load_flags = 0; 111 112 StaticSocketDataProvider data(data_reads, NULL); 113 session_deps.socket_factory.AddSocketDataProvider(&data); 114 115 TestCompletionCallback callback; 116 117 int rv = trans->Start(&request, &callback, NULL); 118 EXPECT_EQ(ERR_IO_PENDING, rv); 119 120 out.rv = callback.WaitForResult(); 121 if (out.rv != OK) 122 return out; 123 124 const HttpResponseInfo* response = trans->GetResponseInfo(); 125 EXPECT_TRUE(response != NULL); 126 127 EXPECT_TRUE(response->headers != NULL); 128 out.status_line = response->headers->GetStatusLine(); 129 130 rv = ReadTransaction(trans.get(), &out.response_data); 131 EXPECT_EQ(OK, rv); 132 133 return out; 134 } 135 136 void ConnectStatusHelperWithExpectedStatus(const MockRead& status, 137 int expected_status); 138 139 void ConnectStatusHelper(const MockRead& status); 140 }; 141 142 // Fill |str| with a long header list that consumes >= |size| bytes. 143 void FillLargeHeadersString(std::string* str, int size) { 144 const char* row = 145 "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"; 146 const int sizeof_row = strlen(row); 147 const int num_rows = static_cast<int>( 148 ceil(static_cast<float>(size) / sizeof_row)); 149 const int sizeof_data = num_rows * sizeof_row; 150 DCHECK(sizeof_data >= size); 151 str->reserve(sizeof_data); 152 153 for (int i = 0; i < num_rows; ++i) 154 str->append(row, sizeof_row); 155 } 156 157 // Alternative functions that eliminate randomness and dependency on the local 158 // host name so that the generated NTLM messages are reproducible. 159 void MockGenerateRandom1(uint8* output, size_t n) { 160 static const uint8 bytes[] = { 161 0x55, 0x29, 0x66, 0x26, 0x6b, 0x9c, 0x73, 0x54 162 }; 163 static size_t current_byte = 0; 164 for (size_t i = 0; i < n; ++i) { 165 output[i] = bytes[current_byte++]; 166 current_byte %= arraysize(bytes); 167 } 168 } 169 170 void MockGenerateRandom2(uint8* output, size_t n) { 171 static const uint8 bytes[] = { 172 0x96, 0x79, 0x85, 0xe7, 0x49, 0x93, 0x70, 0xa1, 173 0x4e, 0xe7, 0x87, 0x45, 0x31, 0x5b, 0xd3, 0x1f 174 }; 175 static size_t current_byte = 0; 176 for (size_t i = 0; i < n; ++i) { 177 output[i] = bytes[current_byte++]; 178 current_byte %= arraysize(bytes); 179 } 180 } 181 182 std::string MockGetHostName() { 183 return "WTC-WIN7"; 184 } 185 186 class CaptureGroupNameSocketPool : public TCPClientSocketPool { 187 public: 188 CaptureGroupNameSocketPool() : TCPClientSocketPool(0, 0, NULL, NULL, NULL) {} 189 const std::string last_group_name_received() const { 190 return last_group_name_; 191 } 192 193 virtual int RequestSocket(const std::string& group_name, 194 const void* socket_params, 195 RequestPriority priority, 196 ClientSocketHandle* handle, 197 CompletionCallback* callback, 198 LoadLog* load_log) { 199 last_group_name_ = group_name; 200 return ERR_IO_PENDING; 201 } 202 virtual void CancelRequest(const std::string& group_name, 203 const ClientSocketHandle* handle) { } 204 virtual void ReleaseSocket(const std::string& group_name, 205 ClientSocket* socket) {} 206 virtual void CloseIdleSockets() {} 207 virtual HostResolver* GetHostResolver() const { 208 return NULL; 209 } 210 virtual int IdleSocketCount() const { 211 return 0; 212 } 213 virtual int IdleSocketCountInGroup(const std::string& group_name) const { 214 return 0; 215 } 216 virtual LoadState GetLoadState(const std::string& group_name, 217 const ClientSocketHandle* handle) const { 218 return LOAD_STATE_IDLE; 219 } 220 221 private: 222 std::string last_group_name_; 223 }; 224 225 //----------------------------------------------------------------------------- 226 227 TEST_F(HttpNetworkTransactionTest, Basic) { 228 SessionDependencies session_deps; 229 scoped_ptr<HttpTransaction> trans( 230 new HttpNetworkTransaction(CreateSession(&session_deps))); 231 } 232 233 TEST_F(HttpNetworkTransactionTest, SimpleGET) { 234 MockRead data_reads[] = { 235 MockRead("HTTP/1.0 200 OK\r\n\r\n"), 236 MockRead("hello world"), 237 MockRead(false, OK), 238 }; 239 SimpleGetHelperResult out = SimpleGetHelper(data_reads); 240 EXPECT_EQ(OK, out.rv); 241 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); 242 EXPECT_EQ("hello world", out.response_data); 243 } 244 245 // Response with no status line. 246 TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) { 247 MockRead data_reads[] = { 248 MockRead("hello world"), 249 MockRead(false, OK), 250 }; 251 SimpleGetHelperResult out = SimpleGetHelper(data_reads); 252 EXPECT_EQ(OK, out.rv); 253 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); 254 EXPECT_EQ("hello world", out.response_data); 255 } 256 257 // Allow up to 4 bytes of junk to precede status line. 258 TEST_F(HttpNetworkTransactionTest, StatusLineJunk2Bytes) { 259 MockRead data_reads[] = { 260 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), 261 MockRead(false, OK), 262 }; 263 SimpleGetHelperResult out = SimpleGetHelper(data_reads); 264 EXPECT_EQ(OK, out.rv); 265 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); 266 EXPECT_EQ("DATA", out.response_data); 267 } 268 269 // Allow up to 4 bytes of junk to precede status line. 270 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) { 271 MockRead data_reads[] = { 272 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), 273 MockRead(false, OK), 274 }; 275 SimpleGetHelperResult out = SimpleGetHelper(data_reads); 276 EXPECT_EQ(OK, out.rv); 277 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); 278 EXPECT_EQ("DATA", out.response_data); 279 } 280 281 // Beyond 4 bytes of slop and it should fail to find a status line. 282 TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) { 283 MockRead data_reads[] = { 284 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"), 285 MockRead(false, OK), 286 }; 287 SimpleGetHelperResult out = SimpleGetHelper(data_reads); 288 EXPECT_EQ(OK, out.rv); 289 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); 290 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data); 291 } 292 293 // Same as StatusLineJunk4Bytes, except the read chunks are smaller. 294 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) { 295 MockRead data_reads[] = { 296 MockRead("\n"), 297 MockRead("\n"), 298 MockRead("Q"), 299 MockRead("J"), 300 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), 301 MockRead(false, OK), 302 }; 303 SimpleGetHelperResult out = SimpleGetHelper(data_reads); 304 EXPECT_EQ(OK, out.rv); 305 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); 306 EXPECT_EQ("DATA", out.response_data); 307 } 308 309 // Close the connection before enough bytes to have a status line. 310 TEST_F(HttpNetworkTransactionTest, StatusLinePartial) { 311 MockRead data_reads[] = { 312 MockRead("HTT"), 313 MockRead(false, OK), 314 }; 315 SimpleGetHelperResult out = SimpleGetHelper(data_reads); 316 EXPECT_EQ(OK, out.rv); 317 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); 318 EXPECT_EQ("HTT", out.response_data); 319 } 320 321 // Simulate a 204 response, lacking a Content-Length header, sent over a 322 // persistent connection. The response should still terminate since a 204 323 // cannot have a response body. 324 TEST_F(HttpNetworkTransactionTest, StopsReading204) { 325 MockRead data_reads[] = { 326 MockRead("HTTP/1.1 204 No Content\r\n\r\n"), 327 MockRead("junk"), // Should not be read!! 328 MockRead(false, OK), 329 }; 330 SimpleGetHelperResult out = SimpleGetHelper(data_reads); 331 EXPECT_EQ(OK, out.rv); 332 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line); 333 EXPECT_EQ("", out.response_data); 334 } 335 336 // A simple request using chunked encoding with some extra data after. 337 // (Like might be seen in a pipelined response.) 338 TEST_F(HttpNetworkTransactionTest, ChunkedEncoding) { 339 MockRead data_reads[] = { 340 MockRead("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"), 341 MockRead("5\r\nHello\r\n"), 342 MockRead("1\r\n"), 343 MockRead(" \r\n"), 344 MockRead("5\r\nworld\r\n"), 345 MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"), 346 MockRead(false, OK), 347 }; 348 SimpleGetHelperResult out = SimpleGetHelper(data_reads); 349 EXPECT_EQ(OK, out.rv); 350 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); 351 EXPECT_EQ("Hello world", out.response_data); 352 } 353 354 // Do a request using the HEAD method. Verify that we don't try to read the 355 // message body (since HEAD has none). 356 TEST_F(HttpNetworkTransactionTest, Head) { 357 SessionDependencies session_deps; 358 scoped_ptr<HttpTransaction> trans( 359 new HttpNetworkTransaction(CreateSession(&session_deps))); 360 361 HttpRequestInfo request; 362 request.method = "HEAD"; 363 request.url = GURL("http://www.google.com/"); 364 request.load_flags = 0; 365 366 MockWrite data_writes1[] = { 367 MockWrite("HEAD / HTTP/1.1\r\n" 368 "Host: www.google.com\r\n" 369 "Connection: keep-alive\r\n" 370 "Content-Length: 0\r\n\r\n"), 371 }; 372 MockRead data_reads1[] = { 373 MockRead("HTTP/1.1 404 Not Found\r\n"), 374 MockRead("Server: Blah\r\n"), 375 MockRead("Content-Length: 1234\r\n\r\n"), 376 377 // No response body because the test stops reading here. 378 MockRead(false, ERR_UNEXPECTED), // Should not be reached. 379 }; 380 381 StaticSocketDataProvider data1(data_reads1, data_writes1); 382 session_deps.socket_factory.AddSocketDataProvider(&data1); 383 384 TestCompletionCallback callback1; 385 386 int rv = trans->Start(&request, &callback1, NULL); 387 EXPECT_EQ(ERR_IO_PENDING, rv); 388 389 rv = callback1.WaitForResult(); 390 EXPECT_EQ(OK, rv); 391 392 const HttpResponseInfo* response = trans->GetResponseInfo(); 393 EXPECT_FALSE(response == NULL); 394 395 // Check that the headers got parsed. 396 EXPECT_TRUE(response->headers != NULL); 397 EXPECT_EQ(1234, response->headers->GetContentLength()); 398 EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine()); 399 400 std::string server_header; 401 void* iter = NULL; 402 bool has_server_header = response->headers->EnumerateHeader( 403 &iter, "Server", &server_header); 404 EXPECT_TRUE(has_server_header); 405 EXPECT_EQ("Blah", server_header); 406 407 // Reading should give EOF right away, since there is no message body 408 // (despite non-zero content-length). 409 std::string response_data; 410 rv = ReadTransaction(trans.get(), &response_data); 411 EXPECT_EQ(OK, rv); 412 EXPECT_EQ("", response_data); 413 } 414 415 TEST_F(HttpNetworkTransactionTest, ReuseConnection) { 416 SessionDependencies session_deps; 417 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); 418 419 MockRead data_reads[] = { 420 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), 421 MockRead("hello"), 422 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), 423 MockRead("world"), 424 MockRead(false, OK), 425 }; 426 StaticSocketDataProvider data(data_reads, NULL); 427 session_deps.socket_factory.AddSocketDataProvider(&data); 428 429 const char* kExpectedResponseData[] = { 430 "hello", "world" 431 }; 432 433 for (int i = 0; i < 2; ++i) { 434 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 435 436 HttpRequestInfo request; 437 request.method = "GET"; 438 request.url = GURL("http://www.google.com/"); 439 request.load_flags = 0; 440 441 TestCompletionCallback callback; 442 443 int rv = trans->Start(&request, &callback, NULL); 444 EXPECT_EQ(ERR_IO_PENDING, rv); 445 446 rv = callback.WaitForResult(); 447 EXPECT_EQ(OK, rv); 448 449 const HttpResponseInfo* response = trans->GetResponseInfo(); 450 EXPECT_TRUE(response != NULL); 451 452 EXPECT_TRUE(response->headers != NULL); 453 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 454 455 std::string response_data; 456 rv = ReadTransaction(trans.get(), &response_data); 457 EXPECT_EQ(OK, rv); 458 EXPECT_EQ(kExpectedResponseData[i], response_data); 459 } 460 } 461 462 TEST_F(HttpNetworkTransactionTest, Ignores100) { 463 SessionDependencies session_deps; 464 scoped_ptr<HttpTransaction> trans( 465 new HttpNetworkTransaction(CreateSession(&session_deps))); 466 467 HttpRequestInfo request; 468 request.method = "POST"; 469 request.url = GURL("http://www.foo.com/"); 470 request.upload_data = new UploadData; 471 request.upload_data->AppendBytes("foo", 3); 472 request.load_flags = 0; 473 474 MockRead data_reads[] = { 475 MockRead("HTTP/1.0 100 Continue\r\n\r\n"), 476 MockRead("HTTP/1.0 200 OK\r\n\r\n"), 477 MockRead("hello world"), 478 MockRead(false, OK), 479 }; 480 StaticSocketDataProvider data(data_reads, NULL); 481 session_deps.socket_factory.AddSocketDataProvider(&data); 482 483 TestCompletionCallback callback; 484 485 int rv = trans->Start(&request, &callback, NULL); 486 EXPECT_EQ(ERR_IO_PENDING, rv); 487 488 rv = callback.WaitForResult(); 489 EXPECT_EQ(OK, rv); 490 491 const HttpResponseInfo* response = trans->GetResponseInfo(); 492 EXPECT_TRUE(response != NULL); 493 494 EXPECT_TRUE(response->headers != NULL); 495 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); 496 497 std::string response_data; 498 rv = ReadTransaction(trans.get(), &response_data); 499 EXPECT_EQ(OK, rv); 500 EXPECT_EQ("hello world", response_data); 501 } 502 503 // This test is almost the same as Ignores100 above, but the response contains 504 // a 102 instead of a 100. Also, instead of HTTP/1.0 the response is 505 // HTTP/1.1 and the two status headers are read in one read. 506 TEST_F(HttpNetworkTransactionTest, Ignores1xx) { 507 SessionDependencies session_deps; 508 scoped_ptr<HttpTransaction> trans( 509 new HttpNetworkTransaction(CreateSession(&session_deps))); 510 511 HttpRequestInfo request; 512 request.method = "GET"; 513 request.url = GURL("http://www.foo.com/"); 514 request.load_flags = 0; 515 516 MockRead data_reads[] = { 517 MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n" 518 "HTTP/1.1 200 OK\r\n\r\n"), 519 MockRead("hello world"), 520 MockRead(false, OK), 521 }; 522 StaticSocketDataProvider data(data_reads, NULL); 523 session_deps.socket_factory.AddSocketDataProvider(&data); 524 525 TestCompletionCallback callback; 526 527 int rv = trans->Start(&request, &callback, NULL); 528 EXPECT_EQ(ERR_IO_PENDING, rv); 529 530 rv = callback.WaitForResult(); 531 EXPECT_EQ(OK, rv); 532 533 const HttpResponseInfo* response = trans->GetResponseInfo(); 534 EXPECT_TRUE(response != NULL); 535 536 EXPECT_TRUE(response->headers != NULL); 537 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 538 539 std::string response_data; 540 rv = ReadTransaction(trans.get(), &response_data); 541 EXPECT_EQ(OK, rv); 542 EXPECT_EQ("hello world", response_data); 543 } 544 545 TEST_F(HttpNetworkTransactionTest, Incomplete100ThenEOF) { 546 SessionDependencies session_deps; 547 scoped_ptr<HttpTransaction> trans( 548 new HttpNetworkTransaction(CreateSession(&session_deps))); 549 550 HttpRequestInfo request; 551 request.method = "POST"; 552 request.url = GURL("http://www.foo.com/"); 553 request.load_flags = 0; 554 555 MockRead data_reads[] = { 556 MockRead(false, "HTTP/1.0 100 Continue\r\n"), 557 MockRead(true, 0), 558 }; 559 StaticSocketDataProvider data(data_reads, NULL); 560 session_deps.socket_factory.AddSocketDataProvider(&data); 561 562 TestCompletionCallback callback; 563 564 int rv = trans->Start(&request, &callback, NULL); 565 EXPECT_EQ(ERR_IO_PENDING, rv); 566 567 rv = callback.WaitForResult(); 568 EXPECT_EQ(OK, rv); 569 570 std::string response_data; 571 rv = ReadTransaction(trans.get(), &response_data); 572 EXPECT_EQ(OK, rv); 573 EXPECT_EQ("", response_data); 574 } 575 576 TEST_F(HttpNetworkTransactionTest, EmptyResponse) { 577 SessionDependencies session_deps; 578 scoped_ptr<HttpTransaction> trans( 579 new HttpNetworkTransaction(CreateSession(&session_deps))); 580 581 HttpRequestInfo request; 582 request.method = "POST"; 583 request.url = GURL("http://www.foo.com/"); 584 request.load_flags = 0; 585 586 MockRead data_reads[] = { 587 MockRead(true, 0), 588 }; 589 StaticSocketDataProvider data(data_reads, NULL); 590 session_deps.socket_factory.AddSocketDataProvider(&data); 591 592 TestCompletionCallback callback; 593 594 int rv = trans->Start(&request, &callback, NULL); 595 EXPECT_EQ(ERR_IO_PENDING, rv); 596 597 rv = callback.WaitForResult(); 598 EXPECT_EQ(ERR_EMPTY_RESPONSE, rv); 599 } 600 601 // read_failure specifies a read failure that should cause the network 602 // transaction to resend the request. 603 void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest( 604 const MockRead& read_failure) { 605 SessionDependencies session_deps; 606 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); 607 608 HttpRequestInfo request; 609 request.method = "GET"; 610 request.url = GURL("http://www.foo.com/"); 611 request.load_flags = 0; 612 613 MockRead data1_reads[] = { 614 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), 615 MockRead("hello"), 616 read_failure, // Now, we reuse the connection and fail the first read. 617 }; 618 StaticSocketDataProvider data1(data1_reads, NULL); 619 session_deps.socket_factory.AddSocketDataProvider(&data1); 620 621 MockRead data2_reads[] = { 622 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), 623 MockRead("world"), 624 MockRead(true, OK), 625 }; 626 StaticSocketDataProvider data2(data2_reads, NULL); 627 session_deps.socket_factory.AddSocketDataProvider(&data2); 628 629 const char* kExpectedResponseData[] = { 630 "hello", "world" 631 }; 632 633 for (int i = 0; i < 2; ++i) { 634 TestCompletionCallback callback; 635 636 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 637 638 int rv = trans->Start(&request, &callback, NULL); 639 EXPECT_EQ(ERR_IO_PENDING, rv); 640 641 rv = callback.WaitForResult(); 642 EXPECT_EQ(OK, rv); 643 644 const HttpResponseInfo* response = trans->GetResponseInfo(); 645 EXPECT_TRUE(response != NULL); 646 647 EXPECT_TRUE(response->headers != NULL); 648 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 649 650 std::string response_data; 651 rv = ReadTransaction(trans.get(), &response_data); 652 EXPECT_EQ(OK, rv); 653 EXPECT_EQ(kExpectedResponseData[i], response_data); 654 } 655 } 656 657 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) { 658 MockRead read_failure(true, ERR_CONNECTION_RESET); 659 KeepAliveConnectionResendRequestTest(read_failure); 660 } 661 662 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) { 663 MockRead read_failure(false, OK); // EOF 664 KeepAliveConnectionResendRequestTest(read_failure); 665 } 666 667 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) { 668 SessionDependencies session_deps; 669 scoped_ptr<HttpTransaction> trans( 670 new HttpNetworkTransaction(CreateSession(&session_deps))); 671 672 HttpRequestInfo request; 673 request.method = "GET"; 674 request.url = GURL("http://www.google.com/"); 675 request.load_flags = 0; 676 677 MockRead data_reads[] = { 678 MockRead(true, ERR_CONNECTION_RESET), 679 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used 680 MockRead("hello world"), 681 MockRead(false, OK), 682 }; 683 StaticSocketDataProvider data(data_reads, NULL); 684 session_deps.socket_factory.AddSocketDataProvider(&data); 685 686 TestCompletionCallback callback; 687 688 int rv = trans->Start(&request, &callback, NULL); 689 EXPECT_EQ(ERR_IO_PENDING, rv); 690 691 rv = callback.WaitForResult(); 692 EXPECT_EQ(ERR_CONNECTION_RESET, rv); 693 694 const HttpResponseInfo* response = trans->GetResponseInfo(); 695 EXPECT_TRUE(response == NULL); 696 } 697 698 // What do various browsers do when the server closes a non-keepalive 699 // connection without sending any response header or body? 700 // 701 // IE7: error page 702 // Safari 3.1.2 (Windows): error page 703 // Firefox 3.0.1: blank page 704 // Opera 9.52: after five attempts, blank page 705 // Us with WinHTTP: error page (ERR_INVALID_RESPONSE) 706 // Us: error page (EMPTY_RESPONSE) 707 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) { 708 MockRead data_reads[] = { 709 MockRead(false, OK), // EOF 710 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used 711 MockRead("hello world"), 712 MockRead(false, OK), 713 }; 714 SimpleGetHelperResult out = SimpleGetHelper(data_reads); 715 EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv); 716 } 717 718 // Test the request-challenge-retry sequence for basic auth. 719 // (basic auth is the easiest to mock, because it has no randomness). 720 TEST_F(HttpNetworkTransactionTest, BasicAuth) { 721 SessionDependencies session_deps; 722 scoped_ptr<HttpTransaction> trans( 723 new HttpNetworkTransaction(CreateSession(&session_deps))); 724 725 HttpRequestInfo request; 726 request.method = "GET"; 727 request.url = GURL("http://www.google.com/"); 728 request.load_flags = 0; 729 730 MockWrite data_writes1[] = { 731 MockWrite("GET / HTTP/1.1\r\n" 732 "Host: www.google.com\r\n" 733 "Connection: keep-alive\r\n\r\n"), 734 }; 735 736 MockRead data_reads1[] = { 737 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 738 // Give a couple authenticate options (only the middle one is actually 739 // supported). 740 MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed. 741 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 742 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), 743 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 744 // Large content-length -- won't matter, as connection will be reset. 745 MockRead("Content-Length: 10000\r\n\r\n"), 746 MockRead(false, ERR_FAILED), 747 }; 748 749 // After calling trans->RestartWithAuth(), this is the request we should 750 // be issuing -- the final header line contains the credentials. 751 MockWrite data_writes2[] = { 752 MockWrite("GET / HTTP/1.1\r\n" 753 "Host: www.google.com\r\n" 754 "Connection: keep-alive\r\n" 755 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 756 }; 757 758 // Lastly, the server responds with the actual content. 759 MockRead data_reads2[] = { 760 MockRead("HTTP/1.0 200 OK\r\n"), 761 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 762 MockRead("Content-Length: 100\r\n\r\n"), 763 MockRead(false, OK), 764 }; 765 766 StaticSocketDataProvider data1(data_reads1, data_writes1); 767 StaticSocketDataProvider data2(data_reads2, data_writes2); 768 session_deps.socket_factory.AddSocketDataProvider(&data1); 769 session_deps.socket_factory.AddSocketDataProvider(&data2); 770 771 TestCompletionCallback callback1; 772 773 int rv = trans->Start(&request, &callback1, NULL); 774 EXPECT_EQ(ERR_IO_PENDING, rv); 775 776 rv = callback1.WaitForResult(); 777 EXPECT_EQ(OK, rv); 778 779 const HttpResponseInfo* response = trans->GetResponseInfo(); 780 EXPECT_FALSE(response == NULL); 781 782 // The password prompt info should have been set in response->auth_challenge. 783 EXPECT_FALSE(response->auth_challenge.get() == NULL); 784 785 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 786 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 787 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 788 789 TestCompletionCallback callback2; 790 791 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2); 792 EXPECT_EQ(ERR_IO_PENDING, rv); 793 794 rv = callback2.WaitForResult(); 795 EXPECT_EQ(OK, rv); 796 797 response = trans->GetResponseInfo(); 798 EXPECT_FALSE(response == NULL); 799 EXPECT_TRUE(response->auth_challenge.get() == NULL); 800 EXPECT_EQ(100, response->headers->GetContentLength()); 801 } 802 803 TEST_F(HttpNetworkTransactionTest, DoNotSendAuth) { 804 SessionDependencies session_deps; 805 scoped_ptr<HttpTransaction> trans( 806 new HttpNetworkTransaction(CreateSession(&session_deps))); 807 808 HttpRequestInfo request; 809 request.method = "GET"; 810 request.url = GURL("http://www.google.com/"); 811 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; 812 813 MockWrite data_writes[] = { 814 MockWrite("GET / HTTP/1.1\r\n" 815 "Host: www.google.com\r\n" 816 "Connection: keep-alive\r\n\r\n"), 817 }; 818 819 MockRead data_reads[] = { 820 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 821 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 822 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 823 // Large content-length -- won't matter, as connection will be reset. 824 MockRead("Content-Length: 10000\r\n\r\n"), 825 MockRead(false, ERR_FAILED), 826 }; 827 828 StaticSocketDataProvider data(data_reads, data_writes); 829 session_deps.socket_factory.AddSocketDataProvider(&data); 830 TestCompletionCallback callback; 831 832 int rv = trans->Start(&request, &callback, NULL); 833 EXPECT_EQ(ERR_IO_PENDING, rv); 834 835 rv = callback.WaitForResult(); 836 EXPECT_EQ(0, rv); 837 838 const HttpResponseInfo* response = trans->GetResponseInfo(); 839 ASSERT_FALSE(response == NULL); 840 EXPECT_TRUE(response->auth_challenge.get() == NULL); 841 } 842 843 // Test the request-challenge-retry sequence for basic auth, over a keep-alive 844 // connection. 845 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) { 846 SessionDependencies session_deps; 847 scoped_ptr<HttpTransaction> trans( 848 new HttpNetworkTransaction(CreateSession(&session_deps))); 849 850 HttpRequestInfo request; 851 request.method = "GET"; 852 request.url = GURL("http://www.google.com/"); 853 request.load_flags = 0; 854 855 MockWrite data_writes1[] = { 856 MockWrite("GET / HTTP/1.1\r\n" 857 "Host: www.google.com\r\n" 858 "Connection: keep-alive\r\n\r\n"), 859 860 // After calling trans->RestartWithAuth(), this is the request we should 861 // be issuing -- the final header line contains the credentials. 862 MockWrite("GET / HTTP/1.1\r\n" 863 "Host: www.google.com\r\n" 864 "Connection: keep-alive\r\n" 865 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 866 }; 867 868 MockRead data_reads1[] = { 869 MockRead("HTTP/1.1 401 Unauthorized\r\n"), 870 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 871 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 872 MockRead("Content-Length: 14\r\n\r\n"), 873 MockRead("Unauthorized\r\n"), 874 875 // Lastly, the server responds with the actual content. 876 MockRead("HTTP/1.1 200 OK\r\n"), 877 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 878 MockRead("Content-Length: 100\r\n\r\n"), 879 MockRead(false, OK), 880 }; 881 882 StaticSocketDataProvider data1(data_reads1, data_writes1); 883 session_deps.socket_factory.AddSocketDataProvider(&data1); 884 885 TestCompletionCallback callback1; 886 887 int rv = trans->Start(&request, &callback1, NULL); 888 EXPECT_EQ(ERR_IO_PENDING, rv); 889 890 rv = callback1.WaitForResult(); 891 EXPECT_EQ(OK, rv); 892 893 const HttpResponseInfo* response = trans->GetResponseInfo(); 894 EXPECT_FALSE(response == NULL); 895 896 // The password prompt info should have been set in response->auth_challenge. 897 EXPECT_FALSE(response->auth_challenge.get() == NULL); 898 899 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 900 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 901 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 902 903 TestCompletionCallback callback2; 904 905 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2); 906 EXPECT_EQ(ERR_IO_PENDING, rv); 907 908 rv = callback2.WaitForResult(); 909 EXPECT_EQ(OK, rv); 910 911 response = trans->GetResponseInfo(); 912 EXPECT_FALSE(response == NULL); 913 EXPECT_TRUE(response->auth_challenge.get() == NULL); 914 EXPECT_EQ(100, response->headers->GetContentLength()); 915 } 916 917 // Test the request-challenge-retry sequence for basic auth, over a keep-alive 918 // connection and with no response body to drain. 919 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) { 920 SessionDependencies session_deps; 921 scoped_ptr<HttpTransaction> trans( 922 new HttpNetworkTransaction(CreateSession(&session_deps))); 923 924 HttpRequestInfo request; 925 request.method = "GET"; 926 request.url = GURL("http://www.google.com/"); 927 request.load_flags = 0; 928 929 MockWrite data_writes1[] = { 930 MockWrite("GET / HTTP/1.1\r\n" 931 "Host: www.google.com\r\n" 932 "Connection: keep-alive\r\n\r\n"), 933 934 // After calling trans->RestartWithAuth(), this is the request we should 935 // be issuing -- the final header line contains the credentials. 936 MockWrite("GET / HTTP/1.1\r\n" 937 "Host: www.google.com\r\n" 938 "Connection: keep-alive\r\n" 939 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 940 }; 941 942 MockRead data_reads1[] = { 943 MockRead("HTTP/1.1 401 Unauthorized\r\n"), 944 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 945 MockRead("Content-Length: 0\r\n\r\n"), // No response body. 946 947 // Lastly, the server responds with the actual content. 948 MockRead("HTTP/1.1 200 OK\r\n"), 949 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 950 MockRead("Content-Length: 100\r\n\r\n"), 951 MockRead(false, OK), 952 }; 953 954 StaticSocketDataProvider data1(data_reads1, data_writes1); 955 session_deps.socket_factory.AddSocketDataProvider(&data1); 956 957 TestCompletionCallback callback1; 958 959 int rv = trans->Start(&request, &callback1, NULL); 960 EXPECT_EQ(ERR_IO_PENDING, rv); 961 962 rv = callback1.WaitForResult(); 963 EXPECT_EQ(OK, rv); 964 965 const HttpResponseInfo* response = trans->GetResponseInfo(); 966 EXPECT_FALSE(response == NULL); 967 968 // The password prompt info should have been set in response->auth_challenge. 969 EXPECT_FALSE(response->auth_challenge.get() == NULL); 970 971 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 972 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 973 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 974 975 TestCompletionCallback callback2; 976 977 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2); 978 EXPECT_EQ(ERR_IO_PENDING, rv); 979 980 rv = callback2.WaitForResult(); 981 EXPECT_EQ(OK, rv); 982 983 response = trans->GetResponseInfo(); 984 EXPECT_FALSE(response == NULL); 985 EXPECT_TRUE(response->auth_challenge.get() == NULL); 986 EXPECT_EQ(100, response->headers->GetContentLength()); 987 } 988 989 // Test the request-challenge-retry sequence for basic auth, over a keep-alive 990 // connection and with a large response body to drain. 991 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) { 992 SessionDependencies session_deps; 993 scoped_ptr<HttpTransaction> trans( 994 new HttpNetworkTransaction(CreateSession(&session_deps))); 995 996 HttpRequestInfo request; 997 request.method = "GET"; 998 request.url = GURL("http://www.google.com/"); 999 request.load_flags = 0; 1000 1001 MockWrite data_writes1[] = { 1002 MockWrite("GET / HTTP/1.1\r\n" 1003 "Host: www.google.com\r\n" 1004 "Connection: keep-alive\r\n\r\n"), 1005 1006 // After calling trans->RestartWithAuth(), this is the request we should 1007 // be issuing -- the final header line contains the credentials. 1008 MockWrite("GET / HTTP/1.1\r\n" 1009 "Host: www.google.com\r\n" 1010 "Connection: keep-alive\r\n" 1011 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 1012 }; 1013 1014 // Respond with 5 kb of response body. 1015 std::string large_body_string("Unauthorized"); 1016 large_body_string.append(5 * 1024, ' '); 1017 large_body_string.append("\r\n"); 1018 1019 MockRead data_reads1[] = { 1020 MockRead("HTTP/1.1 401 Unauthorized\r\n"), 1021 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1022 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1023 // 5134 = 12 + 5 * 1024 + 2 1024 MockRead("Content-Length: 5134\r\n\r\n"), 1025 MockRead(true, large_body_string.data(), large_body_string.size()), 1026 1027 // Lastly, the server responds with the actual content. 1028 MockRead("HTTP/1.1 200 OK\r\n"), 1029 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1030 MockRead("Content-Length: 100\r\n\r\n"), 1031 MockRead(false, OK), 1032 }; 1033 1034 StaticSocketDataProvider data1(data_reads1, data_writes1); 1035 session_deps.socket_factory.AddSocketDataProvider(&data1); 1036 1037 TestCompletionCallback callback1; 1038 1039 int rv = trans->Start(&request, &callback1, NULL); 1040 EXPECT_EQ(ERR_IO_PENDING, rv); 1041 1042 rv = callback1.WaitForResult(); 1043 EXPECT_EQ(OK, rv); 1044 1045 const HttpResponseInfo* response = trans->GetResponseInfo(); 1046 EXPECT_FALSE(response == NULL); 1047 1048 // The password prompt info should have been set in response->auth_challenge. 1049 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1050 1051 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 1052 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1053 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1054 1055 TestCompletionCallback callback2; 1056 1057 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2); 1058 EXPECT_EQ(ERR_IO_PENDING, rv); 1059 1060 rv = callback2.WaitForResult(); 1061 EXPECT_EQ(OK, rv); 1062 1063 response = trans->GetResponseInfo(); 1064 EXPECT_FALSE(response == NULL); 1065 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1066 EXPECT_EQ(100, response->headers->GetContentLength()); 1067 } 1068 1069 // Test the request-challenge-retry sequence for basic auth, over a keep-alive 1070 // connection, but the server gets impatient and closes the connection. 1071 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) { 1072 SessionDependencies session_deps; 1073 scoped_ptr<HttpTransaction> trans( 1074 new HttpNetworkTransaction(CreateSession(&session_deps))); 1075 1076 HttpRequestInfo request; 1077 request.method = "GET"; 1078 request.url = GURL("http://www.google.com/"); 1079 request.load_flags = 0; 1080 1081 MockWrite data_writes1[] = { 1082 MockWrite("GET / HTTP/1.1\r\n" 1083 "Host: www.google.com\r\n" 1084 "Connection: keep-alive\r\n\r\n"), 1085 // This simulates the seemingly successful write to a closed connection 1086 // if the bug is not fixed. 1087 MockWrite("GET / HTTP/1.1\r\n" 1088 "Host: www.google.com\r\n" 1089 "Connection: keep-alive\r\n" 1090 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 1091 }; 1092 1093 MockRead data_reads1[] = { 1094 MockRead("HTTP/1.1 401 Unauthorized\r\n"), 1095 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1096 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1097 MockRead("Content-Length: 14\r\n\r\n"), 1098 // Tell MockTCPClientSocket to simulate the server closing the connection. 1099 MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), 1100 MockRead("Unauthorized\r\n"), 1101 MockRead(false, OK), // The server closes the connection. 1102 }; 1103 1104 // After calling trans->RestartWithAuth(), this is the request we should 1105 // be issuing -- the final header line contains the credentials. 1106 MockWrite data_writes2[] = { 1107 MockWrite("GET / HTTP/1.1\r\n" 1108 "Host: www.google.com\r\n" 1109 "Connection: keep-alive\r\n" 1110 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 1111 }; 1112 1113 // Lastly, the server responds with the actual content. 1114 MockRead data_reads2[] = { 1115 MockRead("HTTP/1.1 200 OK\r\n"), 1116 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1117 MockRead("Content-Length: 100\r\n\r\n"), 1118 MockRead(false, OK), 1119 }; 1120 1121 StaticSocketDataProvider data1(data_reads1, data_writes1); 1122 StaticSocketDataProvider data2(data_reads2, data_writes2); 1123 session_deps.socket_factory.AddSocketDataProvider(&data1); 1124 session_deps.socket_factory.AddSocketDataProvider(&data2); 1125 1126 TestCompletionCallback callback1; 1127 1128 int rv = trans->Start(&request, &callback1, NULL); 1129 EXPECT_EQ(ERR_IO_PENDING, rv); 1130 1131 rv = callback1.WaitForResult(); 1132 EXPECT_EQ(OK, rv); 1133 1134 const HttpResponseInfo* response = trans->GetResponseInfo(); 1135 EXPECT_FALSE(response == NULL); 1136 1137 // The password prompt info should have been set in response->auth_challenge. 1138 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1139 1140 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 1141 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1142 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1143 1144 TestCompletionCallback callback2; 1145 1146 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2); 1147 EXPECT_EQ(ERR_IO_PENDING, rv); 1148 1149 rv = callback2.WaitForResult(); 1150 EXPECT_EQ(OK, rv); 1151 1152 response = trans->GetResponseInfo(); 1153 ASSERT_FALSE(response == NULL); 1154 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1155 EXPECT_EQ(100, response->headers->GetContentLength()); 1156 } 1157 1158 // Test the request-challenge-retry sequence for basic auth, over a keep-alive 1159 // proxy connection, when setting up an SSL tunnel. 1160 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) { 1161 // Configure against proxy server "myproxy:70". 1162 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); 1163 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1164 1165 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1166 1167 HttpRequestInfo request; 1168 request.method = "GET"; 1169 request.url = GURL("https://www.google.com/"); 1170 // Ensure that proxy authentication is attempted even 1171 // when the no authentication data flag is set. 1172 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; 1173 1174 // Since we have proxy, should try to establish tunnel. 1175 MockWrite data_writes1[] = { 1176 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 1177 "Host: www.google.com\r\n" 1178 "Proxy-Connection: keep-alive\r\n\r\n"), 1179 1180 // After calling trans->RestartWithAuth(), this is the request we should 1181 // be issuing -- the final header line contains the credentials. 1182 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 1183 "Host: www.google.com\r\n" 1184 "Proxy-Connection: keep-alive\r\n" 1185 "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), 1186 }; 1187 1188 // The proxy responds to the connect with a 407, using a persistent 1189 // connection. 1190 MockRead data_reads1[] = { 1191 // No credentials. 1192 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), 1193 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1194 MockRead("Content-Length: 10\r\n\r\n"), 1195 MockRead("0123456789"), 1196 1197 // Wrong credentials (wrong password). 1198 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), 1199 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1200 MockRead("Content-Length: 10\r\n\r\n"), 1201 // No response body because the test stops reading here. 1202 MockRead(false, ERR_UNEXPECTED), // Should not be reached. 1203 }; 1204 1205 StaticSocketDataProvider data1(data_reads1, data_writes1); 1206 session_deps.socket_factory.AddSocketDataProvider(&data1); 1207 1208 TestCompletionCallback callback1; 1209 1210 int rv = trans->Start(&request, &callback1, NULL); 1211 EXPECT_EQ(ERR_IO_PENDING, rv); 1212 1213 rv = callback1.WaitForResult(); 1214 EXPECT_EQ(OK, rv); 1215 1216 const HttpResponseInfo* response = trans->GetResponseInfo(); 1217 EXPECT_FALSE(response == NULL); 1218 1219 EXPECT_TRUE(response->headers->IsKeepAlive()); 1220 EXPECT_EQ(407, response->headers->response_code()); 1221 EXPECT_EQ(10, response->headers->GetContentLength()); 1222 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 1223 1224 // The password prompt info should have been set in response->auth_challenge. 1225 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1226 1227 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port); 1228 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1229 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1230 1231 TestCompletionCallback callback2; 1232 1233 // Wrong password (should be "bar"). 1234 rv = trans->RestartWithAuth(L"foo", L"baz", &callback2); 1235 EXPECT_EQ(ERR_IO_PENDING, rv); 1236 1237 rv = callback2.WaitForResult(); 1238 EXPECT_EQ(OK, rv); 1239 1240 response = trans->GetResponseInfo(); 1241 EXPECT_FALSE(response == NULL); 1242 1243 EXPECT_TRUE(response->headers->IsKeepAlive()); 1244 EXPECT_EQ(407, response->headers->response_code()); 1245 EXPECT_EQ(10, response->headers->GetContentLength()); 1246 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 1247 1248 // The password prompt info should have been set in response->auth_challenge. 1249 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1250 1251 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port); 1252 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1253 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1254 } 1255 1256 // Test that we don't read the response body when we fail to establish a tunnel, 1257 // even if the user cancels the proxy's auth attempt. 1258 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) { 1259 // Configure against proxy server "myproxy:70". 1260 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); 1261 1262 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1263 1264 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1265 1266 HttpRequestInfo request; 1267 request.method = "GET"; 1268 request.url = GURL("https://www.google.com/"); 1269 request.load_flags = 0; 1270 1271 // Since we have proxy, should try to establish tunnel. 1272 MockWrite data_writes[] = { 1273 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 1274 "Host: www.google.com\r\n" 1275 "Proxy-Connection: keep-alive\r\n\r\n"), 1276 }; 1277 1278 // The proxy responds to the connect with a 407. 1279 MockRead data_reads[] = { 1280 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), 1281 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1282 MockRead("Content-Length: 10\r\n\r\n"), 1283 MockRead(false, ERR_UNEXPECTED), // Should not be reached. 1284 }; 1285 1286 StaticSocketDataProvider data(data_reads, data_writes); 1287 session_deps.socket_factory.AddSocketDataProvider(&data); 1288 1289 TestCompletionCallback callback; 1290 1291 int rv = trans->Start(&request, &callback, NULL); 1292 EXPECT_EQ(ERR_IO_PENDING, rv); 1293 1294 rv = callback.WaitForResult(); 1295 EXPECT_EQ(OK, rv); 1296 1297 const HttpResponseInfo* response = trans->GetResponseInfo(); 1298 EXPECT_FALSE(response == NULL); 1299 1300 EXPECT_TRUE(response->headers->IsKeepAlive()); 1301 EXPECT_EQ(407, response->headers->response_code()); 1302 EXPECT_EQ(10, response->headers->GetContentLength()); 1303 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 1304 1305 std::string response_data; 1306 rv = ReadTransaction(trans.get(), &response_data); 1307 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); 1308 } 1309 1310 void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus( 1311 const MockRead& status, int expected_status) { 1312 // Configure against proxy server "myproxy:70". 1313 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); 1314 1315 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1316 1317 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1318 1319 HttpRequestInfo request; 1320 request.method = "GET"; 1321 request.url = GURL("https://www.google.com/"); 1322 request.load_flags = 0; 1323 1324 // Since we have proxy, should try to establish tunnel. 1325 MockWrite data_writes[] = { 1326 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 1327 "Host: www.google.com\r\n" 1328 "Proxy-Connection: keep-alive\r\n\r\n"), 1329 }; 1330 1331 MockRead data_reads[] = { 1332 status, 1333 MockRead("Content-Length: 10\r\n\r\n"), 1334 // No response body because the test stops reading here. 1335 MockRead(false, ERR_UNEXPECTED), // Should not be reached. 1336 }; 1337 1338 StaticSocketDataProvider data(data_reads, data_writes); 1339 session_deps.socket_factory.AddSocketDataProvider(&data); 1340 1341 TestCompletionCallback callback; 1342 1343 int rv = trans->Start(&request, &callback, NULL); 1344 EXPECT_EQ(ERR_IO_PENDING, rv); 1345 1346 rv = callback.WaitForResult(); 1347 EXPECT_EQ(expected_status, rv); 1348 } 1349 1350 void HttpNetworkTransactionTest::ConnectStatusHelper(const MockRead& status) { 1351 ConnectStatusHelperWithExpectedStatus( 1352 status, ERR_TUNNEL_CONNECTION_FAILED); 1353 } 1354 1355 TEST_F(HttpNetworkTransactionTest, ConnectStatus100) { 1356 ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n")); 1357 } 1358 1359 TEST_F(HttpNetworkTransactionTest, ConnectStatus101) { 1360 ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n")); 1361 } 1362 1363 TEST_F(HttpNetworkTransactionTest, ConnectStatus201) { 1364 ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n")); 1365 } 1366 1367 TEST_F(HttpNetworkTransactionTest, ConnectStatus202) { 1368 ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n")); 1369 } 1370 1371 TEST_F(HttpNetworkTransactionTest, ConnectStatus203) { 1372 ConnectStatusHelper( 1373 MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n")); 1374 } 1375 1376 TEST_F(HttpNetworkTransactionTest, ConnectStatus204) { 1377 ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n")); 1378 } 1379 1380 TEST_F(HttpNetworkTransactionTest, ConnectStatus205) { 1381 ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n")); 1382 } 1383 1384 TEST_F(HttpNetworkTransactionTest, ConnectStatus206) { 1385 ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n")); 1386 } 1387 1388 TEST_F(HttpNetworkTransactionTest, ConnectStatus300) { 1389 ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n")); 1390 } 1391 1392 TEST_F(HttpNetworkTransactionTest, ConnectStatus301) { 1393 ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n")); 1394 } 1395 1396 TEST_F(HttpNetworkTransactionTest, ConnectStatus302) { 1397 ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n")); 1398 } 1399 1400 TEST_F(HttpNetworkTransactionTest, ConnectStatus303) { 1401 ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n")); 1402 } 1403 1404 TEST_F(HttpNetworkTransactionTest, ConnectStatus304) { 1405 ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n")); 1406 } 1407 1408 TEST_F(HttpNetworkTransactionTest, ConnectStatus305) { 1409 ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n")); 1410 } 1411 1412 TEST_F(HttpNetworkTransactionTest, ConnectStatus306) { 1413 ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n")); 1414 } 1415 1416 TEST_F(HttpNetworkTransactionTest, ConnectStatus307) { 1417 ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n")); 1418 } 1419 1420 TEST_F(HttpNetworkTransactionTest, ConnectStatus400) { 1421 ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n")); 1422 } 1423 1424 TEST_F(HttpNetworkTransactionTest, ConnectStatus401) { 1425 ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n")); 1426 } 1427 1428 TEST_F(HttpNetworkTransactionTest, ConnectStatus402) { 1429 ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n")); 1430 } 1431 1432 TEST_F(HttpNetworkTransactionTest, ConnectStatus403) { 1433 ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n")); 1434 } 1435 1436 TEST_F(HttpNetworkTransactionTest, ConnectStatus404) { 1437 ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n")); 1438 } 1439 1440 TEST_F(HttpNetworkTransactionTest, ConnectStatus405) { 1441 ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n")); 1442 } 1443 1444 TEST_F(HttpNetworkTransactionTest, ConnectStatus406) { 1445 ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n")); 1446 } 1447 1448 TEST_F(HttpNetworkTransactionTest, ConnectStatus407) { 1449 ConnectStatusHelperWithExpectedStatus( 1450 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), 1451 ERR_PROXY_AUTH_REQUESTED); 1452 } 1453 1454 TEST_F(HttpNetworkTransactionTest, ConnectStatus408) { 1455 ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n")); 1456 } 1457 1458 TEST_F(HttpNetworkTransactionTest, ConnectStatus409) { 1459 ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n")); 1460 } 1461 1462 TEST_F(HttpNetworkTransactionTest, ConnectStatus410) { 1463 ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n")); 1464 } 1465 1466 TEST_F(HttpNetworkTransactionTest, ConnectStatus411) { 1467 ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n")); 1468 } 1469 1470 TEST_F(HttpNetworkTransactionTest, ConnectStatus412) { 1471 ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n")); 1472 } 1473 1474 TEST_F(HttpNetworkTransactionTest, ConnectStatus413) { 1475 ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n")); 1476 } 1477 1478 TEST_F(HttpNetworkTransactionTest, ConnectStatus414) { 1479 ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n")); 1480 } 1481 1482 TEST_F(HttpNetworkTransactionTest, ConnectStatus415) { 1483 ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n")); 1484 } 1485 1486 TEST_F(HttpNetworkTransactionTest, ConnectStatus416) { 1487 ConnectStatusHelper( 1488 MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n")); 1489 } 1490 1491 TEST_F(HttpNetworkTransactionTest, ConnectStatus417) { 1492 ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n")); 1493 } 1494 1495 TEST_F(HttpNetworkTransactionTest, ConnectStatus500) { 1496 ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n")); 1497 } 1498 1499 TEST_F(HttpNetworkTransactionTest, ConnectStatus501) { 1500 ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n")); 1501 } 1502 1503 TEST_F(HttpNetworkTransactionTest, ConnectStatus502) { 1504 ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n")); 1505 } 1506 1507 TEST_F(HttpNetworkTransactionTest, ConnectStatus503) { 1508 ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n")); 1509 } 1510 1511 TEST_F(HttpNetworkTransactionTest, ConnectStatus504) { 1512 ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n")); 1513 } 1514 1515 TEST_F(HttpNetworkTransactionTest, ConnectStatus505) { 1516 ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n")); 1517 } 1518 1519 // Test the flow when both the proxy server AND origin server require 1520 // authentication. Again, this uses basic auth for both since that is 1521 // the simplest to mock. 1522 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) { 1523 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); 1524 1525 // Configure against proxy server "myproxy:70". 1526 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction( 1527 CreateSession(&session_deps))); 1528 1529 HttpRequestInfo request; 1530 request.method = "GET"; 1531 request.url = GURL("http://www.google.com/"); 1532 request.load_flags = 0; 1533 1534 MockWrite data_writes1[] = { 1535 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 1536 "Host: www.google.com\r\n" 1537 "Proxy-Connection: keep-alive\r\n\r\n"), 1538 }; 1539 1540 MockRead data_reads1[] = { 1541 MockRead("HTTP/1.0 407 Unauthorized\r\n"), 1542 // Give a couple authenticate options (only the middle one is actually 1543 // supported). 1544 MockRead("Proxy-Authenticate: Basic invalid\r\n"), // Malformed. 1545 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1546 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), 1547 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1548 // Large content-length -- won't matter, as connection will be reset. 1549 MockRead("Content-Length: 10000\r\n\r\n"), 1550 MockRead(false, ERR_FAILED), 1551 }; 1552 1553 // After calling trans->RestartWithAuth() the first time, this is the 1554 // request we should be issuing -- the final header line contains the 1555 // proxy's credentials. 1556 MockWrite data_writes2[] = { 1557 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 1558 "Host: www.google.com\r\n" 1559 "Proxy-Connection: keep-alive\r\n" 1560 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 1561 }; 1562 1563 // Now the proxy server lets the request pass through to origin server. 1564 // The origin server responds with a 401. 1565 MockRead data_reads2[] = { 1566 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 1567 // Note: We are using the same realm-name as the proxy server. This is 1568 // completely valid, as realms are unique across hosts. 1569 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1570 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1571 MockRead("Content-Length: 2000\r\n\r\n"), 1572 MockRead(false, ERR_FAILED), // Won't be reached. 1573 }; 1574 1575 // After calling trans->RestartWithAuth() the second time, we should send 1576 // the credentials for both the proxy and origin server. 1577 MockWrite data_writes3[] = { 1578 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 1579 "Host: www.google.com\r\n" 1580 "Proxy-Connection: keep-alive\r\n" 1581 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" 1582 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), 1583 }; 1584 1585 // Lastly we get the desired content. 1586 MockRead data_reads3[] = { 1587 MockRead("HTTP/1.0 200 OK\r\n"), 1588 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1589 MockRead("Content-Length: 100\r\n\r\n"), 1590 MockRead(false, OK), 1591 }; 1592 1593 StaticSocketDataProvider data1(data_reads1, data_writes1); 1594 StaticSocketDataProvider data2(data_reads2, data_writes2); 1595 StaticSocketDataProvider data3(data_reads3, data_writes3); 1596 session_deps.socket_factory.AddSocketDataProvider(&data1); 1597 session_deps.socket_factory.AddSocketDataProvider(&data2); 1598 session_deps.socket_factory.AddSocketDataProvider(&data3); 1599 1600 TestCompletionCallback callback1; 1601 1602 int rv = trans->Start(&request, &callback1, NULL); 1603 EXPECT_EQ(ERR_IO_PENDING, rv); 1604 1605 rv = callback1.WaitForResult(); 1606 EXPECT_EQ(OK, rv); 1607 1608 const HttpResponseInfo* response = trans->GetResponseInfo(); 1609 EXPECT_FALSE(response == NULL); 1610 1611 // The password prompt info should have been set in response->auth_challenge. 1612 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1613 1614 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port); 1615 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1616 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1617 1618 TestCompletionCallback callback2; 1619 1620 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2); 1621 EXPECT_EQ(ERR_IO_PENDING, rv); 1622 1623 rv = callback2.WaitForResult(); 1624 EXPECT_EQ(OK, rv); 1625 1626 response = trans->GetResponseInfo(); 1627 EXPECT_FALSE(response == NULL); 1628 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1629 1630 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 1631 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1632 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1633 1634 TestCompletionCallback callback3; 1635 1636 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback3); 1637 EXPECT_EQ(ERR_IO_PENDING, rv); 1638 1639 rv = callback3.WaitForResult(); 1640 EXPECT_EQ(OK, rv); 1641 1642 response = trans->GetResponseInfo(); 1643 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1644 EXPECT_EQ(100, response->headers->GetContentLength()); 1645 } 1646 1647 // For the NTLM implementation using SSPI, we skip the NTLM tests since we 1648 // can't hook into its internals to cause it to generate predictable NTLM 1649 // authorization headers. 1650 #if defined(NTLM_PORTABLE) 1651 // The NTLM authentication unit tests were generated by capturing the HTTP 1652 // requests and responses using Fiddler 2 and inspecting the generated random 1653 // bytes in the debugger. 1654 1655 // Enter the correct password and authenticate successfully. 1656 TEST_F(HttpNetworkTransactionTest, NTLMAuth1) { 1657 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1, 1658 MockGetHostName); 1659 SessionDependencies session_deps; 1660 scoped_ptr<HttpTransaction> trans( 1661 new HttpNetworkTransaction(CreateSession(&session_deps))); 1662 1663 HttpRequestInfo request; 1664 request.method = "GET"; 1665 request.url = GURL("http://172.22.68.17/kids/login.aspx"); 1666 request.load_flags = 0; 1667 1668 MockWrite data_writes1[] = { 1669 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 1670 "Host: 172.22.68.17\r\n" 1671 "Connection: keep-alive\r\n\r\n"), 1672 }; 1673 1674 MockRead data_reads1[] = { 1675 MockRead("HTTP/1.1 401 Access Denied\r\n"), 1676 // Negotiate and NTLM are often requested together. We only support NTLM. 1677 MockRead("WWW-Authenticate: Negotiate\r\n"), 1678 MockRead("WWW-Authenticate: NTLM\r\n"), 1679 MockRead("Connection: close\r\n"), 1680 MockRead("Content-Length: 42\r\n"), 1681 MockRead("Content-Type: text/html\r\n\r\n"), 1682 // Missing content -- won't matter, as connection will be reset. 1683 MockRead(false, ERR_UNEXPECTED), 1684 }; 1685 1686 MockWrite data_writes2[] = { 1687 // After restarting with a null identity, this is the 1688 // request we should be issuing -- the final header line contains a Type 1689 // 1 message. 1690 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 1691 "Host: 172.22.68.17\r\n" 1692 "Connection: keep-alive\r\n" 1693 "Authorization: NTLM " 1694 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), 1695 1696 // After calling trans->RestartWithAuth(), we should send a Type 3 message 1697 // (the credentials for the origin server). The second request continues 1698 // on the same connection. 1699 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 1700 "Host: 172.22.68.17\r\n" 1701 "Connection: keep-alive\r\n" 1702 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" 1703 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" 1704 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW" 1705 "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX" 1706 "ahlhx5I=\r\n\r\n"), 1707 }; 1708 1709 MockRead data_reads2[] = { 1710 // The origin server responds with a Type 2 message. 1711 MockRead("HTTP/1.1 401 Access Denied\r\n"), 1712 MockRead("WWW-Authenticate: NTLM " 1713 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo" 1714 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" 1715 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" 1716 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" 1717 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" 1718 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" 1719 "BtAAAAAAA=\r\n"), 1720 MockRead("Content-Length: 42\r\n"), 1721 MockRead("Content-Type: text/html\r\n\r\n"), 1722 MockRead("You are not authorized to view this page\r\n"), 1723 1724 // Lastly we get the desired content. 1725 MockRead("HTTP/1.1 200 OK\r\n"), 1726 MockRead("Content-Type: text/html; charset=utf-8\r\n"), 1727 MockRead("Content-Length: 13\r\n\r\n"), 1728 MockRead("Please Login\r\n"), 1729 MockRead(false, OK), 1730 }; 1731 1732 StaticSocketDataProvider data1(data_reads1, data_writes1); 1733 StaticSocketDataProvider data2(data_reads2, data_writes2); 1734 session_deps.socket_factory.AddSocketDataProvider(&data1); 1735 session_deps.socket_factory.AddSocketDataProvider(&data2); 1736 1737 TestCompletionCallback callback1; 1738 1739 int rv = trans->Start(&request, &callback1, NULL); 1740 EXPECT_EQ(ERR_IO_PENDING, rv); 1741 1742 rv = callback1.WaitForResult(); 1743 EXPECT_EQ(OK, rv); 1744 1745 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 1746 TestCompletionCallback callback2; 1747 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2); 1748 EXPECT_EQ(ERR_IO_PENDING, rv); 1749 rv = callback2.WaitForResult(); 1750 EXPECT_EQ(OK, rv); 1751 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 1752 1753 const HttpResponseInfo* response = trans->GetResponseInfo(); 1754 EXPECT_FALSE(response == NULL); 1755 1756 // The password prompt info should have been set in response->auth_challenge. 1757 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1758 1759 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port); 1760 EXPECT_EQ(L"", response->auth_challenge->realm); 1761 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme); 1762 1763 TestCompletionCallback callback3; 1764 1765 rv = trans->RestartWithAuth(L"testing-ntlm", L"testing-ntlm", &callback3); 1766 EXPECT_EQ(ERR_IO_PENDING, rv); 1767 1768 rv = callback3.WaitForResult(); 1769 EXPECT_EQ(OK, rv); 1770 1771 response = trans->GetResponseInfo(); 1772 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1773 EXPECT_EQ(13, response->headers->GetContentLength()); 1774 } 1775 1776 // Enter a wrong password, and then the correct one. 1777 TEST_F(HttpNetworkTransactionTest, NTLMAuth2) { 1778 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom2, 1779 MockGetHostName); 1780 SessionDependencies session_deps; 1781 scoped_ptr<HttpTransaction> trans( 1782 new HttpNetworkTransaction(CreateSession(&session_deps))); 1783 1784 HttpRequestInfo request; 1785 request.method = "GET"; 1786 request.url = GURL("http://172.22.68.17/kids/login.aspx"); 1787 request.load_flags = 0; 1788 1789 MockWrite data_writes1[] = { 1790 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 1791 "Host: 172.22.68.17\r\n" 1792 "Connection: keep-alive\r\n\r\n"), 1793 }; 1794 1795 MockRead data_reads1[] = { 1796 MockRead("HTTP/1.1 401 Access Denied\r\n"), 1797 // Negotiate and NTLM are often requested together. We only support NTLM. 1798 MockRead("WWW-Authenticate: Negotiate\r\n"), 1799 MockRead("WWW-Authenticate: NTLM\r\n"), 1800 MockRead("Connection: close\r\n"), 1801 MockRead("Content-Length: 42\r\n"), 1802 MockRead("Content-Type: text/html\r\n\r\n"), 1803 // Missing content -- won't matter, as connection will be reset. 1804 MockRead(false, ERR_UNEXPECTED), 1805 }; 1806 1807 MockWrite data_writes2[] = { 1808 // After restarting with a null identity, this is the 1809 // request we should be issuing -- the final header line contains a Type 1810 // 1 message. 1811 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 1812 "Host: 172.22.68.17\r\n" 1813 "Connection: keep-alive\r\n" 1814 "Authorization: NTLM " 1815 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), 1816 1817 // After calling trans->RestartWithAuth(), we should send a Type 3 message 1818 // (the credentials for the origin server). The second request continues 1819 // on the same connection. 1820 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 1821 "Host: 172.22.68.17\r\n" 1822 "Connection: keep-alive\r\n" 1823 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" 1824 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" 1825 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY" 1826 "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj" 1827 "4Ww7b7E=\r\n\r\n"), 1828 }; 1829 1830 MockRead data_reads2[] = { 1831 // The origin server responds with a Type 2 message. 1832 MockRead("HTTP/1.1 401 Access Denied\r\n"), 1833 MockRead("WWW-Authenticate: NTLM " 1834 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCbVWUZezVGpAAAAAAAAAAALo" 1835 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" 1836 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" 1837 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" 1838 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" 1839 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" 1840 "BtAAAAAAA=\r\n"), 1841 MockRead("Content-Length: 42\r\n"), 1842 MockRead("Content-Type: text/html\r\n\r\n"), 1843 MockRead("You are not authorized to view this page\r\n"), 1844 1845 // Wrong password. 1846 MockRead("HTTP/1.1 401 Access Denied\r\n"), 1847 MockRead("WWW-Authenticate: Negotiate\r\n"), 1848 MockRead("WWW-Authenticate: NTLM\r\n"), 1849 MockRead("Connection: close\r\n"), 1850 MockRead("Content-Length: 42\r\n"), 1851 MockRead("Content-Type: text/html\r\n\r\n"), 1852 // Missing content -- won't matter, as connection will be reset. 1853 MockRead(false, ERR_UNEXPECTED), 1854 }; 1855 1856 MockWrite data_writes3[] = { 1857 // After restarting with a null identity, this is the 1858 // request we should be issuing -- the final header line contains a Type 1859 // 1 message. 1860 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 1861 "Host: 172.22.68.17\r\n" 1862 "Connection: keep-alive\r\n" 1863 "Authorization: NTLM " 1864 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), 1865 1866 // After calling trans->RestartWithAuth(), we should send a Type 3 message 1867 // (the credentials for the origin server). The second request continues 1868 // on the same connection. 1869 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 1870 "Host: 172.22.68.17\r\n" 1871 "Connection: keep-alive\r\n" 1872 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" 1873 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" 1874 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54" 1875 "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI" 1876 "+4MUm7c=\r\n\r\n"), 1877 }; 1878 1879 MockRead data_reads3[] = { 1880 // The origin server responds with a Type 2 message. 1881 MockRead("HTTP/1.1 401 Access Denied\r\n"), 1882 MockRead("WWW-Authenticate: NTLM " 1883 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCL24VN8dgOR8AAAAAAAAAALo" 1884 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" 1885 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" 1886 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" 1887 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" 1888 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" 1889 "BtAAAAAAA=\r\n"), 1890 MockRead("Content-Length: 42\r\n"), 1891 MockRead("Content-Type: text/html\r\n\r\n"), 1892 MockRead("You are not authorized to view this page\r\n"), 1893 1894 // Lastly we get the desired content. 1895 MockRead("HTTP/1.1 200 OK\r\n"), 1896 MockRead("Content-Type: text/html; charset=utf-8\r\n"), 1897 MockRead("Content-Length: 13\r\n\r\n"), 1898 MockRead("Please Login\r\n"), 1899 MockRead(false, OK), 1900 }; 1901 1902 StaticSocketDataProvider data1(data_reads1, data_writes1); 1903 StaticSocketDataProvider data2(data_reads2, data_writes2); 1904 StaticSocketDataProvider data3(data_reads3, data_writes3); 1905 session_deps.socket_factory.AddSocketDataProvider(&data1); 1906 session_deps.socket_factory.AddSocketDataProvider(&data2); 1907 session_deps.socket_factory.AddSocketDataProvider(&data3); 1908 1909 TestCompletionCallback callback1; 1910 1911 int rv = trans->Start(&request, &callback1, NULL); 1912 EXPECT_EQ(ERR_IO_PENDING, rv); 1913 1914 rv = callback1.WaitForResult(); 1915 EXPECT_EQ(OK, rv); 1916 1917 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 1918 TestCompletionCallback callback2; 1919 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2); 1920 EXPECT_EQ(ERR_IO_PENDING, rv); 1921 rv = callback2.WaitForResult(); 1922 EXPECT_EQ(OK, rv); 1923 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 1924 1925 const HttpResponseInfo* response = trans->GetResponseInfo(); 1926 EXPECT_FALSE(response == NULL); 1927 1928 // The password prompt info should have been set in response->auth_challenge. 1929 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1930 1931 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port); 1932 EXPECT_EQ(L"", response->auth_challenge->realm); 1933 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme); 1934 1935 TestCompletionCallback callback3; 1936 1937 // Enter the wrong password. 1938 rv = trans->RestartWithAuth(L"testing-ntlm", L"wrongpassword", &callback3); 1939 EXPECT_EQ(ERR_IO_PENDING, rv); 1940 1941 rv = callback3.WaitForResult(); 1942 EXPECT_EQ(OK, rv); 1943 1944 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 1945 TestCompletionCallback callback4; 1946 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback4); 1947 EXPECT_EQ(ERR_IO_PENDING, rv); 1948 rv = callback4.WaitForResult(); 1949 EXPECT_EQ(OK, rv); 1950 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 1951 1952 response = trans->GetResponseInfo(); 1953 EXPECT_FALSE(response == NULL); 1954 1955 // The password prompt info should have been set in response->auth_challenge. 1956 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1957 1958 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port); 1959 EXPECT_EQ(L"", response->auth_challenge->realm); 1960 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme); 1961 1962 TestCompletionCallback callback5; 1963 1964 // Now enter the right password. 1965 rv = trans->RestartWithAuth(L"testing-ntlm", L"testing-ntlm", &callback5); 1966 EXPECT_EQ(ERR_IO_PENDING, rv); 1967 1968 rv = callback5.WaitForResult(); 1969 EXPECT_EQ(OK, rv); 1970 1971 response = trans->GetResponseInfo(); 1972 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1973 EXPECT_EQ(13, response->headers->GetContentLength()); 1974 } 1975 #endif // NTLM_PORTABLE 1976 1977 // Test reading a server response which has only headers, and no body. 1978 // After some maximum number of bytes is consumed, the transaction should 1979 // fail with ERR_RESPONSE_HEADERS_TOO_BIG. 1980 TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) { 1981 SessionDependencies session_deps; 1982 scoped_ptr<HttpTransaction> trans( 1983 new HttpNetworkTransaction(CreateSession(&session_deps))); 1984 1985 HttpRequestInfo request; 1986 request.method = "GET"; 1987 request.url = GURL("http://www.google.com/"); 1988 request.load_flags = 0; 1989 1990 // Respond with 300 kb of headers (we should fail after 256 kb). 1991 std::string large_headers_string; 1992 FillLargeHeadersString(&large_headers_string, 300 * 1024); 1993 1994 MockRead data_reads[] = { 1995 MockRead("HTTP/1.0 200 OK\r\n"), 1996 MockRead(true, large_headers_string.data(), large_headers_string.size()), 1997 MockRead("\r\nBODY"), 1998 MockRead(false, OK), 1999 }; 2000 StaticSocketDataProvider data(data_reads, NULL); 2001 session_deps.socket_factory.AddSocketDataProvider(&data); 2002 2003 TestCompletionCallback callback; 2004 2005 int rv = trans->Start(&request, &callback, NULL); 2006 EXPECT_EQ(ERR_IO_PENDING, rv); 2007 2008 rv = callback.WaitForResult(); 2009 EXPECT_EQ(ERR_RESPONSE_HEADERS_TOO_BIG, rv); 2010 2011 const HttpResponseInfo* response = trans->GetResponseInfo(); 2012 EXPECT_TRUE(response == NULL); 2013 } 2014 2015 // Make sure that we don't try to reuse a TCPClientSocket when failing to 2016 // establish tunnel. 2017 // http://code.google.com/p/chromium/issues/detail?id=3772 2018 TEST_F(HttpNetworkTransactionTest, DontRecycleTCPSocketForSSLTunnel) { 2019 // Configure against proxy server "myproxy:70". 2020 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); 2021 2022 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 2023 2024 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2025 2026 HttpRequestInfo request; 2027 request.method = "GET"; 2028 request.url = GURL("https://www.google.com/"); 2029 request.load_flags = 0; 2030 2031 // Since we have proxy, should try to establish tunnel. 2032 MockWrite data_writes1[] = { 2033 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 2034 "Host: www.google.com\r\n" 2035 "Proxy-Connection: keep-alive\r\n\r\n"), 2036 }; 2037 2038 // The proxy responds to the connect with a 404, using a persistent 2039 // connection. Usually a proxy would return 501 (not implemented), 2040 // or 200 (tunnel established). 2041 MockRead data_reads1[] = { 2042 MockRead("HTTP/1.1 404 Not Found\r\n"), 2043 MockRead("Content-Length: 10\r\n\r\n"), 2044 MockRead(false, ERR_UNEXPECTED), // Should not be reached. 2045 }; 2046 2047 StaticSocketDataProvider data1(data_reads1, data_writes1); 2048 session_deps.socket_factory.AddSocketDataProvider(&data1); 2049 2050 TestCompletionCallback callback1; 2051 2052 int rv = trans->Start(&request, &callback1, NULL); 2053 EXPECT_EQ(ERR_IO_PENDING, rv); 2054 2055 rv = callback1.WaitForResult(); 2056 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); 2057 2058 const HttpResponseInfo* response = trans->GetResponseInfo(); 2059 EXPECT_TRUE(response == NULL); 2060 2061 // Empty the current queue. This is necessary because idle sockets are 2062 // added to the connection pool asynchronously with a PostTask. 2063 MessageLoop::current()->RunAllPending(); 2064 2065 // We now check to make sure the TCPClientSocket was not added back to 2066 // the pool. 2067 EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); 2068 trans.reset(); 2069 MessageLoop::current()->RunAllPending(); 2070 // Make sure that the socket didn't get recycled after calling the destructor. 2071 EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); 2072 } 2073 2074 // Make sure that we recycle a socket after reading all of the response body. 2075 TEST_F(HttpNetworkTransactionTest, RecycleSocket) { 2076 SessionDependencies session_deps; 2077 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 2078 2079 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2080 2081 HttpRequestInfo request; 2082 request.method = "GET"; 2083 request.url = GURL("http://www.google.com/"); 2084 request.load_flags = 0; 2085 2086 MockRead data_reads[] = { 2087 // A part of the response body is received with the response headers. 2088 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"), 2089 // The rest of the response body is received in two parts. 2090 MockRead("lo"), 2091 MockRead(" world"), 2092 MockRead("junk"), // Should not be read!! 2093 MockRead(false, OK), 2094 }; 2095 2096 StaticSocketDataProvider data(data_reads, NULL); 2097 session_deps.socket_factory.AddSocketDataProvider(&data); 2098 2099 TestCompletionCallback callback; 2100 2101 int rv = trans->Start(&request, &callback, NULL); 2102 EXPECT_EQ(ERR_IO_PENDING, rv); 2103 2104 rv = callback.WaitForResult(); 2105 EXPECT_EQ(OK, rv); 2106 2107 const HttpResponseInfo* response = trans->GetResponseInfo(); 2108 EXPECT_TRUE(response != NULL); 2109 2110 EXPECT_TRUE(response->headers != NULL); 2111 std::string status_line = response->headers->GetStatusLine(); 2112 EXPECT_EQ("HTTP/1.1 200 OK", status_line); 2113 2114 EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); 2115 2116 std::string response_data; 2117 rv = ReadTransaction(trans.get(), &response_data); 2118 EXPECT_EQ(OK, rv); 2119 EXPECT_EQ("hello world", response_data); 2120 2121 // Empty the current queue. This is necessary because idle sockets are 2122 // added to the connection pool asynchronously with a PostTask. 2123 MessageLoop::current()->RunAllPending(); 2124 2125 // We now check to make sure the socket was added back to the pool. 2126 EXPECT_EQ(1, session->tcp_socket_pool()->IdleSocketCount()); 2127 } 2128 2129 // Make sure that we recycle a socket after a zero-length response. 2130 // http://crbug.com/9880 2131 TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) { 2132 SessionDependencies session_deps; 2133 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 2134 2135 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2136 2137 HttpRequestInfo request; 2138 request.method = "GET"; 2139 request.url = GURL("http://www.google.com/csi?v=3&s=web&action=&" 2140 "tran=undefined&ei=mAXcSeegAo-SMurloeUN&" 2141 "e=17259,18167,19592,19773,19981,20133,20173,20233&" 2142 "rt=prt.2642,ol.2649,xjs.2951"); 2143 request.load_flags = 0; 2144 2145 MockRead data_reads[] = { 2146 MockRead("HTTP/1.1 204 No Content\r\n" 2147 "Content-Length: 0\r\n" 2148 "Content-Type: text/html\r\n\r\n"), 2149 MockRead("junk"), // Should not be read!! 2150 MockRead(false, OK), 2151 }; 2152 2153 StaticSocketDataProvider data(data_reads, NULL); 2154 session_deps.socket_factory.AddSocketDataProvider(&data); 2155 2156 TestCompletionCallback callback; 2157 2158 int rv = trans->Start(&request, &callback, NULL); 2159 EXPECT_EQ(ERR_IO_PENDING, rv); 2160 2161 rv = callback.WaitForResult(); 2162 EXPECT_EQ(OK, rv); 2163 2164 const HttpResponseInfo* response = trans->GetResponseInfo(); 2165 EXPECT_TRUE(response != NULL); 2166 2167 EXPECT_TRUE(response->headers != NULL); 2168 std::string status_line = response->headers->GetStatusLine(); 2169 EXPECT_EQ("HTTP/1.1 204 No Content", status_line); 2170 2171 EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); 2172 2173 std::string response_data; 2174 rv = ReadTransaction(trans.get(), &response_data); 2175 EXPECT_EQ(OK, rv); 2176 EXPECT_EQ("", response_data); 2177 2178 // Empty the current queue. This is necessary because idle sockets are 2179 // added to the connection pool asynchronously with a PostTask. 2180 MessageLoop::current()->RunAllPending(); 2181 2182 // We now check to make sure the socket was added back to the pool. 2183 EXPECT_EQ(1, session->tcp_socket_pool()->IdleSocketCount()); 2184 } 2185 2186 TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) { 2187 HttpRequestInfo request[2]; 2188 // Transaction 1: a GET request that succeeds. The socket is recycled 2189 // after use. 2190 request[0].method = "GET"; 2191 request[0].url = GURL("http://www.google.com/"); 2192 request[0].load_flags = 0; 2193 // Transaction 2: a POST request. Reuses the socket kept alive from 2194 // transaction 1. The first attempts fails when writing the POST data. 2195 // This causes the transaction to retry with a new socket. The second 2196 // attempt succeeds. 2197 request[1].method = "POST"; 2198 request[1].url = GURL("http://www.google.com/login.cgi"); 2199 request[1].upload_data = new UploadData; 2200 request[1].upload_data->AppendBytes("foo", 3); 2201 request[1].load_flags = 0; 2202 2203 SessionDependencies session_deps; 2204 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); 2205 2206 // The first socket is used for transaction 1 and the first attempt of 2207 // transaction 2. 2208 2209 // The response of transaction 1. 2210 MockRead data_reads1[] = { 2211 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"), 2212 MockRead("hello world"), 2213 MockRead(false, OK), 2214 }; 2215 // The mock write results of transaction 1 and the first attempt of 2216 // transaction 2. 2217 MockWrite data_writes1[] = { 2218 MockWrite(false, 64), // GET 2219 MockWrite(false, 93), // POST 2220 MockWrite(false, ERR_CONNECTION_ABORTED), // POST data 2221 }; 2222 StaticSocketDataProvider data1(data_reads1, data_writes1); 2223 2224 // The second socket is used for the second attempt of transaction 2. 2225 2226 // The response of transaction 2. 2227 MockRead data_reads2[] = { 2228 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"), 2229 MockRead("welcome"), 2230 MockRead(false, OK), 2231 }; 2232 // The mock write results of the second attempt of transaction 2. 2233 MockWrite data_writes2[] = { 2234 MockWrite(false, 93), // POST 2235 MockWrite(false, 3), // POST data 2236 }; 2237 StaticSocketDataProvider data2(data_reads2, data_writes2); 2238 2239 session_deps.socket_factory.AddSocketDataProvider(&data1); 2240 session_deps.socket_factory.AddSocketDataProvider(&data2); 2241 2242 const char* kExpectedResponseData[] = { 2243 "hello world", "welcome" 2244 }; 2245 2246 for (int i = 0; i < 2; ++i) { 2247 scoped_ptr<HttpTransaction> trans( 2248 new HttpNetworkTransaction(session)); 2249 2250 TestCompletionCallback callback; 2251 2252 int rv = trans->Start(&request[i], &callback, NULL); 2253 EXPECT_EQ(ERR_IO_PENDING, rv); 2254 2255 rv = callback.WaitForResult(); 2256 EXPECT_EQ(OK, rv); 2257 2258 const HttpResponseInfo* response = trans->GetResponseInfo(); 2259 EXPECT_TRUE(response != NULL); 2260 2261 EXPECT_TRUE(response->headers != NULL); 2262 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 2263 2264 std::string response_data; 2265 rv = ReadTransaction(trans.get(), &response_data); 2266 EXPECT_EQ(OK, rv); 2267 EXPECT_EQ(kExpectedResponseData[i], response_data); 2268 } 2269 } 2270 2271 // Test the request-challenge-retry sequence for basic auth when there is 2272 // an identity in the URL. The request should be sent as normal, but when 2273 // it fails the identity from the URL is used to answer the challenge. 2274 TEST_F(HttpNetworkTransactionTest, AuthIdentityInURL) { 2275 SessionDependencies session_deps; 2276 scoped_ptr<HttpTransaction> trans( 2277 new HttpNetworkTransaction(CreateSession(&session_deps))); 2278 2279 HttpRequestInfo request; 2280 request.method = "GET"; 2281 // Note: the URL has a username:password in it. 2282 request.url = GURL("http://foo:b@r@www.google.com/"); 2283 2284 // The password contains an escaped character -- for this test to pass it 2285 // will need to be unescaped by HttpNetworkTransaction. 2286 EXPECT_EQ("b%40r", request.url.password()); 2287 2288 request.load_flags = LOAD_NORMAL; 2289 2290 MockWrite data_writes1[] = { 2291 MockWrite("GET / HTTP/1.1\r\n" 2292 "Host: www.google.com\r\n" 2293 "Connection: keep-alive\r\n\r\n"), 2294 }; 2295 2296 MockRead data_reads1[] = { 2297 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 2298 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 2299 MockRead("Content-Length: 10\r\n\r\n"), 2300 MockRead(false, ERR_FAILED), 2301 }; 2302 2303 // After the challenge above, the transaction will be restarted using the 2304 // identity from the url (foo, b@r) to answer the challenge. 2305 MockWrite data_writes2[] = { 2306 MockWrite("GET / HTTP/1.1\r\n" 2307 "Host: www.google.com\r\n" 2308 "Connection: keep-alive\r\n" 2309 "Authorization: Basic Zm9vOmJAcg==\r\n\r\n"), 2310 }; 2311 2312 MockRead data_reads2[] = { 2313 MockRead("HTTP/1.0 200 OK\r\n"), 2314 MockRead("Content-Length: 100\r\n\r\n"), 2315 MockRead(false, OK), 2316 }; 2317 2318 StaticSocketDataProvider data1(data_reads1, data_writes1); 2319 StaticSocketDataProvider data2(data_reads2, data_writes2); 2320 session_deps.socket_factory.AddSocketDataProvider(&data1); 2321 session_deps.socket_factory.AddSocketDataProvider(&data2); 2322 2323 TestCompletionCallback callback1; 2324 2325 int rv = trans->Start(&request, &callback1, NULL); 2326 EXPECT_EQ(ERR_IO_PENDING, rv); 2327 2328 rv = callback1.WaitForResult(); 2329 EXPECT_EQ(OK, rv); 2330 2331 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 2332 TestCompletionCallback callback2; 2333 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2); 2334 EXPECT_EQ(ERR_IO_PENDING, rv); 2335 rv = callback2.WaitForResult(); 2336 EXPECT_EQ(OK, rv); 2337 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 2338 2339 const HttpResponseInfo* response = trans->GetResponseInfo(); 2340 EXPECT_FALSE(response == NULL); 2341 2342 // There is no challenge info, since the identity in URL worked. 2343 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2344 2345 EXPECT_EQ(100, response->headers->GetContentLength()); 2346 2347 // Empty the current queue. 2348 MessageLoop::current()->RunAllPending(); 2349 } 2350 2351 // Test the request-challenge-retry sequence for basic auth when there is 2352 // an incorrect identity in the URL. The identity from the URL should be used 2353 // only once. 2354 TEST_F(HttpNetworkTransactionTest, WrongAuthIdentityInURL) { 2355 SessionDependencies session_deps; 2356 scoped_ptr<HttpTransaction> trans( 2357 new HttpNetworkTransaction(CreateSession(&session_deps))); 2358 2359 HttpRequestInfo request; 2360 request.method = "GET"; 2361 // Note: the URL has a username:password in it. The password "baz" is 2362 // wrong (should be "bar"). 2363 request.url = GURL("http://foo:baz@www.google.com/"); 2364 2365 request.load_flags = LOAD_NORMAL; 2366 2367 MockWrite data_writes1[] = { 2368 MockWrite("GET / HTTP/1.1\r\n" 2369 "Host: www.google.com\r\n" 2370 "Connection: keep-alive\r\n\r\n"), 2371 }; 2372 2373 MockRead data_reads1[] = { 2374 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 2375 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 2376 MockRead("Content-Length: 10\r\n\r\n"), 2377 MockRead(false, ERR_FAILED), 2378 }; 2379 2380 // After the challenge above, the transaction will be restarted using the 2381 // identity from the url (foo, baz) to answer the challenge. 2382 MockWrite data_writes2[] = { 2383 MockWrite("GET / HTTP/1.1\r\n" 2384 "Host: www.google.com\r\n" 2385 "Connection: keep-alive\r\n" 2386 "Authorization: Basic Zm9vOmJheg==\r\n\r\n"), 2387 }; 2388 2389 MockRead data_reads2[] = { 2390 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 2391 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 2392 MockRead("Content-Length: 10\r\n\r\n"), 2393 MockRead(false, ERR_FAILED), 2394 }; 2395 2396 // After the challenge above, the transaction will be restarted using the 2397 // identity supplied by the user (foo, bar) to answer the challenge. 2398 MockWrite data_writes3[] = { 2399 MockWrite("GET / HTTP/1.1\r\n" 2400 "Host: www.google.com\r\n" 2401 "Connection: keep-alive\r\n" 2402 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 2403 }; 2404 2405 MockRead data_reads3[] = { 2406 MockRead("HTTP/1.0 200 OK\r\n"), 2407 MockRead("Content-Length: 100\r\n\r\n"), 2408 MockRead(false, OK), 2409 }; 2410 2411 StaticSocketDataProvider data1(data_reads1, data_writes1); 2412 StaticSocketDataProvider data2(data_reads2, data_writes2); 2413 StaticSocketDataProvider data3(data_reads3, data_writes3); 2414 session_deps.socket_factory.AddSocketDataProvider(&data1); 2415 session_deps.socket_factory.AddSocketDataProvider(&data2); 2416 session_deps.socket_factory.AddSocketDataProvider(&data3); 2417 2418 TestCompletionCallback callback1; 2419 2420 int rv = trans->Start(&request, &callback1, NULL); 2421 EXPECT_EQ(ERR_IO_PENDING, rv); 2422 2423 rv = callback1.WaitForResult(); 2424 EXPECT_EQ(OK, rv); 2425 2426 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 2427 TestCompletionCallback callback2; 2428 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2); 2429 EXPECT_EQ(ERR_IO_PENDING, rv); 2430 rv = callback2.WaitForResult(); 2431 EXPECT_EQ(OK, rv); 2432 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 2433 2434 const HttpResponseInfo* response = trans->GetResponseInfo(); 2435 EXPECT_FALSE(response == NULL); 2436 // The password prompt info should have been set in response->auth_challenge. 2437 EXPECT_FALSE(response->auth_challenge.get() == NULL); 2438 2439 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 2440 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 2441 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 2442 2443 TestCompletionCallback callback3; 2444 rv = trans->RestartWithAuth(L"foo", L"bar", &callback3); 2445 EXPECT_EQ(ERR_IO_PENDING, rv); 2446 rv = callback3.WaitForResult(); 2447 EXPECT_EQ(OK, rv); 2448 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 2449 2450 response = trans->GetResponseInfo(); 2451 EXPECT_FALSE(response == NULL); 2452 2453 // There is no challenge info, since the identity worked. 2454 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2455 2456 EXPECT_EQ(100, response->headers->GetContentLength()); 2457 2458 // Empty the current queue. 2459 MessageLoop::current()->RunAllPending(); 2460 } 2461 2462 // Test that previously tried username/passwords for a realm get re-used. 2463 TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) { 2464 SessionDependencies session_deps; 2465 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); 2466 2467 // Transaction 1: authenticate (foo, bar) on MyRealm1 2468 { 2469 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2470 2471 HttpRequestInfo request; 2472 request.method = "GET"; 2473 request.url = GURL("http://www.google.com/x/y/z"); 2474 request.load_flags = 0; 2475 2476 MockWrite data_writes1[] = { 2477 MockWrite("GET /x/y/z HTTP/1.1\r\n" 2478 "Host: www.google.com\r\n" 2479 "Connection: keep-alive\r\n\r\n"), 2480 }; 2481 2482 MockRead data_reads1[] = { 2483 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 2484 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 2485 MockRead("Content-Length: 10000\r\n\r\n"), 2486 MockRead(false, ERR_FAILED), 2487 }; 2488 2489 // Resend with authorization (username=foo, password=bar) 2490 MockWrite data_writes2[] = { 2491 MockWrite("GET /x/y/z HTTP/1.1\r\n" 2492 "Host: www.google.com\r\n" 2493 "Connection: keep-alive\r\n" 2494 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 2495 }; 2496 2497 // Sever accepts the authorization. 2498 MockRead data_reads2[] = { 2499 MockRead("HTTP/1.0 200 OK\r\n"), 2500 MockRead("Content-Length: 100\r\n\r\n"), 2501 MockRead(false, OK), 2502 }; 2503 2504 StaticSocketDataProvider data1(data_reads1, data_writes1); 2505 StaticSocketDataProvider data2(data_reads2, data_writes2); 2506 session_deps.socket_factory.AddSocketDataProvider(&data1); 2507 session_deps.socket_factory.AddSocketDataProvider(&data2); 2508 2509 TestCompletionCallback callback1; 2510 2511 int rv = trans->Start(&request, &callback1, NULL); 2512 EXPECT_EQ(ERR_IO_PENDING, rv); 2513 2514 rv = callback1.WaitForResult(); 2515 EXPECT_EQ(OK, rv); 2516 2517 const HttpResponseInfo* response = trans->GetResponseInfo(); 2518 EXPECT_FALSE(response == NULL); 2519 2520 // The password prompt info should have been set in 2521 // response->auth_challenge. 2522 EXPECT_FALSE(response->auth_challenge.get() == NULL); 2523 2524 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 2525 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 2526 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 2527 2528 TestCompletionCallback callback2; 2529 2530 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2); 2531 EXPECT_EQ(ERR_IO_PENDING, rv); 2532 2533 rv = callback2.WaitForResult(); 2534 EXPECT_EQ(OK, rv); 2535 2536 response = trans->GetResponseInfo(); 2537 EXPECT_FALSE(response == NULL); 2538 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2539 EXPECT_EQ(100, response->headers->GetContentLength()); 2540 } 2541 2542 // ------------------------------------------------------------------------ 2543 2544 // Transaction 2: authenticate (foo2, bar2) on MyRealm2 2545 { 2546 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2547 2548 HttpRequestInfo request; 2549 request.method = "GET"; 2550 // Note that Transaction 1 was at /x/y/z, so this is in the same 2551 // protection space as MyRealm1. 2552 request.url = GURL("http://www.google.com/x/y/a/b"); 2553 request.load_flags = 0; 2554 2555 MockWrite data_writes1[] = { 2556 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" 2557 "Host: www.google.com\r\n" 2558 "Connection: keep-alive\r\n" 2559 // Send preemptive authorization for MyRealm1 2560 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 2561 }; 2562 2563 // The server didn't like the preemptive authorization, and 2564 // challenges us for a different realm (MyRealm2). 2565 MockRead data_reads1[] = { 2566 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 2567 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"), 2568 MockRead("Content-Length: 10000\r\n\r\n"), 2569 MockRead(false, ERR_FAILED), 2570 }; 2571 2572 // Resend with authorization for MyRealm2 (username=foo2, password=bar2) 2573 MockWrite data_writes2[] = { 2574 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" 2575 "Host: www.google.com\r\n" 2576 "Connection: keep-alive\r\n" 2577 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), 2578 }; 2579 2580 // Sever accepts the authorization. 2581 MockRead data_reads2[] = { 2582 MockRead("HTTP/1.0 200 OK\r\n"), 2583 MockRead("Content-Length: 100\r\n\r\n"), 2584 MockRead(false, OK), 2585 }; 2586 2587 StaticSocketDataProvider data1(data_reads1, data_writes1); 2588 StaticSocketDataProvider data2(data_reads2, data_writes2); 2589 session_deps.socket_factory.AddSocketDataProvider(&data1); 2590 session_deps.socket_factory.AddSocketDataProvider(&data2); 2591 2592 TestCompletionCallback callback1; 2593 2594 int rv = trans->Start(&request, &callback1, NULL); 2595 EXPECT_EQ(ERR_IO_PENDING, rv); 2596 2597 rv = callback1.WaitForResult(); 2598 EXPECT_EQ(OK, rv); 2599 2600 const HttpResponseInfo* response = trans->GetResponseInfo(); 2601 EXPECT_FALSE(response == NULL); 2602 2603 // The password prompt info should have been set in 2604 // response->auth_challenge. 2605 EXPECT_FALSE(response->auth_challenge.get() == NULL); 2606 2607 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 2608 EXPECT_EQ(L"MyRealm2", response->auth_challenge->realm); 2609 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 2610 2611 TestCompletionCallback callback2; 2612 2613 rv = trans->RestartWithAuth(L"foo2", L"bar2", &callback2); 2614 EXPECT_EQ(ERR_IO_PENDING, rv); 2615 2616 rv = callback2.WaitForResult(); 2617 EXPECT_EQ(OK, rv); 2618 2619 response = trans->GetResponseInfo(); 2620 EXPECT_FALSE(response == NULL); 2621 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2622 EXPECT_EQ(100, response->headers->GetContentLength()); 2623 } 2624 2625 // ------------------------------------------------------------------------ 2626 2627 // Transaction 3: Resend a request in MyRealm's protection space -- 2628 // succeed with preemptive authorization. 2629 { 2630 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2631 2632 HttpRequestInfo request; 2633 request.method = "GET"; 2634 request.url = GURL("http://www.google.com/x/y/z2"); 2635 request.load_flags = 0; 2636 2637 MockWrite data_writes1[] = { 2638 MockWrite("GET /x/y/z2 HTTP/1.1\r\n" 2639 "Host: www.google.com\r\n" 2640 "Connection: keep-alive\r\n" 2641 // The authorization for MyRealm1 gets sent preemptively 2642 // (since the url is in the same protection space) 2643 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 2644 }; 2645 2646 // Sever accepts the preemptive authorization 2647 MockRead data_reads1[] = { 2648 MockRead("HTTP/1.0 200 OK\r\n"), 2649 MockRead("Content-Length: 100\r\n\r\n"), 2650 MockRead(false, OK), 2651 }; 2652 2653 StaticSocketDataProvider data1(data_reads1, data_writes1); 2654 session_deps.socket_factory.AddSocketDataProvider(&data1); 2655 2656 TestCompletionCallback callback1; 2657 2658 int rv = trans->Start(&request, &callback1, NULL); 2659 EXPECT_EQ(ERR_IO_PENDING, rv); 2660 2661 rv = callback1.WaitForResult(); 2662 EXPECT_EQ(OK, rv); 2663 2664 const HttpResponseInfo* response = trans->GetResponseInfo(); 2665 EXPECT_FALSE(response == NULL); 2666 2667 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2668 EXPECT_EQ(100, response->headers->GetContentLength()); 2669 } 2670 2671 // ------------------------------------------------------------------------ 2672 2673 // Transaction 4: request another URL in MyRealm (however the 2674 // url is not known to belong to the protection space, so no pre-auth). 2675 { 2676 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2677 2678 HttpRequestInfo request; 2679 request.method = "GET"; 2680 request.url = GURL("http://www.google.com/x/1"); 2681 request.load_flags = 0; 2682 2683 MockWrite data_writes1[] = { 2684 MockWrite("GET /x/1 HTTP/1.1\r\n" 2685 "Host: www.google.com\r\n" 2686 "Connection: keep-alive\r\n\r\n"), 2687 }; 2688 2689 MockRead data_reads1[] = { 2690 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 2691 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 2692 MockRead("Content-Length: 10000\r\n\r\n"), 2693 MockRead(false, ERR_FAILED), 2694 }; 2695 2696 // Resend with authorization from MyRealm's cache. 2697 MockWrite data_writes2[] = { 2698 MockWrite("GET /x/1 HTTP/1.1\r\n" 2699 "Host: www.google.com\r\n" 2700 "Connection: keep-alive\r\n" 2701 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 2702 }; 2703 2704 // Sever accepts the authorization. 2705 MockRead data_reads2[] = { 2706 MockRead("HTTP/1.0 200 OK\r\n"), 2707 MockRead("Content-Length: 100\r\n\r\n"), 2708 MockRead(false, OK), 2709 }; 2710 2711 StaticSocketDataProvider data1(data_reads1, data_writes1); 2712 StaticSocketDataProvider data2(data_reads2, data_writes2); 2713 session_deps.socket_factory.AddSocketDataProvider(&data1); 2714 session_deps.socket_factory.AddSocketDataProvider(&data2); 2715 2716 TestCompletionCallback callback1; 2717 2718 int rv = trans->Start(&request, &callback1, NULL); 2719 EXPECT_EQ(ERR_IO_PENDING, rv); 2720 2721 rv = callback1.WaitForResult(); 2722 EXPECT_EQ(OK, rv); 2723 2724 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 2725 TestCompletionCallback callback2; 2726 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2); 2727 EXPECT_EQ(ERR_IO_PENDING, rv); 2728 rv = callback2.WaitForResult(); 2729 EXPECT_EQ(OK, rv); 2730 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 2731 2732 const HttpResponseInfo* response = trans->GetResponseInfo(); 2733 EXPECT_FALSE(response == NULL); 2734 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2735 EXPECT_EQ(100, response->headers->GetContentLength()); 2736 } 2737 2738 // ------------------------------------------------------------------------ 2739 2740 // Transaction 5: request a URL in MyRealm, but the server rejects the 2741 // cached identity. Should invalidate and re-prompt. 2742 { 2743 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2744 2745 HttpRequestInfo request; 2746 request.method = "GET"; 2747 request.url = GURL("http://www.google.com/p/q/t"); 2748 request.load_flags = 0; 2749 2750 MockWrite data_writes1[] = { 2751 MockWrite("GET /p/q/t HTTP/1.1\r\n" 2752 "Host: www.google.com\r\n" 2753 "Connection: keep-alive\r\n\r\n"), 2754 }; 2755 2756 MockRead data_reads1[] = { 2757 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 2758 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 2759 MockRead("Content-Length: 10000\r\n\r\n"), 2760 MockRead(false, ERR_FAILED), 2761 }; 2762 2763 // Resend with authorization from cache for MyRealm. 2764 MockWrite data_writes2[] = { 2765 MockWrite("GET /p/q/t HTTP/1.1\r\n" 2766 "Host: www.google.com\r\n" 2767 "Connection: keep-alive\r\n" 2768 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 2769 }; 2770 2771 // Sever rejects the authorization. 2772 MockRead data_reads2[] = { 2773 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 2774 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 2775 MockRead("Content-Length: 10000\r\n\r\n"), 2776 MockRead(false, ERR_FAILED), 2777 }; 2778 2779 // At this point we should prompt for new credentials for MyRealm. 2780 // Restart with username=foo3, password=foo4. 2781 MockWrite data_writes3[] = { 2782 MockWrite("GET /p/q/t HTTP/1.1\r\n" 2783 "Host: www.google.com\r\n" 2784 "Connection: keep-alive\r\n" 2785 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"), 2786 }; 2787 2788 // Sever accepts the authorization. 2789 MockRead data_reads3[] = { 2790 MockRead("HTTP/1.0 200 OK\r\n"), 2791 MockRead("Content-Length: 100\r\n\r\n"), 2792 MockRead(false, OK), 2793 }; 2794 2795 StaticSocketDataProvider data1(data_reads1, data_writes1); 2796 StaticSocketDataProvider data2(data_reads2, data_writes2); 2797 StaticSocketDataProvider data3(data_reads3, data_writes3); 2798 session_deps.socket_factory.AddSocketDataProvider(&data1); 2799 session_deps.socket_factory.AddSocketDataProvider(&data2); 2800 session_deps.socket_factory.AddSocketDataProvider(&data3); 2801 2802 TestCompletionCallback callback1; 2803 2804 int rv = trans->Start(&request, &callback1, NULL); 2805 EXPECT_EQ(ERR_IO_PENDING, rv); 2806 2807 rv = callback1.WaitForResult(); 2808 EXPECT_EQ(OK, rv); 2809 2810 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 2811 TestCompletionCallback callback2; 2812 rv = trans->RestartWithAuth(std::wstring(), std::wstring(), &callback2); 2813 EXPECT_EQ(ERR_IO_PENDING, rv); 2814 rv = callback2.WaitForResult(); 2815 EXPECT_EQ(OK, rv); 2816 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 2817 2818 const HttpResponseInfo* response = trans->GetResponseInfo(); 2819 EXPECT_FALSE(response == NULL); 2820 2821 // The password prompt info should have been set in 2822 // response->auth_challenge. 2823 EXPECT_FALSE(response->auth_challenge.get() == NULL); 2824 2825 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 2826 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 2827 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 2828 2829 TestCompletionCallback callback3; 2830 2831 rv = trans->RestartWithAuth(L"foo3", L"bar3", &callback3); 2832 EXPECT_EQ(ERR_IO_PENDING, rv); 2833 2834 rv = callback3.WaitForResult(); 2835 EXPECT_EQ(OK, rv); 2836 2837 response = trans->GetResponseInfo(); 2838 EXPECT_FALSE(response == NULL); 2839 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2840 EXPECT_EQ(100, response->headers->GetContentLength()); 2841 } 2842 } 2843 2844 // Test the ResetStateForRestart() private method. 2845 TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) { 2846 // Create a transaction (the dependencies aren't important). 2847 SessionDependencies session_deps; 2848 scoped_ptr<HttpNetworkTransaction> trans( 2849 new HttpNetworkTransaction(CreateSession(&session_deps))); 2850 2851 // Setup some state (which we expect ResetStateForRestart() will clear). 2852 trans->read_buf_ = new IOBuffer(15); 2853 trans->read_buf_len_ = 15; 2854 trans->request_headers_ = "Authorization: NTLM"; 2855 2856 // Setup state in response_ 2857 HttpResponseInfo* response = &trans->response_; 2858 response->auth_challenge = new AuthChallengeInfo(); 2859 response->ssl_info.cert_status = -15; 2860 response->response_time = base::Time::Now(); 2861 response->was_cached = true; // (Wouldn't ever actually be true...) 2862 2863 { // Setup state for response_.vary_data 2864 HttpRequestInfo request; 2865 std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n"); 2866 std::replace(temp.begin(), temp.end(), '\n', '\0'); 2867 scoped_refptr<HttpResponseHeaders> headers = new HttpResponseHeaders(temp); 2868 request.extra_headers = "Foo: 1\nbar: 23"; 2869 EXPECT_TRUE(response->vary_data.Init(request, *headers)); 2870 } 2871 2872 // Cause the above state to be reset. 2873 trans->ResetStateForRestart(); 2874 2875 // Verify that the state that needed to be reset, has been reset. 2876 EXPECT_TRUE(trans->read_buf_.get() == NULL); 2877 EXPECT_EQ(0, trans->read_buf_len_); 2878 EXPECT_EQ(0U, trans->request_headers_.size()); 2879 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2880 EXPECT_TRUE(response->headers.get() == NULL); 2881 EXPECT_EQ(false, response->was_cached); 2882 EXPECT_EQ(0, response->ssl_info.cert_status); 2883 EXPECT_FALSE(response->vary_data.is_valid()); 2884 } 2885 2886 // Test HTTPS connections to a site with a bad certificate 2887 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificate) { 2888 SessionDependencies session_deps; 2889 scoped_ptr<HttpTransaction> trans( 2890 new HttpNetworkTransaction(CreateSession(&session_deps))); 2891 2892 HttpRequestInfo request; 2893 request.method = "GET"; 2894 request.url = GURL("https://www.google.com/"); 2895 request.load_flags = 0; 2896 2897 MockWrite data_writes[] = { 2898 MockWrite("GET / HTTP/1.1\r\n" 2899 "Host: www.google.com\r\n" 2900 "Connection: keep-alive\r\n\r\n"), 2901 }; 2902 2903 MockRead data_reads[] = { 2904 MockRead("HTTP/1.0 200 OK\r\n"), 2905 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 2906 MockRead("Content-Length: 100\r\n\r\n"), 2907 MockRead(false, OK), 2908 }; 2909 2910 StaticSocketDataProvider ssl_bad_certificate; 2911 StaticSocketDataProvider data(data_reads, data_writes); 2912 SSLSocketDataProvider ssl_bad(true, ERR_CERT_AUTHORITY_INVALID); 2913 SSLSocketDataProvider ssl(true, OK); 2914 2915 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); 2916 session_deps.socket_factory.AddSocketDataProvider(&data); 2917 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); 2918 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 2919 2920 TestCompletionCallback callback; 2921 2922 int rv = trans->Start(&request, &callback, NULL); 2923 EXPECT_EQ(ERR_IO_PENDING, rv); 2924 2925 rv = callback.WaitForResult(); 2926 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); 2927 2928 rv = trans->RestartIgnoringLastError(&callback); 2929 EXPECT_EQ(ERR_IO_PENDING, rv); 2930 2931 rv = callback.WaitForResult(); 2932 EXPECT_EQ(OK, rv); 2933 2934 const HttpResponseInfo* response = trans->GetResponseInfo(); 2935 2936 EXPECT_FALSE(response == NULL); 2937 EXPECT_EQ(100, response->headers->GetContentLength()); 2938 } 2939 2940 // Test HTTPS connections to a site with a bad certificate, going through a 2941 // proxy 2942 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) { 2943 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); 2944 2945 HttpRequestInfo request; 2946 request.method = "GET"; 2947 request.url = GURL("https://www.google.com/"); 2948 request.load_flags = 0; 2949 2950 MockWrite proxy_writes[] = { 2951 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 2952 "Host: www.google.com\r\n" 2953 "Proxy-Connection: keep-alive\r\n\r\n"), 2954 }; 2955 2956 MockRead proxy_reads[] = { 2957 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), 2958 MockRead(false, OK) 2959 }; 2960 2961 MockWrite data_writes[] = { 2962 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 2963 "Host: www.google.com\r\n" 2964 "Proxy-Connection: keep-alive\r\n\r\n"), 2965 MockWrite("GET / HTTP/1.1\r\n" 2966 "Host: www.google.com\r\n" 2967 "Connection: keep-alive\r\n\r\n"), 2968 }; 2969 2970 MockRead data_reads[] = { 2971 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), 2972 MockRead("HTTP/1.0 200 OK\r\n"), 2973 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 2974 MockRead("Content-Length: 100\r\n\r\n"), 2975 MockRead(false, OK), 2976 }; 2977 2978 StaticSocketDataProvider ssl_bad_certificate(proxy_reads, proxy_writes); 2979 StaticSocketDataProvider data(data_reads, data_writes); 2980 SSLSocketDataProvider ssl_bad(true, ERR_CERT_AUTHORITY_INVALID); 2981 SSLSocketDataProvider ssl(true, OK); 2982 2983 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); 2984 session_deps.socket_factory.AddSocketDataProvider(&data); 2985 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); 2986 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 2987 2988 TestCompletionCallback callback; 2989 2990 for (int i = 0; i < 2; i++) { 2991 session_deps.socket_factory.ResetNextMockIndexes(); 2992 2993 scoped_ptr<HttpTransaction> trans( 2994 new HttpNetworkTransaction(CreateSession(&session_deps))); 2995 2996 int rv = trans->Start(&request, &callback, NULL); 2997 EXPECT_EQ(ERR_IO_PENDING, rv); 2998 2999 rv = callback.WaitForResult(); 3000 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); 3001 3002 rv = trans->RestartIgnoringLastError(&callback); 3003 EXPECT_EQ(ERR_IO_PENDING, rv); 3004 3005 rv = callback.WaitForResult(); 3006 EXPECT_EQ(OK, rv); 3007 3008 const HttpResponseInfo* response = trans->GetResponseInfo(); 3009 3010 EXPECT_FALSE(response == NULL); 3011 EXPECT_EQ(100, response->headers->GetContentLength()); 3012 } 3013 } 3014 3015 TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgent) { 3016 SessionDependencies session_deps; 3017 scoped_ptr<HttpTransaction> trans( 3018 new HttpNetworkTransaction(CreateSession(&session_deps))); 3019 3020 HttpRequestInfo request; 3021 request.method = "GET"; 3022 request.url = GURL("http://www.google.com/"); 3023 request.user_agent = "Chromium Ultra Awesome X Edition"; 3024 3025 MockWrite data_writes[] = { 3026 MockWrite("GET / HTTP/1.1\r\n" 3027 "Host: www.google.com\r\n" 3028 "Connection: keep-alive\r\n" 3029 "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"), 3030 }; 3031 3032 // Lastly, the server responds with the actual content. 3033 MockRead data_reads[] = { 3034 MockRead("HTTP/1.0 200 OK\r\n"), 3035 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 3036 MockRead("Content-Length: 100\r\n\r\n"), 3037 MockRead(false, OK), 3038 }; 3039 3040 StaticSocketDataProvider data(data_reads, data_writes); 3041 session_deps.socket_factory.AddSocketDataProvider(&data); 3042 3043 TestCompletionCallback callback; 3044 3045 int rv = trans->Start(&request, &callback, NULL); 3046 EXPECT_EQ(ERR_IO_PENDING, rv); 3047 3048 rv = callback.WaitForResult(); 3049 EXPECT_EQ(OK, rv); 3050 } 3051 3052 TEST_F(HttpNetworkTransactionTest, BuildRequest_Referer) { 3053 SessionDependencies session_deps; 3054 scoped_ptr<HttpTransaction> trans( 3055 new HttpNetworkTransaction(CreateSession(&session_deps))); 3056 3057 HttpRequestInfo request; 3058 request.method = "GET"; 3059 request.url = GURL("http://www.google.com/"); 3060 request.load_flags = 0; 3061 request.referrer = GURL("http://the.previous.site.com/"); 3062 3063 MockWrite data_writes[] = { 3064 MockWrite("GET / HTTP/1.1\r\n" 3065 "Host: www.google.com\r\n" 3066 "Connection: keep-alive\r\n" 3067 "Referer: http://the.previous.site.com/\r\n\r\n"), 3068 }; 3069 3070 // Lastly, the server responds with the actual content. 3071 MockRead data_reads[] = { 3072 MockRead("HTTP/1.0 200 OK\r\n"), 3073 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 3074 MockRead("Content-Length: 100\r\n\r\n"), 3075 MockRead(false, OK), 3076 }; 3077 3078 StaticSocketDataProvider data(data_reads, data_writes); 3079 session_deps.socket_factory.AddSocketDataProvider(&data); 3080 3081 TestCompletionCallback callback; 3082 3083 int rv = trans->Start(&request, &callback, NULL); 3084 EXPECT_EQ(ERR_IO_PENDING, rv); 3085 3086 rv = callback.WaitForResult(); 3087 EXPECT_EQ(OK, rv); 3088 } 3089 3090 TEST_F(HttpNetworkTransactionTest, BuildRequest_PostContentLengthZero) { 3091 SessionDependencies session_deps; 3092 scoped_ptr<HttpTransaction> trans( 3093 new HttpNetworkTransaction(CreateSession(&session_deps))); 3094 3095 HttpRequestInfo request; 3096 request.method = "POST"; 3097 request.url = GURL("http://www.google.com/"); 3098 3099 MockWrite data_writes[] = { 3100 MockWrite("POST / HTTP/1.1\r\n" 3101 "Host: www.google.com\r\n" 3102 "Connection: keep-alive\r\n" 3103 "Content-Length: 0\r\n\r\n"), 3104 }; 3105 3106 // Lastly, the server responds with the actual content. 3107 MockRead data_reads[] = { 3108 MockRead("HTTP/1.0 200 OK\r\n"), 3109 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 3110 MockRead("Content-Length: 100\r\n\r\n"), 3111 MockRead(false, OK), 3112 }; 3113 3114 StaticSocketDataProvider data(data_reads, data_writes); 3115 session_deps.socket_factory.AddSocketDataProvider(&data); 3116 3117 TestCompletionCallback callback; 3118 3119 int rv = trans->Start(&request, &callback, NULL); 3120 EXPECT_EQ(ERR_IO_PENDING, rv); 3121 3122 rv = callback.WaitForResult(); 3123 EXPECT_EQ(OK, rv); 3124 } 3125 3126 TEST_F(HttpNetworkTransactionTest, BuildRequest_PutContentLengthZero) { 3127 SessionDependencies session_deps; 3128 scoped_ptr<HttpTransaction> trans( 3129 new HttpNetworkTransaction(CreateSession(&session_deps))); 3130 3131 HttpRequestInfo request; 3132 request.method = "PUT"; 3133 request.url = GURL("http://www.google.com/"); 3134 3135 MockWrite data_writes[] = { 3136 MockWrite("PUT / HTTP/1.1\r\n" 3137 "Host: www.google.com\r\n" 3138 "Connection: keep-alive\r\n" 3139 "Content-Length: 0\r\n\r\n"), 3140 }; 3141 3142 // Lastly, the server responds with the actual content. 3143 MockRead data_reads[] = { 3144 MockRead("HTTP/1.0 200 OK\r\n"), 3145 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 3146 MockRead("Content-Length: 100\r\n\r\n"), 3147 MockRead(false, OK), 3148 }; 3149 3150 StaticSocketDataProvider data(data_reads, data_writes); 3151 session_deps.socket_factory.AddSocketDataProvider(&data); 3152 3153 TestCompletionCallback callback; 3154 3155 int rv = trans->Start(&request, &callback, NULL); 3156 EXPECT_EQ(ERR_IO_PENDING, rv); 3157 3158 rv = callback.WaitForResult(); 3159 EXPECT_EQ(OK, rv); 3160 } 3161 3162 TEST_F(HttpNetworkTransactionTest, BuildRequest_HeadContentLengthZero) { 3163 SessionDependencies session_deps; 3164 scoped_ptr<HttpTransaction> trans( 3165 new HttpNetworkTransaction(CreateSession(&session_deps))); 3166 3167 HttpRequestInfo request; 3168 request.method = "HEAD"; 3169 request.url = GURL("http://www.google.com/"); 3170 3171 MockWrite data_writes[] = { 3172 MockWrite("HEAD / HTTP/1.1\r\n" 3173 "Host: www.google.com\r\n" 3174 "Connection: keep-alive\r\n" 3175 "Content-Length: 0\r\n\r\n"), 3176 }; 3177 3178 // Lastly, the server responds with the actual content. 3179 MockRead data_reads[] = { 3180 MockRead("HTTP/1.0 200 OK\r\n"), 3181 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 3182 MockRead("Content-Length: 100\r\n\r\n"), 3183 MockRead(false, OK), 3184 }; 3185 3186 StaticSocketDataProvider data(data_reads, data_writes); 3187 session_deps.socket_factory.AddSocketDataProvider(&data); 3188 3189 TestCompletionCallback callback; 3190 3191 int rv = trans->Start(&request, &callback, NULL); 3192 EXPECT_EQ(ERR_IO_PENDING, rv); 3193 3194 rv = callback.WaitForResult(); 3195 EXPECT_EQ(OK, rv); 3196 } 3197 3198 TEST_F(HttpNetworkTransactionTest, BuildRequest_CacheControlNoCache) { 3199 SessionDependencies session_deps; 3200 scoped_ptr<HttpTransaction> trans( 3201 new HttpNetworkTransaction(CreateSession(&session_deps))); 3202 3203 HttpRequestInfo request; 3204 request.method = "GET"; 3205 request.url = GURL("http://www.google.com/"); 3206 request.load_flags = LOAD_BYPASS_CACHE; 3207 3208 MockWrite data_writes[] = { 3209 MockWrite("GET / HTTP/1.1\r\n" 3210 "Host: www.google.com\r\n" 3211 "Connection: keep-alive\r\n" 3212 "Pragma: no-cache\r\n" 3213 "Cache-Control: no-cache\r\n\r\n"), 3214 }; 3215 3216 // Lastly, the server responds with the actual content. 3217 MockRead data_reads[] = { 3218 MockRead("HTTP/1.0 200 OK\r\n"), 3219 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 3220 MockRead("Content-Length: 100\r\n\r\n"), 3221 MockRead(false, OK), 3222 }; 3223 3224 StaticSocketDataProvider data(data_reads, data_writes); 3225 session_deps.socket_factory.AddSocketDataProvider(&data); 3226 3227 TestCompletionCallback callback; 3228 3229 int rv = trans->Start(&request, &callback, NULL); 3230 EXPECT_EQ(ERR_IO_PENDING, rv); 3231 3232 rv = callback.WaitForResult(); 3233 EXPECT_EQ(OK, rv); 3234 } 3235 3236 TEST_F(HttpNetworkTransactionTest, 3237 BuildRequest_CacheControlValidateCache) { 3238 SessionDependencies session_deps; 3239 scoped_ptr<HttpTransaction> trans( 3240 new HttpNetworkTransaction(CreateSession(&session_deps))); 3241 3242 HttpRequestInfo request; 3243 request.method = "GET"; 3244 request.url = GURL("http://www.google.com/"); 3245 request.load_flags = LOAD_VALIDATE_CACHE; 3246 3247 MockWrite data_writes[] = { 3248 MockWrite("GET / HTTP/1.1\r\n" 3249 "Host: www.google.com\r\n" 3250 "Connection: keep-alive\r\n" 3251 "Cache-Control: max-age=0\r\n\r\n"), 3252 }; 3253 3254 // Lastly, the server responds with the actual content. 3255 MockRead data_reads[] = { 3256 MockRead("HTTP/1.0 200 OK\r\n"), 3257 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 3258 MockRead("Content-Length: 100\r\n\r\n"), 3259 MockRead(false, OK), 3260 }; 3261 3262 StaticSocketDataProvider data(data_reads, data_writes); 3263 session_deps.socket_factory.AddSocketDataProvider(&data); 3264 3265 TestCompletionCallback callback; 3266 3267 int rv = trans->Start(&request, &callback, NULL); 3268 EXPECT_EQ(ERR_IO_PENDING, rv); 3269 3270 rv = callback.WaitForResult(); 3271 EXPECT_EQ(OK, rv); 3272 } 3273 3274 TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) { 3275 SessionDependencies session_deps; 3276 scoped_ptr<HttpTransaction> trans( 3277 new HttpNetworkTransaction(CreateSession(&session_deps))); 3278 3279 HttpRequestInfo request; 3280 request.method = "GET"; 3281 request.url = GURL("http://www.google.com/"); 3282 request.extra_headers = "FooHeader: Bar\r\n"; 3283 3284 MockWrite data_writes[] = { 3285 MockWrite("GET / HTTP/1.1\r\n" 3286 "Host: www.google.com\r\n" 3287 "Connection: keep-alive\r\n" 3288 "FooHeader: Bar\r\n\r\n"), 3289 }; 3290 3291 // Lastly, the server responds with the actual content. 3292 MockRead data_reads[] = { 3293 MockRead("HTTP/1.0 200 OK\r\n"), 3294 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 3295 MockRead("Content-Length: 100\r\n\r\n"), 3296 MockRead(false, OK), 3297 }; 3298 3299 StaticSocketDataProvider data(data_reads, data_writes); 3300 session_deps.socket_factory.AddSocketDataProvider(&data); 3301 3302 TestCompletionCallback callback; 3303 3304 int rv = trans->Start(&request, &callback, NULL); 3305 EXPECT_EQ(ERR_IO_PENDING, rv); 3306 3307 rv = callback.WaitForResult(); 3308 EXPECT_EQ(OK, rv); 3309 } 3310 3311 TEST_F(HttpNetworkTransactionTest, SOCKS4_HTTP_GET) { 3312 SessionDependencies session_deps( 3313 CreateFixedProxyService("socks4://myproxy:1080")); 3314 3315 scoped_ptr<HttpTransaction> trans( 3316 new HttpNetworkTransaction(CreateSession(&session_deps))); 3317 3318 HttpRequestInfo request; 3319 request.method = "GET"; 3320 request.url = GURL("http://www.google.com/"); 3321 request.load_flags = 0; 3322 3323 char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 }; 3324 char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; 3325 3326 MockWrite data_writes[] = { 3327 MockWrite(true, write_buffer, arraysize(write_buffer)), 3328 MockWrite("GET / HTTP/1.1\r\n" 3329 "Host: www.google.com\r\n" 3330 "Connection: keep-alive\r\n\r\n") 3331 }; 3332 3333 MockRead data_reads[] = { 3334 MockRead(true, read_buffer, arraysize(read_buffer)), 3335 MockRead("HTTP/1.0 200 OK\r\n"), 3336 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), 3337 MockRead("Payload"), 3338 MockRead(false, OK) 3339 }; 3340 3341 StaticSocketDataProvider data(data_reads, data_writes); 3342 session_deps.socket_factory.AddSocketDataProvider(&data); 3343 3344 TestCompletionCallback callback; 3345 3346 int rv = trans->Start(&request, &callback, NULL); 3347 EXPECT_EQ(ERR_IO_PENDING, rv); 3348 3349 rv = callback.WaitForResult(); 3350 EXPECT_EQ(OK, rv); 3351 3352 const HttpResponseInfo* response = trans->GetResponseInfo(); 3353 EXPECT_FALSE(response == NULL); 3354 3355 std::string response_text; 3356 rv = ReadTransaction(trans.get(), &response_text); 3357 EXPECT_EQ(OK, rv); 3358 EXPECT_EQ("Payload", response_text); 3359 } 3360 3361 TEST_F(HttpNetworkTransactionTest, SOCKS4_SSL_GET) { 3362 SessionDependencies session_deps( 3363 CreateFixedProxyService("socks4://myproxy:1080")); 3364 3365 scoped_ptr<HttpTransaction> trans( 3366 new HttpNetworkTransaction(CreateSession(&session_deps))); 3367 3368 HttpRequestInfo request; 3369 request.method = "GET"; 3370 request.url = GURL("https://www.google.com/"); 3371 request.load_flags = 0; 3372 3373 unsigned char write_buffer[] = { 0x04, 0x01, 0x01, 0xBB, 127, 0, 0, 1, 0 }; 3374 unsigned char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; 3375 3376 MockWrite data_writes[] = { 3377 MockWrite(true, reinterpret_cast<char*>(write_buffer), 3378 arraysize(write_buffer)), 3379 MockWrite("GET / HTTP/1.1\r\n" 3380 "Host: www.google.com\r\n" 3381 "Connection: keep-alive\r\n\r\n") 3382 }; 3383 3384 MockRead data_reads[] = { 3385 MockWrite(true, reinterpret_cast<char*>(read_buffer), 3386 arraysize(read_buffer)), 3387 MockRead("HTTP/1.0 200 OK\r\n"), 3388 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), 3389 MockRead("Payload"), 3390 MockRead(false, OK) 3391 }; 3392 3393 StaticSocketDataProvider data(data_reads, data_writes); 3394 session_deps.socket_factory.AddSocketDataProvider(&data); 3395 3396 SSLSocketDataProvider ssl(true, OK); 3397 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 3398 3399 TestCompletionCallback callback; 3400 3401 int rv = trans->Start(&request, &callback, NULL); 3402 EXPECT_EQ(ERR_IO_PENDING, rv); 3403 3404 rv = callback.WaitForResult(); 3405 EXPECT_EQ(OK, rv); 3406 3407 const HttpResponseInfo* response = trans->GetResponseInfo(); 3408 EXPECT_FALSE(response == NULL); 3409 3410 std::string response_text; 3411 rv = ReadTransaction(trans.get(), &response_text); 3412 EXPECT_EQ(OK, rv); 3413 EXPECT_EQ("Payload", response_text); 3414 } 3415 3416 TEST_F(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) { 3417 SessionDependencies session_deps( 3418 CreateFixedProxyService("socks5://myproxy:1080")); 3419 3420 scoped_ptr<HttpTransaction> trans( 3421 new HttpNetworkTransaction(CreateSession(&session_deps))); 3422 3423 HttpRequestInfo request; 3424 request.method = "GET"; 3425 request.url = GURL("http://www.google.com/"); 3426 request.load_flags = 0; 3427 3428 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; 3429 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 }; 3430 const char kSOCKS5OkRequest[] = { 3431 0x05, // Version 3432 0x01, // Command (CONNECT) 3433 0x00, // Reserved. 3434 0x03, // Address type (DOMAINNAME). 3435 0x0E, // Length of domain (14) 3436 // Domain string: 3437 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', 3438 0x00, 0x50, // 16-bit port (80) 3439 }; 3440 const char kSOCKS5OkResponse[] = 3441 { 0x05, 0x00, 0x00, 0x01, 127, 0, 0, 1, 0x00, 0x50 }; 3442 3443 MockWrite data_writes[] = { 3444 MockWrite(true, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)), 3445 MockWrite(true, kSOCKS5OkRequest, arraysize(kSOCKS5OkRequest)), 3446 MockWrite("GET / HTTP/1.1\r\n" 3447 "Host: www.google.com\r\n" 3448 "Connection: keep-alive\r\n\r\n") 3449 }; 3450 3451 MockRead data_reads[] = { 3452 MockWrite(true, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), 3453 MockWrite(true, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)), 3454 MockRead("HTTP/1.0 200 OK\r\n"), 3455 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), 3456 MockRead("Payload"), 3457 MockRead(false, OK) 3458 }; 3459 3460 StaticSocketDataProvider data(data_reads, data_writes); 3461 session_deps.socket_factory.AddSocketDataProvider(&data); 3462 3463 TestCompletionCallback callback; 3464 3465 int rv = trans->Start(&request, &callback, NULL); 3466 EXPECT_EQ(ERR_IO_PENDING, rv); 3467 3468 rv = callback.WaitForResult(); 3469 EXPECT_EQ(OK, rv); 3470 3471 const HttpResponseInfo* response = trans->GetResponseInfo(); 3472 EXPECT_FALSE(response == NULL); 3473 3474 std::string response_text; 3475 rv = ReadTransaction(trans.get(), &response_text); 3476 EXPECT_EQ(OK, rv); 3477 EXPECT_EQ("Payload", response_text); 3478 } 3479 3480 TEST_F(HttpNetworkTransactionTest, SOCKS5_SSL_GET) { 3481 SessionDependencies session_deps( 3482 CreateFixedProxyService("socks5://myproxy:1080")); 3483 3484 scoped_ptr<HttpTransaction> trans( 3485 new HttpNetworkTransaction(CreateSession(&session_deps))); 3486 3487 HttpRequestInfo request; 3488 request.method = "GET"; 3489 request.url = GURL("https://www.google.com/"); 3490 request.load_flags = 0; 3491 3492 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; 3493 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 }; 3494 const unsigned char kSOCKS5OkRequest[] = { 3495 0x05, // Version 3496 0x01, // Command (CONNECT) 3497 0x00, // Reserved. 3498 0x03, // Address type (DOMAINNAME). 3499 0x0E, // Length of domain (14) 3500 // Domain string: 3501 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', 3502 0x01, 0xBB, // 16-bit port (443) 3503 }; 3504 3505 const char kSOCKS5OkResponse[] = 3506 { 0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0x00, 0x00 }; 3507 3508 MockWrite data_writes[] = { 3509 MockWrite(true, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)), 3510 MockWrite(true, reinterpret_cast<const char*>(kSOCKS5OkRequest), 3511 arraysize(kSOCKS5OkRequest)), 3512 MockWrite("GET / HTTP/1.1\r\n" 3513 "Host: www.google.com\r\n" 3514 "Connection: keep-alive\r\n\r\n") 3515 }; 3516 3517 MockRead data_reads[] = { 3518 MockWrite(true, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), 3519 MockWrite(true, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)), 3520 MockRead("HTTP/1.0 200 OK\r\n"), 3521 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), 3522 MockRead("Payload"), 3523 MockRead(false, OK) 3524 }; 3525 3526 StaticSocketDataProvider data(data_reads, data_writes); 3527 session_deps.socket_factory.AddSocketDataProvider(&data); 3528 3529 SSLSocketDataProvider ssl(true, OK); 3530 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 3531 3532 TestCompletionCallback callback; 3533 3534 int rv = trans->Start(&request, &callback, NULL); 3535 EXPECT_EQ(ERR_IO_PENDING, rv); 3536 3537 rv = callback.WaitForResult(); 3538 EXPECT_EQ(OK, rv); 3539 3540 const HttpResponseInfo* response = trans->GetResponseInfo(); 3541 EXPECT_FALSE(response == NULL); 3542 3543 std::string response_text; 3544 rv = ReadTransaction(trans.get(), &response_text); 3545 EXPECT_EQ(OK, rv); 3546 EXPECT_EQ("Payload", response_text); 3547 } 3548 3549 // Tests that for connection endpoints the group names are correctly set. 3550 TEST_F(HttpNetworkTransactionTest, GroupNameForProxyConnections) { 3551 const struct { 3552 const std::string proxy_server; 3553 const std::string url; 3554 const std::string expected_group_name; 3555 } tests[] = { 3556 { 3557 "", // no proxy (direct) 3558 "http://www.google.com/direct", 3559 "http://www.google.com/", 3560 }, 3561 { 3562 "http_proxy", 3563 "http://www.google.com/http_proxy_normal", 3564 "proxy/http_proxy:80/", 3565 }, 3566 { 3567 "socks4://socks_proxy:1080", 3568 "http://www.google.com/socks4_direct", 3569 "proxy/socks4://socks_proxy:1080/http://www.google.com/", 3570 }, 3571 3572 // SSL Tests 3573 { 3574 "", 3575 "https://www.google.com/direct_ssl", 3576 "https://www.google.com/", 3577 }, 3578 { 3579 "http_proxy", 3580 "https://www.google.com/http_connect_ssl", 3581 "proxy/http_proxy:80/https://www.google.com/", 3582 }, 3583 { 3584 "socks4://socks_proxy:1080", 3585 "https://www.google.com/socks4_ssl", 3586 "proxy/socks4://socks_proxy:1080/https://www.google.com/", 3587 }, 3588 }; 3589 3590 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 3591 SessionDependencies session_deps( 3592 CreateFixedProxyService(tests[i].proxy_server)); 3593 3594 scoped_refptr<CaptureGroupNameSocketPool> conn_pool( 3595 new CaptureGroupNameSocketPool()); 3596 3597 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 3598 session->tcp_socket_pool_ = conn_pool.get(); 3599 3600 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 3601 3602 HttpRequestInfo request; 3603 request.method = "GET"; 3604 request.url = GURL(tests[i].url); 3605 request.load_flags = 0; 3606 3607 TestCompletionCallback callback; 3608 3609 // We do not complete this request, the dtor will clean the transaction up. 3610 EXPECT_EQ(ERR_IO_PENDING, trans->Start(&request, &callback, NULL)); 3611 EXPECT_EQ(tests[i].expected_group_name, 3612 conn_pool->last_group_name_received()); 3613 } 3614 } 3615 3616 TEST_F(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) { 3617 SessionDependencies session_deps( 3618 CreateFixedProxyService("myproxy:70;foobar:80")); 3619 3620 // This simulates failure resolving all hostnames; that means we will fail 3621 // connecting to both proxies (myproxy:70 and foobar:80). 3622 session_deps.host_resolver->rules()->AddSimulatedFailure("*"); 3623 3624 scoped_ptr<HttpTransaction> trans( 3625 new HttpNetworkTransaction(CreateSession(&session_deps))); 3626 3627 HttpRequestInfo request; 3628 request.method = "GET"; 3629 request.url = GURL("http://www.google.com/"); 3630 3631 TestCompletionCallback callback; 3632 3633 int rv = trans->Start(&request, &callback, NULL); 3634 EXPECT_EQ(ERR_IO_PENDING, rv); 3635 3636 rv = callback.WaitForResult(); 3637 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv); 3638 } 3639 3640 // Host resolution observer used by 3641 // HttpNetworkTransactionTest.ResolveMadeWithReferrer to check that host 3642 // resovle requests are issued with a referrer of |expected_referrer|. 3643 class ResolutionReferrerObserver : public HostResolver::Observer { 3644 public: 3645 explicit ResolutionReferrerObserver(const GURL& expected_referrer) 3646 : expected_referrer_(expected_referrer), 3647 called_start_with_referrer_(false), 3648 called_finish_with_referrer_(false) { 3649 } 3650 3651 virtual void OnStartResolution(int id, 3652 const HostResolver::RequestInfo& info) { 3653 if (info.referrer() == expected_referrer_) 3654 called_start_with_referrer_ = true; 3655 } 3656 3657 virtual void OnFinishResolutionWithStatus( 3658 int id, bool was_resolved, const HostResolver::RequestInfo& info ) { 3659 if (info.referrer() == expected_referrer_) 3660 called_finish_with_referrer_ = true; 3661 } 3662 3663 virtual void OnCancelResolution(int id, 3664 const HostResolver::RequestInfo& info ) { 3665 FAIL() << "Should not be cancelling any requests!"; 3666 } 3667 3668 bool did_complete_with_expected_referrer() const { 3669 return called_start_with_referrer_ && called_finish_with_referrer_; 3670 } 3671 3672 private: 3673 GURL expected_referrer_; 3674 bool called_start_with_referrer_; 3675 bool called_finish_with_referrer_; 3676 3677 DISALLOW_COPY_AND_ASSIGN(ResolutionReferrerObserver); 3678 }; 3679 3680 // Make sure that when HostResolver::Resolve() is invoked, it passes through 3681 // the "referrer". This is depended on by the DNS prefetch observer. 3682 TEST_F(HttpNetworkTransactionTest, ResolveMadeWithReferrer) { 3683 GURL referrer = GURL("http://expected-referrer/"); 3684 EXPECT_TRUE(referrer.is_valid()); 3685 ResolutionReferrerObserver resolution_observer(referrer); 3686 3687 SessionDependencies session_deps; 3688 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction( 3689 CreateSession(&session_deps))); 3690 3691 // Attach an observer to watch the host resolutions being made. 3692 session_deps.host_resolver->AddObserver(&resolution_observer); 3693 3694 // Connect up a mock socket which will fail when reading. 3695 MockRead data_reads[] = { 3696 MockRead(false, ERR_FAILED), 3697 }; 3698 StaticSocketDataProvider data(data_reads, NULL); 3699 session_deps.socket_factory.AddSocketDataProvider(&data); 3700 3701 // Issue a request, containing an HTTP referrer. 3702 HttpRequestInfo request; 3703 request.method = "GET"; 3704 request.referrer = referrer; 3705 request.url = GURL("http://www.google.com/"); 3706 3707 // Run the request until it fails reading from the socket. 3708 TestCompletionCallback callback; 3709 int rv = trans->Start(&request, &callback, NULL); 3710 EXPECT_EQ(ERR_IO_PENDING, rv); 3711 rv = callback.WaitForResult(); 3712 EXPECT_EQ(ERR_FAILED, rv); 3713 3714 // Check that the host resolution observer saw |referrer|. 3715 EXPECT_TRUE(resolution_observer.did_complete_with_expected_referrer()); 3716 } 3717 3718 // Make sure that when the load flags contain LOAD_BYPASS_CACHE, the resolver's 3719 // host cache is bypassed. 3720 TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh) { 3721 SessionDependencies session_deps; 3722 3723 // Select a host resolver that does caching. 3724 session_deps.host_resolver = new MockCachingHostResolver; 3725 3726 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction( 3727 CreateSession(&session_deps))); 3728 3729 // Warm up the host cache so it has an entry for "www.google.com" (by doing 3730 // a synchronous lookup.) 3731 AddressList addrlist; 3732 int rv = session_deps.host_resolver->Resolve( 3733 HostResolver::RequestInfo("www.google.com", 80), &addrlist, 3734 NULL, NULL, NULL); 3735 EXPECT_EQ(OK, rv); 3736 3737 // Verify that it was added to host cache, by doing a subsequent async lookup 3738 // and confirming it completes synchronously. 3739 TestCompletionCallback resolve_callback; 3740 rv = session_deps.host_resolver->Resolve( 3741 HostResolver::RequestInfo("www.google.com", 80), &addrlist, 3742 &resolve_callback, NULL, NULL); 3743 ASSERT_EQ(OK, rv); 3744 3745 // Inject a failure the next time that "www.google.com" is resolved. This way 3746 // we can tell if the next lookup hit the cache, or the "network". 3747 // (cache --> success, "network" --> failure). 3748 session_deps.host_resolver->rules()->AddSimulatedFailure("www.google.com"); 3749 3750 // Connect up a mock socket which will fail with ERR_UNEXPECTED during the 3751 // first read -- this won't be reached as the host resolution will fail first. 3752 MockRead data_reads[] = { MockRead(false, ERR_UNEXPECTED) }; 3753 StaticSocketDataProvider data(data_reads, NULL); 3754 session_deps.socket_factory.AddSocketDataProvider(&data); 3755 3756 // Issue a request, asking to bypass the cache(s). 3757 HttpRequestInfo request; 3758 request.method = "GET"; 3759 request.load_flags = LOAD_BYPASS_CACHE; 3760 request.url = GURL("http://www.google.com/"); 3761 3762 // Run the request. 3763 TestCompletionCallback callback; 3764 rv = trans->Start(&request, &callback, NULL); 3765 ASSERT_EQ(ERR_IO_PENDING, rv); 3766 rv = callback.WaitForResult(); 3767 3768 // If we bypassed the cache, we would have gotten a failure while resolving 3769 // "www.google.com". 3770 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv); 3771 } 3772 3773 // Make sure we can handle an error when writing the request. 3774 TEST_F(HttpNetworkTransactionTest, RequestWriteError) { 3775 SessionDependencies session_deps; 3776 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); 3777 3778 HttpRequestInfo request; 3779 request.method = "GET"; 3780 request.url = GURL("http://www.foo.com/"); 3781 request.load_flags = 0; 3782 3783 MockWrite write_failure[] = { 3784 MockWrite(true, ERR_CONNECTION_RESET), 3785 }; 3786 StaticSocketDataProvider data(NULL, write_failure); 3787 session_deps.socket_factory.AddSocketDataProvider(&data); 3788 3789 TestCompletionCallback callback; 3790 3791 scoped_ptr<HttpTransaction> trans( 3792 new HttpNetworkTransaction(CreateSession(&session_deps))); 3793 3794 int rv = trans->Start(&request, &callback, NULL); 3795 EXPECT_EQ(ERR_IO_PENDING, rv); 3796 3797 rv = callback.WaitForResult(); 3798 EXPECT_EQ(ERR_CONNECTION_RESET, rv); 3799 } 3800 3801 // Check that a connection closed after the start of the headers finishes ok. 3802 TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) { 3803 SessionDependencies session_deps; 3804 scoped_refptr<HttpNetworkSession> session = CreateSession(&session_deps); 3805 3806 HttpRequestInfo request; 3807 request.method = "GET"; 3808 request.url = GURL("http://www.foo.com/"); 3809 request.load_flags = 0; 3810 3811 MockRead data_reads[] = { 3812 MockRead("HTTP/1."), 3813 MockRead(false, OK), 3814 }; 3815 3816 StaticSocketDataProvider data(data_reads, NULL); 3817 session_deps.socket_factory.AddSocketDataProvider(&data); 3818 3819 TestCompletionCallback callback; 3820 3821 scoped_ptr<HttpTransaction> trans( 3822 new HttpNetworkTransaction(CreateSession(&session_deps))); 3823 3824 int rv = trans->Start(&request, &callback, NULL); 3825 EXPECT_EQ(ERR_IO_PENDING, rv); 3826 3827 rv = callback.WaitForResult(); 3828 EXPECT_EQ(OK, rv); 3829 3830 const HttpResponseInfo* response = trans->GetResponseInfo(); 3831 EXPECT_TRUE(response != NULL); 3832 3833 EXPECT_TRUE(response->headers != NULL); 3834 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); 3835 3836 std::string response_data; 3837 rv = ReadTransaction(trans.get(), &response_data); 3838 EXPECT_EQ(OK, rv); 3839 EXPECT_EQ("", response_data); 3840 } 3841 3842 // Make sure that a dropped connection while draining the body for auth 3843 // restart does the right thing. 3844 TEST_F(HttpNetworkTransactionTest, DrainResetOK) { 3845 SessionDependencies session_deps; 3846 scoped_ptr<HttpTransaction> trans( 3847 new HttpNetworkTransaction(CreateSession(&session_deps))); 3848 3849 HttpRequestInfo request; 3850 request.method = "GET"; 3851 request.url = GURL("http://www.google.com/"); 3852 request.load_flags = 0; 3853 3854 MockWrite data_writes1[] = { 3855 MockWrite("GET / HTTP/1.1\r\n" 3856 "Host: www.google.com\r\n" 3857 "Connection: keep-alive\r\n\r\n"), 3858 }; 3859 3860 MockRead data_reads1[] = { 3861 MockRead("HTTP/1.1 401 Unauthorized\r\n"), 3862 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 3863 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 3864 MockRead("Content-Length: 14\r\n\r\n"), 3865 MockRead("Unauth"), 3866 MockRead(true, ERR_CONNECTION_RESET), 3867 }; 3868 3869 StaticSocketDataProvider data1(data_reads1, data_writes1); 3870 session_deps.socket_factory.AddSocketDataProvider(&data1); 3871 3872 // After calling trans->RestartWithAuth(), this is the request we should 3873 // be issuing -- the final header line contains the credentials. 3874 MockWrite data_writes2[] = { 3875 MockWrite("GET / HTTP/1.1\r\n" 3876 "Host: www.google.com\r\n" 3877 "Connection: keep-alive\r\n" 3878 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 3879 }; 3880 3881 // Lastly, the server responds with the actual content. 3882 MockRead data_reads2[] = { 3883 MockRead("HTTP/1.1 200 OK\r\n"), 3884 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 3885 MockRead("Content-Length: 100\r\n\r\n"), 3886 MockRead(false, OK), 3887 }; 3888 3889 StaticSocketDataProvider data2(data_reads2, data_writes2); 3890 session_deps.socket_factory.AddSocketDataProvider(&data2); 3891 3892 TestCompletionCallback callback1; 3893 3894 int rv = trans->Start(&request, &callback1, NULL); 3895 EXPECT_EQ(ERR_IO_PENDING, rv); 3896 3897 rv = callback1.WaitForResult(); 3898 EXPECT_EQ(OK, rv); 3899 3900 const HttpResponseInfo* response = trans->GetResponseInfo(); 3901 EXPECT_FALSE(response == NULL); 3902 3903 // The password prompt info should have been set in response->auth_challenge. 3904 EXPECT_FALSE(response->auth_challenge.get() == NULL); 3905 3906 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 3907 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 3908 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 3909 3910 TestCompletionCallback callback2; 3911 3912 rv = trans->RestartWithAuth(L"foo", L"bar", &callback2); 3913 EXPECT_EQ(ERR_IO_PENDING, rv); 3914 3915 rv = callback2.WaitForResult(); 3916 EXPECT_EQ(OK, rv); 3917 3918 response = trans->GetResponseInfo(); 3919 EXPECT_FALSE(response == NULL); 3920 EXPECT_TRUE(response->auth_challenge.get() == NULL); 3921 EXPECT_EQ(100, response->headers->GetContentLength()); 3922 } 3923 3924 // Test HTTPS connections going through a proxy that sends extra data. 3925 TEST_F(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) { 3926 SessionDependencies session_deps(CreateFixedProxyService("myproxy:70")); 3927 3928 HttpRequestInfo request; 3929 request.method = "GET"; 3930 request.url = GURL("https://www.google.com/"); 3931 request.load_flags = 0; 3932 3933 MockRead proxy_reads[] = { 3934 MockRead("HTTP/1.0 200 Connected\r\n\r\nExtra data"), 3935 MockRead(false, OK) 3936 }; 3937 3938 StaticSocketDataProvider data(proxy_reads, NULL); 3939 SSLSocketDataProvider ssl(true, OK); 3940 3941 session_deps.socket_factory.AddSocketDataProvider(&data); 3942 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 3943 3944 TestCompletionCallback callback; 3945 3946 session_deps.socket_factory.ResetNextMockIndexes(); 3947 3948 scoped_ptr<HttpTransaction> trans( 3949 new HttpNetworkTransaction(CreateSession(&session_deps))); 3950 3951 int rv = trans->Start(&request, &callback, NULL); 3952 EXPECT_EQ(ERR_IO_PENDING, rv); 3953 3954 rv = callback.WaitForResult(); 3955 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); 3956 } 3957 3958 TEST_F(HttpNetworkTransactionTest, LargeContentLengthThenClose) { 3959 MockRead data_reads[] = { 3960 MockRead("HTTP/1.0 200 OK\r\nContent-Length:6719476739\r\n\r\n"), 3961 MockRead(false, OK), 3962 }; 3963 SimpleGetHelperResult out = SimpleGetHelper(data_reads); 3964 EXPECT_EQ(OK, out.rv); 3965 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); 3966 EXPECT_EQ("", out.response_data); 3967 } 3968 3969 } // namespace net 3970