1 // Copyright (c) 2011 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 "net/http/http_network_transaction.h" 6 7 #include <math.h> // ceil 8 #include <vector> 9 10 #include "base/basictypes.h" 11 #include "base/compiler_specific.h" 12 #include "base/file_path.h" 13 #include "base/file_util.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/utf_string_conversions.h" 16 #include "net/base/auth.h" 17 #include "net/base/capturing_net_log.h" 18 #include "net/base/completion_callback.h" 19 #include "net/base/mock_host_resolver.h" 20 #include "net/base/net_log.h" 21 #include "net/base/net_log_unittest.h" 22 #include "net/base/request_priority.h" 23 #include "net/base/ssl_cert_request_info.h" 24 #include "net/base/ssl_config_service_defaults.h" 25 #include "net/base/ssl_info.h" 26 #include "net/base/test_completion_callback.h" 27 #include "net/base/upload_data.h" 28 #include "net/http/http_auth_handler_digest.h" 29 #include "net/http/http_auth_handler_mock.h" 30 #include "net/http/http_auth_handler_ntlm.h" 31 #include "net/http/http_basic_stream.h" 32 #include "net/http/http_net_log_params.h" 33 #include "net/http/http_network_session.h" 34 #include "net/http/http_network_session_peer.h" 35 #include "net/http/http_stream.h" 36 #include "net/http/http_stream_factory.h" 37 #include "net/http/http_transaction_unittest.h" 38 #include "net/proxy/proxy_config_service_fixed.h" 39 #include "net/proxy/proxy_resolver.h" 40 #include "net/proxy/proxy_service.h" 41 #include "net/socket/client_socket_factory.h" 42 #include "net/socket/socket_test_util.h" 43 #include "net/socket/ssl_client_socket.h" 44 #include "net/spdy/spdy_framer.h" 45 #include "net/spdy/spdy_session.h" 46 #include "net/spdy/spdy_session_pool.h" 47 #include "net/spdy/spdy_test_util.h" 48 #include "testing/gtest/include/gtest/gtest.h" 49 #include "testing/platform_test.h" 50 51 //----------------------------------------------------------------------------- 52 53 namespace { 54 55 const string16 kBar(ASCIIToUTF16("bar")); 56 const string16 kBar2(ASCIIToUTF16("bar2")); 57 const string16 kBar3(ASCIIToUTF16("bar3")); 58 const string16 kBaz(ASCIIToUTF16("baz")); 59 const string16 kFirst(ASCIIToUTF16("first")); 60 const string16 kFoo(ASCIIToUTF16("foo")); 61 const string16 kFoo2(ASCIIToUTF16("foo2")); 62 const string16 kFoo3(ASCIIToUTF16("foo3")); 63 const string16 kFou(ASCIIToUTF16("fou")); 64 const string16 kSecond(ASCIIToUTF16("second")); 65 const string16 kTestingNTLM(ASCIIToUTF16("testing-ntlm")); 66 const string16 kWrongPassword(ASCIIToUTF16("wrongpassword")); 67 68 } // namespace 69 70 namespace net { 71 72 // Helper to manage the lifetimes of the dependencies for a 73 // HttpNetworkTransaction. 74 struct SessionDependencies { 75 // Default set of dependencies -- "null" proxy service. 76 SessionDependencies() 77 : host_resolver(new MockHostResolver), 78 cert_verifier(new CertVerifier), 79 proxy_service(ProxyService::CreateDirect()), 80 ssl_config_service(new SSLConfigServiceDefaults), 81 http_auth_handler_factory( 82 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), 83 net_log(NULL) {} 84 85 // Custom proxy service dependency. 86 explicit SessionDependencies(ProxyService* proxy_service) 87 : host_resolver(new MockHostResolver), 88 cert_verifier(new CertVerifier), 89 proxy_service(proxy_service), 90 ssl_config_service(new SSLConfigServiceDefaults), 91 http_auth_handler_factory( 92 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), 93 net_log(NULL) {} 94 95 scoped_ptr<MockHostResolverBase> host_resolver; 96 scoped_ptr<CertVerifier> cert_verifier; 97 scoped_refptr<ProxyService> proxy_service; 98 scoped_refptr<SSLConfigService> ssl_config_service; 99 MockClientSocketFactory socket_factory; 100 scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory; 101 NetLog* net_log; 102 }; 103 104 HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { 105 net::HttpNetworkSession::Params params; 106 params.client_socket_factory = &session_deps->socket_factory; 107 params.host_resolver = session_deps->host_resolver.get(); 108 params.cert_verifier = session_deps->cert_verifier.get(); 109 params.proxy_service = session_deps->proxy_service; 110 params.ssl_config_service = session_deps->ssl_config_service; 111 params.http_auth_handler_factory = 112 session_deps->http_auth_handler_factory.get(); 113 params.net_log = session_deps->net_log; 114 return new HttpNetworkSession(params); 115 } 116 117 class HttpNetworkTransactionTest : public PlatformTest { 118 public: 119 virtual void SetUp() { 120 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); 121 MessageLoop::current()->RunAllPending(); 122 spdy::SpdyFramer::set_enable_compression_default(false); 123 } 124 125 virtual void TearDown() { 126 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); 127 MessageLoop::current()->RunAllPending(); 128 spdy::SpdyFramer::set_enable_compression_default(true); 129 // Empty the current queue. 130 MessageLoop::current()->RunAllPending(); 131 PlatformTest::TearDown(); 132 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); 133 MessageLoop::current()->RunAllPending(); 134 } 135 136 protected: 137 void KeepAliveConnectionResendRequestTest(const MockRead& read_failure); 138 139 struct SimpleGetHelperResult { 140 int rv; 141 std::string status_line; 142 std::string response_data; 143 }; 144 145 SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[], 146 size_t reads_count) { 147 SimpleGetHelperResult out; 148 149 HttpRequestInfo request; 150 request.method = "GET"; 151 request.url = GURL("http://www.google.com/"); 152 request.load_flags = 0; 153 154 SessionDependencies session_deps; 155 scoped_ptr<HttpTransaction> trans( 156 new HttpNetworkTransaction(CreateSession(&session_deps))); 157 158 StaticSocketDataProvider data(data_reads, reads_count, NULL, 0); 159 session_deps.socket_factory.AddSocketDataProvider(&data); 160 161 TestCompletionCallback callback; 162 163 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 164 EXPECT_TRUE(log.bound().IsLoggingAllEvents()); 165 int rv = trans->Start(&request, &callback, log.bound()); 166 EXPECT_EQ(ERR_IO_PENDING, rv); 167 168 out.rv = callback.WaitForResult(); 169 if (out.rv != OK) 170 return out; 171 172 const HttpResponseInfo* response = trans->GetResponseInfo(); 173 EXPECT_TRUE(response != NULL); 174 175 EXPECT_TRUE(response->headers != NULL); 176 out.status_line = response->headers->GetStatusLine(); 177 178 EXPECT_EQ("192.0.2.33", response->socket_address.host()); 179 EXPECT_EQ(0, response->socket_address.port()); 180 181 rv = ReadTransaction(trans.get(), &out.response_data); 182 EXPECT_EQ(OK, rv); 183 184 net::CapturingNetLog::EntryList entries; 185 log.GetEntries(&entries); 186 size_t pos = ExpectLogContainsSomewhere( 187 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS, 188 NetLog::PHASE_NONE); 189 ExpectLogContainsSomewhere( 190 entries, pos, 191 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS, 192 NetLog::PHASE_NONE); 193 194 CapturingNetLog::Entry entry = entries[pos]; 195 NetLogHttpRequestParameter* request_params = 196 static_cast<NetLogHttpRequestParameter*>(entry.extra_parameters.get()); 197 EXPECT_EQ("GET / HTTP/1.1\r\n", request_params->GetLine()); 198 EXPECT_EQ("Host: www.google.com\r\n" 199 "Connection: keep-alive\r\n\r\n", 200 request_params->GetHeaders().ToString()); 201 202 return out; 203 } 204 205 void ConnectStatusHelperWithExpectedStatus(const MockRead& status, 206 int expected_status); 207 208 void ConnectStatusHelper(const MockRead& status); 209 }; 210 211 // Fill |str| with a long header list that consumes >= |size| bytes. 212 void FillLargeHeadersString(std::string* str, int size) { 213 const char* row = 214 "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"; 215 const int sizeof_row = strlen(row); 216 const int num_rows = static_cast<int>( 217 ceil(static_cast<float>(size) / sizeof_row)); 218 const int sizeof_data = num_rows * sizeof_row; 219 DCHECK(sizeof_data >= size); 220 str->reserve(sizeof_data); 221 222 for (int i = 0; i < num_rows; ++i) 223 str->append(row, sizeof_row); 224 } 225 226 // Alternative functions that eliminate randomness and dependency on the local 227 // host name so that the generated NTLM messages are reproducible. 228 void MockGenerateRandom1(uint8* output, size_t n) { 229 static const uint8 bytes[] = { 230 0x55, 0x29, 0x66, 0x26, 0x6b, 0x9c, 0x73, 0x54 231 }; 232 static size_t current_byte = 0; 233 for (size_t i = 0; i < n; ++i) { 234 output[i] = bytes[current_byte++]; 235 current_byte %= arraysize(bytes); 236 } 237 } 238 239 void MockGenerateRandom2(uint8* output, size_t n) { 240 static const uint8 bytes[] = { 241 0x96, 0x79, 0x85, 0xe7, 0x49, 0x93, 0x70, 0xa1, 242 0x4e, 0xe7, 0x87, 0x45, 0x31, 0x5b, 0xd3, 0x1f 243 }; 244 static size_t current_byte = 0; 245 for (size_t i = 0; i < n; ++i) { 246 output[i] = bytes[current_byte++]; 247 current_byte %= arraysize(bytes); 248 } 249 } 250 251 std::string MockGetHostName() { 252 return "WTC-WIN7"; 253 } 254 255 template<typename ParentPool> 256 class CaptureGroupNameSocketPool : public ParentPool { 257 public: 258 CaptureGroupNameSocketPool(HostResolver* host_resolver, 259 CertVerifier* cert_verifier); 260 261 const std::string last_group_name_received() const { 262 return last_group_name_; 263 } 264 265 virtual int RequestSocket(const std::string& group_name, 266 const void* socket_params, 267 RequestPriority priority, 268 ClientSocketHandle* handle, 269 CompletionCallback* callback, 270 const BoundNetLog& net_log) { 271 last_group_name_ = group_name; 272 return ERR_IO_PENDING; 273 } 274 virtual void CancelRequest(const std::string& group_name, 275 ClientSocketHandle* handle) {} 276 virtual void ReleaseSocket(const std::string& group_name, 277 ClientSocket* socket, 278 int id) {} 279 virtual void CloseIdleSockets() {} 280 virtual int IdleSocketCount() const { 281 return 0; 282 } 283 virtual int IdleSocketCountInGroup(const std::string& group_name) const { 284 return 0; 285 } 286 virtual LoadState GetLoadState(const std::string& group_name, 287 const ClientSocketHandle* handle) const { 288 return LOAD_STATE_IDLE; 289 } 290 virtual base::TimeDelta ConnectionTimeout() const { 291 return base::TimeDelta(); 292 } 293 294 private: 295 std::string last_group_name_; 296 }; 297 298 typedef CaptureGroupNameSocketPool<TransportClientSocketPool> 299 CaptureGroupNameTransportSocketPool; 300 typedef CaptureGroupNameSocketPool<HttpProxyClientSocketPool> 301 CaptureGroupNameHttpProxySocketPool; 302 typedef CaptureGroupNameSocketPool<SOCKSClientSocketPool> 303 CaptureGroupNameSOCKSSocketPool; 304 typedef CaptureGroupNameSocketPool<SSLClientSocketPool> 305 CaptureGroupNameSSLSocketPool; 306 307 template<typename ParentPool> 308 CaptureGroupNameSocketPool<ParentPool>::CaptureGroupNameSocketPool( 309 HostResolver* host_resolver, 310 CertVerifier* /* cert_verifier */) 311 : ParentPool(0, 0, NULL, host_resolver, NULL, NULL) {} 312 313 template<> 314 CaptureGroupNameHttpProxySocketPool::CaptureGroupNameSocketPool( 315 HostResolver* host_resolver, 316 CertVerifier* /* cert_verifier */) 317 : HttpProxyClientSocketPool(0, 0, NULL, host_resolver, NULL, NULL, NULL) {} 318 319 template<> 320 CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool( 321 HostResolver* host_resolver, 322 CertVerifier* cert_verifier) 323 : SSLClientSocketPool(0, 0, NULL, host_resolver, cert_verifier, NULL, NULL, 324 NULL, NULL, NULL, NULL, NULL, NULL, NULL) {} 325 326 //----------------------------------------------------------------------------- 327 328 // This is the expected list of advertised protocols from the browser's NPN 329 // list. 330 static const char kExpectedNPNString[] = "\x08http/1.1\x06spdy/2"; 331 332 // This is the expected return from a current server advertising SPDY. 333 static const char kAlternateProtocolHttpHeader[] = 334 "Alternate-Protocol: 443:npn-spdy/2\r\n\r\n"; 335 336 TEST_F(HttpNetworkTransactionTest, Basic) { 337 SessionDependencies session_deps; 338 scoped_ptr<HttpTransaction> trans( 339 new HttpNetworkTransaction(CreateSession(&session_deps))); 340 } 341 342 TEST_F(HttpNetworkTransactionTest, SimpleGET) { 343 MockRead data_reads[] = { 344 MockRead("HTTP/1.0 200 OK\r\n\r\n"), 345 MockRead("hello world"), 346 MockRead(false, OK), 347 }; 348 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 349 arraysize(data_reads)); 350 EXPECT_EQ(OK, out.rv); 351 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); 352 EXPECT_EQ("hello world", out.response_data); 353 } 354 355 // Response with no status line. 356 TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) { 357 MockRead data_reads[] = { 358 MockRead("hello world"), 359 MockRead(false, OK), 360 }; 361 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 362 arraysize(data_reads)); 363 EXPECT_EQ(OK, out.rv); 364 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); 365 EXPECT_EQ("hello world", out.response_data); 366 } 367 368 // Allow up to 4 bytes of junk to precede status line. 369 TEST_F(HttpNetworkTransactionTest, StatusLineJunk2Bytes) { 370 MockRead data_reads[] = { 371 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), 372 MockRead(false, OK), 373 }; 374 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 375 arraysize(data_reads)); 376 EXPECT_EQ(OK, out.rv); 377 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); 378 EXPECT_EQ("DATA", out.response_data); 379 } 380 381 // Allow up to 4 bytes of junk to precede status line. 382 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) { 383 MockRead data_reads[] = { 384 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), 385 MockRead(false, OK), 386 }; 387 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 388 arraysize(data_reads)); 389 EXPECT_EQ(OK, out.rv); 390 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); 391 EXPECT_EQ("DATA", out.response_data); 392 } 393 394 // Beyond 4 bytes of slop and it should fail to find a status line. 395 TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) { 396 MockRead data_reads[] = { 397 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"), 398 MockRead(false, OK), 399 }; 400 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 401 arraysize(data_reads)); 402 EXPECT_EQ(OK, out.rv); 403 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); 404 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data); 405 } 406 407 // Same as StatusLineJunk4Bytes, except the read chunks are smaller. 408 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) { 409 MockRead data_reads[] = { 410 MockRead("\n"), 411 MockRead("\n"), 412 MockRead("Q"), 413 MockRead("J"), 414 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), 415 MockRead(false, OK), 416 }; 417 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 418 arraysize(data_reads)); 419 EXPECT_EQ(OK, out.rv); 420 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); 421 EXPECT_EQ("DATA", out.response_data); 422 } 423 424 // Close the connection before enough bytes to have a status line. 425 TEST_F(HttpNetworkTransactionTest, StatusLinePartial) { 426 MockRead data_reads[] = { 427 MockRead("HTT"), 428 MockRead(false, OK), 429 }; 430 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 431 arraysize(data_reads)); 432 EXPECT_EQ(OK, out.rv); 433 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); 434 EXPECT_EQ("HTT", out.response_data); 435 } 436 437 // Simulate a 204 response, lacking a Content-Length header, sent over a 438 // persistent connection. The response should still terminate since a 204 439 // cannot have a response body. 440 TEST_F(HttpNetworkTransactionTest, StopsReading204) { 441 MockRead data_reads[] = { 442 MockRead("HTTP/1.1 204 No Content\r\n\r\n"), 443 MockRead("junk"), // Should not be read!! 444 MockRead(false, OK), 445 }; 446 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 447 arraysize(data_reads)); 448 EXPECT_EQ(OK, out.rv); 449 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line); 450 EXPECT_EQ("", out.response_data); 451 } 452 453 // A simple request using chunked encoding with some extra data after. 454 // (Like might be seen in a pipelined response.) 455 TEST_F(HttpNetworkTransactionTest, ChunkedEncoding) { 456 MockRead data_reads[] = { 457 MockRead("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"), 458 MockRead("5\r\nHello\r\n"), 459 MockRead("1\r\n"), 460 MockRead(" \r\n"), 461 MockRead("5\r\nworld\r\n"), 462 MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"), 463 MockRead(false, OK), 464 }; 465 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 466 arraysize(data_reads)); 467 EXPECT_EQ(OK, out.rv); 468 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); 469 EXPECT_EQ("Hello world", out.response_data); 470 } 471 472 // Next tests deal with http://crbug.com/56344. 473 474 TEST_F(HttpNetworkTransactionTest, 475 MultipleContentLengthHeadersNoTransferEncoding) { 476 MockRead data_reads[] = { 477 MockRead("HTTP/1.1 200 OK\r\n"), 478 MockRead("Content-Length: 10\r\n"), 479 MockRead("Content-Length: 5\r\n\r\n"), 480 }; 481 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 482 arraysize(data_reads)); 483 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv); 484 } 485 486 TEST_F(HttpNetworkTransactionTest, 487 DuplicateContentLengthHeadersNoTransferEncoding) { 488 MockRead data_reads[] = { 489 MockRead("HTTP/1.1 200 OK\r\n"), 490 MockRead("Content-Length: 5\r\n"), 491 MockRead("Content-Length: 5\r\n\r\n"), 492 MockRead("Hello"), 493 }; 494 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 495 arraysize(data_reads)); 496 EXPECT_EQ(OK, out.rv); 497 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); 498 EXPECT_EQ("Hello", out.response_data); 499 } 500 501 TEST_F(HttpNetworkTransactionTest, 502 ComplexContentLengthHeadersNoTransferEncoding) { 503 // More than 2 dupes. 504 { 505 MockRead data_reads[] = { 506 MockRead("HTTP/1.1 200 OK\r\n"), 507 MockRead("Content-Length: 5\r\n"), 508 MockRead("Content-Length: 5\r\n"), 509 MockRead("Content-Length: 5\r\n\r\n"), 510 MockRead("Hello"), 511 }; 512 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 513 arraysize(data_reads)); 514 EXPECT_EQ(OK, out.rv); 515 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); 516 EXPECT_EQ("Hello", out.response_data); 517 } 518 // HTTP/1.0 519 { 520 MockRead data_reads[] = { 521 MockRead("HTTP/1.0 200 OK\r\n"), 522 MockRead("Content-Length: 5\r\n"), 523 MockRead("Content-Length: 5\r\n"), 524 MockRead("Content-Length: 5\r\n\r\n"), 525 MockRead("Hello"), 526 }; 527 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 528 arraysize(data_reads)); 529 EXPECT_EQ(OK, out.rv); 530 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); 531 EXPECT_EQ("Hello", out.response_data); 532 } 533 // 2 dupes and one mismatched. 534 { 535 MockRead data_reads[] = { 536 MockRead("HTTP/1.1 200 OK\r\n"), 537 MockRead("Content-Length: 10\r\n"), 538 MockRead("Content-Length: 10\r\n"), 539 MockRead("Content-Length: 5\r\n\r\n"), 540 }; 541 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 542 arraysize(data_reads)); 543 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv); 544 } 545 } 546 547 TEST_F(HttpNetworkTransactionTest, 548 MultipleContentLengthHeadersTransferEncoding) { 549 MockRead data_reads[] = { 550 MockRead("HTTP/1.1 200 OK\r\n"), 551 MockRead("Content-Length: 666\r\n"), 552 MockRead("Content-Length: 1337\r\n"), 553 MockRead("Transfer-Encoding: chunked\r\n\r\n"), 554 MockRead("5\r\nHello\r\n"), 555 MockRead("1\r\n"), 556 MockRead(" \r\n"), 557 MockRead("5\r\nworld\r\n"), 558 MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"), 559 MockRead(false, OK), 560 }; 561 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 562 arraysize(data_reads)); 563 EXPECT_EQ(OK, out.rv); 564 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); 565 EXPECT_EQ("Hello world", out.response_data); 566 } 567 568 // Do a request using the HEAD method. Verify that we don't try to read the 569 // message body (since HEAD has none). 570 TEST_F(HttpNetworkTransactionTest, Head) { 571 HttpRequestInfo request; 572 request.method = "HEAD"; 573 request.url = GURL("http://www.google.com/"); 574 request.load_flags = 0; 575 576 SessionDependencies session_deps; 577 scoped_ptr<HttpTransaction> trans( 578 new HttpNetworkTransaction(CreateSession(&session_deps))); 579 580 MockWrite data_writes1[] = { 581 MockWrite("HEAD / HTTP/1.1\r\n" 582 "Host: www.google.com\r\n" 583 "Connection: keep-alive\r\n" 584 "Content-Length: 0\r\n\r\n"), 585 }; 586 MockRead data_reads1[] = { 587 MockRead("HTTP/1.1 404 Not Found\r\n"), 588 MockRead("Server: Blah\r\n"), 589 MockRead("Content-Length: 1234\r\n\r\n"), 590 591 // No response body because the test stops reading here. 592 MockRead(false, ERR_UNEXPECTED), // Should not be reached. 593 }; 594 595 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 596 data_writes1, arraysize(data_writes1)); 597 session_deps.socket_factory.AddSocketDataProvider(&data1); 598 599 TestCompletionCallback callback1; 600 601 int rv = trans->Start(&request, &callback1, BoundNetLog()); 602 EXPECT_EQ(ERR_IO_PENDING, rv); 603 604 rv = callback1.WaitForResult(); 605 EXPECT_EQ(OK, rv); 606 607 const HttpResponseInfo* response = trans->GetResponseInfo(); 608 EXPECT_FALSE(response == NULL); 609 610 // Check that the headers got parsed. 611 EXPECT_TRUE(response->headers != NULL); 612 EXPECT_EQ(1234, response->headers->GetContentLength()); 613 EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine()); 614 615 std::string server_header; 616 void* iter = NULL; 617 bool has_server_header = response->headers->EnumerateHeader( 618 &iter, "Server", &server_header); 619 EXPECT_TRUE(has_server_header); 620 EXPECT_EQ("Blah", server_header); 621 622 // Reading should give EOF right away, since there is no message body 623 // (despite non-zero content-length). 624 std::string response_data; 625 rv = ReadTransaction(trans.get(), &response_data); 626 EXPECT_EQ(OK, rv); 627 EXPECT_EQ("", response_data); 628 } 629 630 TEST_F(HttpNetworkTransactionTest, ReuseConnection) { 631 SessionDependencies session_deps; 632 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 633 634 MockRead data_reads[] = { 635 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), 636 MockRead("hello"), 637 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), 638 MockRead("world"), 639 MockRead(false, OK), 640 }; 641 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); 642 session_deps.socket_factory.AddSocketDataProvider(&data); 643 644 const char* const kExpectedResponseData[] = { 645 "hello", "world" 646 }; 647 648 for (int i = 0; i < 2; ++i) { 649 HttpRequestInfo request; 650 request.method = "GET"; 651 request.url = GURL("http://www.google.com/"); 652 request.load_flags = 0; 653 654 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 655 656 TestCompletionCallback callback; 657 658 int rv = trans->Start(&request, &callback, BoundNetLog()); 659 EXPECT_EQ(ERR_IO_PENDING, rv); 660 661 rv = callback.WaitForResult(); 662 EXPECT_EQ(OK, rv); 663 664 const HttpResponseInfo* response = trans->GetResponseInfo(); 665 EXPECT_TRUE(response != NULL); 666 667 EXPECT_TRUE(response->headers != NULL); 668 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 669 670 std::string response_data; 671 rv = ReadTransaction(trans.get(), &response_data); 672 EXPECT_EQ(OK, rv); 673 EXPECT_EQ(kExpectedResponseData[i], response_data); 674 } 675 } 676 677 TEST_F(HttpNetworkTransactionTest, Ignores100) { 678 HttpRequestInfo request; 679 request.method = "POST"; 680 request.url = GURL("http://www.foo.com/"); 681 request.upload_data = new UploadData; 682 request.upload_data->AppendBytes("foo", 3); 683 request.load_flags = 0; 684 685 SessionDependencies session_deps; 686 scoped_ptr<HttpTransaction> trans( 687 new HttpNetworkTransaction(CreateSession(&session_deps))); 688 689 MockRead data_reads[] = { 690 MockRead("HTTP/1.0 100 Continue\r\n\r\n"), 691 MockRead("HTTP/1.0 200 OK\r\n\r\n"), 692 MockRead("hello world"), 693 MockRead(false, OK), 694 }; 695 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); 696 session_deps.socket_factory.AddSocketDataProvider(&data); 697 698 TestCompletionCallback callback; 699 700 int rv = trans->Start(&request, &callback, BoundNetLog()); 701 EXPECT_EQ(ERR_IO_PENDING, rv); 702 703 rv = callback.WaitForResult(); 704 EXPECT_EQ(OK, rv); 705 706 const HttpResponseInfo* response = trans->GetResponseInfo(); 707 EXPECT_TRUE(response != NULL); 708 709 EXPECT_TRUE(response->headers != NULL); 710 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); 711 712 std::string response_data; 713 rv = ReadTransaction(trans.get(), &response_data); 714 EXPECT_EQ(OK, rv); 715 EXPECT_EQ("hello world", response_data); 716 } 717 718 // This test is almost the same as Ignores100 above, but the response contains 719 // a 102 instead of a 100. Also, instead of HTTP/1.0 the response is 720 // HTTP/1.1 and the two status headers are read in one read. 721 TEST_F(HttpNetworkTransactionTest, Ignores1xx) { 722 HttpRequestInfo request; 723 request.method = "GET"; 724 request.url = GURL("http://www.foo.com/"); 725 request.load_flags = 0; 726 727 SessionDependencies session_deps; 728 scoped_ptr<HttpTransaction> trans( 729 new HttpNetworkTransaction(CreateSession(&session_deps))); 730 731 MockRead data_reads[] = { 732 MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n" 733 "HTTP/1.1 200 OK\r\n\r\n"), 734 MockRead("hello world"), 735 MockRead(false, OK), 736 }; 737 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); 738 session_deps.socket_factory.AddSocketDataProvider(&data); 739 740 TestCompletionCallback callback; 741 742 int rv = trans->Start(&request, &callback, BoundNetLog()); 743 EXPECT_EQ(ERR_IO_PENDING, rv); 744 745 rv = callback.WaitForResult(); 746 EXPECT_EQ(OK, rv); 747 748 const HttpResponseInfo* response = trans->GetResponseInfo(); 749 EXPECT_TRUE(response != NULL); 750 751 EXPECT_TRUE(response->headers != NULL); 752 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 753 754 std::string response_data; 755 rv = ReadTransaction(trans.get(), &response_data); 756 EXPECT_EQ(OK, rv); 757 EXPECT_EQ("hello world", response_data); 758 } 759 760 TEST_F(HttpNetworkTransactionTest, Incomplete100ThenEOF) { 761 HttpRequestInfo request; 762 request.method = "POST"; 763 request.url = GURL("http://www.foo.com/"); 764 request.load_flags = 0; 765 766 SessionDependencies session_deps; 767 scoped_ptr<HttpTransaction> trans( 768 new HttpNetworkTransaction(CreateSession(&session_deps))); 769 770 MockRead data_reads[] = { 771 MockRead(false, "HTTP/1.0 100 Continue\r\n"), 772 MockRead(true, 0), 773 }; 774 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); 775 session_deps.socket_factory.AddSocketDataProvider(&data); 776 777 TestCompletionCallback callback; 778 779 int rv = trans->Start(&request, &callback, BoundNetLog()); 780 EXPECT_EQ(ERR_IO_PENDING, rv); 781 782 rv = callback.WaitForResult(); 783 EXPECT_EQ(OK, rv); 784 785 std::string response_data; 786 rv = ReadTransaction(trans.get(), &response_data); 787 EXPECT_EQ(OK, rv); 788 EXPECT_EQ("", response_data); 789 } 790 791 TEST_F(HttpNetworkTransactionTest, EmptyResponse) { 792 HttpRequestInfo request; 793 request.method = "POST"; 794 request.url = GURL("http://www.foo.com/"); 795 request.load_flags = 0; 796 797 SessionDependencies session_deps; 798 scoped_ptr<HttpTransaction> trans( 799 new HttpNetworkTransaction(CreateSession(&session_deps))); 800 801 MockRead data_reads[] = { 802 MockRead(true, 0), 803 }; 804 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); 805 session_deps.socket_factory.AddSocketDataProvider(&data); 806 807 TestCompletionCallback callback; 808 809 int rv = trans->Start(&request, &callback, BoundNetLog()); 810 EXPECT_EQ(ERR_IO_PENDING, rv); 811 812 rv = callback.WaitForResult(); 813 EXPECT_EQ(ERR_EMPTY_RESPONSE, rv); 814 } 815 816 // read_failure specifies a read failure that should cause the network 817 // transaction to resend the request. 818 void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest( 819 const MockRead& read_failure) { 820 HttpRequestInfo request; 821 request.method = "GET"; 822 request.url = GURL("http://www.foo.com/"); 823 request.load_flags = 0; 824 825 SessionDependencies session_deps; 826 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 827 828 MockRead data1_reads[] = { 829 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), 830 MockRead("hello"), 831 read_failure, // Now, we reuse the connection and fail the first read. 832 }; 833 StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), NULL, 0); 834 session_deps.socket_factory.AddSocketDataProvider(&data1); 835 836 MockRead data2_reads[] = { 837 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), 838 MockRead("world"), 839 MockRead(true, OK), 840 }; 841 StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0); 842 session_deps.socket_factory.AddSocketDataProvider(&data2); 843 844 const char* kExpectedResponseData[] = { 845 "hello", "world" 846 }; 847 848 for (int i = 0; i < 2; ++i) { 849 TestCompletionCallback callback; 850 851 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 852 853 int rv = trans->Start(&request, &callback, BoundNetLog()); 854 EXPECT_EQ(ERR_IO_PENDING, rv); 855 856 rv = callback.WaitForResult(); 857 EXPECT_EQ(OK, rv); 858 859 const HttpResponseInfo* response = trans->GetResponseInfo(); 860 EXPECT_TRUE(response != NULL); 861 862 EXPECT_TRUE(response->headers != NULL); 863 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 864 865 std::string response_data; 866 rv = ReadTransaction(trans.get(), &response_data); 867 EXPECT_EQ(OK, rv); 868 EXPECT_EQ(kExpectedResponseData[i], response_data); 869 } 870 } 871 872 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) { 873 MockRead read_failure(true, ERR_CONNECTION_RESET); 874 KeepAliveConnectionResendRequestTest(read_failure); 875 } 876 877 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) { 878 MockRead read_failure(false, OK); // EOF 879 KeepAliveConnectionResendRequestTest(read_failure); 880 } 881 882 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) { 883 HttpRequestInfo request; 884 request.method = "GET"; 885 request.url = GURL("http://www.google.com/"); 886 request.load_flags = 0; 887 888 SessionDependencies session_deps; 889 scoped_ptr<HttpTransaction> trans( 890 new HttpNetworkTransaction(CreateSession(&session_deps))); 891 892 MockRead data_reads[] = { 893 MockRead(true, ERR_CONNECTION_RESET), 894 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used 895 MockRead("hello world"), 896 MockRead(false, OK), 897 }; 898 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); 899 session_deps.socket_factory.AddSocketDataProvider(&data); 900 901 TestCompletionCallback callback; 902 903 int rv = trans->Start(&request, &callback, BoundNetLog()); 904 EXPECT_EQ(ERR_IO_PENDING, rv); 905 906 rv = callback.WaitForResult(); 907 EXPECT_EQ(ERR_CONNECTION_RESET, rv); 908 909 const HttpResponseInfo* response = trans->GetResponseInfo(); 910 EXPECT_TRUE(response == NULL); 911 } 912 913 // What do various browsers do when the server closes a non-keepalive 914 // connection without sending any response header or body? 915 // 916 // IE7: error page 917 // Safari 3.1.2 (Windows): error page 918 // Firefox 3.0.1: blank page 919 // Opera 9.52: after five attempts, blank page 920 // Us with WinHTTP: error page (ERR_INVALID_RESPONSE) 921 // Us: error page (EMPTY_RESPONSE) 922 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) { 923 MockRead data_reads[] = { 924 MockRead(false, OK), // EOF 925 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used 926 MockRead("hello world"), 927 MockRead(false, OK), 928 }; 929 SimpleGetHelperResult out = SimpleGetHelper(data_reads, 930 arraysize(data_reads)); 931 EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv); 932 } 933 934 // Test that we correctly reuse a keep-alive connection after not explicitly 935 // reading the body. 936 TEST_F(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) { 937 HttpRequestInfo request; 938 request.method = "GET"; 939 request.url = GURL("http://www.foo.com/"); 940 request.load_flags = 0; 941 942 SessionDependencies session_deps; 943 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 944 945 // Note that because all these reads happen in the same 946 // StaticSocketDataProvider, it shows that the same socket is being reused for 947 // all transactions. 948 MockRead data1_reads[] = { 949 MockRead("HTTP/1.1 204 No Content\r\n\r\n"), 950 MockRead("HTTP/1.1 205 Reset Content\r\n\r\n"), 951 MockRead("HTTP/1.1 304 Not Modified\r\n\r\n"), 952 MockRead("HTTP/1.1 302 Found\r\n" 953 "Content-Length: 0\r\n\r\n"), 954 MockRead("HTTP/1.1 302 Found\r\n" 955 "Content-Length: 5\r\n\r\n" 956 "hello"), 957 MockRead("HTTP/1.1 301 Moved Permanently\r\n" 958 "Content-Length: 0\r\n\r\n"), 959 MockRead("HTTP/1.1 301 Moved Permanently\r\n" 960 "Content-Length: 5\r\n\r\n" 961 "hello"), 962 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), 963 MockRead("hello"), 964 }; 965 StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), NULL, 0); 966 session_deps.socket_factory.AddSocketDataProvider(&data1); 967 968 MockRead data2_reads[] = { 969 MockRead(false, ERR_UNEXPECTED), // Should not be reached. 970 }; 971 StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0); 972 session_deps.socket_factory.AddSocketDataProvider(&data2); 973 974 const int kNumUnreadBodies = arraysize(data1_reads) - 2; 975 std::string response_lines[kNumUnreadBodies]; 976 977 for (size_t i = 0; i < arraysize(data1_reads) - 2; ++i) { 978 TestCompletionCallback callback; 979 980 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 981 982 int rv = trans->Start(&request, &callback, BoundNetLog()); 983 EXPECT_EQ(ERR_IO_PENDING, rv); 984 985 rv = callback.WaitForResult(); 986 EXPECT_EQ(OK, rv); 987 988 const HttpResponseInfo* response = trans->GetResponseInfo(); 989 ASSERT_TRUE(response != NULL); 990 991 ASSERT_TRUE(response->headers != NULL); 992 response_lines[i] = response->headers->GetStatusLine(); 993 994 // We intentionally don't read the response bodies. 995 } 996 997 const char* const kStatusLines[] = { 998 "HTTP/1.1 204 No Content", 999 "HTTP/1.1 205 Reset Content", 1000 "HTTP/1.1 304 Not Modified", 1001 "HTTP/1.1 302 Found", 1002 "HTTP/1.1 302 Found", 1003 "HTTP/1.1 301 Moved Permanently", 1004 "HTTP/1.1 301 Moved Permanently", 1005 }; 1006 1007 COMPILE_ASSERT(kNumUnreadBodies == arraysize(kStatusLines), 1008 forgot_to_update_kStatusLines); 1009 1010 for (int i = 0; i < kNumUnreadBodies; ++i) 1011 EXPECT_EQ(kStatusLines[i], response_lines[i]); 1012 1013 TestCompletionCallback callback; 1014 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1015 int rv = trans->Start(&request, &callback, BoundNetLog()); 1016 EXPECT_EQ(ERR_IO_PENDING, rv); 1017 rv = callback.WaitForResult(); 1018 EXPECT_EQ(OK, rv); 1019 const HttpResponseInfo* response = trans->GetResponseInfo(); 1020 ASSERT_TRUE(response != NULL); 1021 ASSERT_TRUE(response->headers != NULL); 1022 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 1023 std::string response_data; 1024 rv = ReadTransaction(trans.get(), &response_data); 1025 EXPECT_EQ(OK, rv); 1026 EXPECT_EQ("hello", response_data); 1027 } 1028 1029 // Test the request-challenge-retry sequence for basic auth. 1030 // (basic auth is the easiest to mock, because it has no randomness). 1031 TEST_F(HttpNetworkTransactionTest, BasicAuth) { 1032 HttpRequestInfo request; 1033 request.method = "GET"; 1034 request.url = GURL("http://www.google.com/"); 1035 request.load_flags = 0; 1036 1037 SessionDependencies session_deps; 1038 scoped_ptr<HttpTransaction> trans( 1039 new HttpNetworkTransaction(CreateSession(&session_deps))); 1040 1041 MockWrite data_writes1[] = { 1042 MockWrite("GET / HTTP/1.1\r\n" 1043 "Host: www.google.com\r\n" 1044 "Connection: keep-alive\r\n\r\n"), 1045 }; 1046 1047 MockRead data_reads1[] = { 1048 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 1049 // Give a couple authenticate options (only the middle one is actually 1050 // supported). 1051 MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed. 1052 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1053 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), 1054 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1055 // Large content-length -- won't matter, as connection will be reset. 1056 MockRead("Content-Length: 10000\r\n\r\n"), 1057 MockRead(false, ERR_FAILED), 1058 }; 1059 1060 // After calling trans->RestartWithAuth(), this is the request we should 1061 // be issuing -- the final header line contains the credentials. 1062 MockWrite data_writes2[] = { 1063 MockWrite("GET / HTTP/1.1\r\n" 1064 "Host: www.google.com\r\n" 1065 "Connection: keep-alive\r\n" 1066 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 1067 }; 1068 1069 // Lastly, the server responds with the actual content. 1070 MockRead data_reads2[] = { 1071 MockRead("HTTP/1.0 200 OK\r\n"), 1072 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1073 MockRead("Content-Length: 100\r\n\r\n"), 1074 MockRead(false, OK), 1075 }; 1076 1077 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 1078 data_writes1, arraysize(data_writes1)); 1079 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 1080 data_writes2, arraysize(data_writes2)); 1081 session_deps.socket_factory.AddSocketDataProvider(&data1); 1082 session_deps.socket_factory.AddSocketDataProvider(&data2); 1083 1084 TestCompletionCallback callback1; 1085 1086 int rv = trans->Start(&request, &callback1, BoundNetLog()); 1087 EXPECT_EQ(ERR_IO_PENDING, rv); 1088 1089 rv = callback1.WaitForResult(); 1090 EXPECT_EQ(OK, rv); 1091 1092 const HttpResponseInfo* response = trans->GetResponseInfo(); 1093 EXPECT_FALSE(response == NULL); 1094 1095 // The password prompt info should have been set in response->auth_challenge. 1096 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1097 1098 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 1099 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1100 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1101 1102 TestCompletionCallback callback2; 1103 1104 rv = trans->RestartWithAuth(kFoo, kBar, &callback2); 1105 EXPECT_EQ(ERR_IO_PENDING, rv); 1106 1107 rv = callback2.WaitForResult(); 1108 EXPECT_EQ(OK, rv); 1109 1110 response = trans->GetResponseInfo(); 1111 EXPECT_FALSE(response == NULL); 1112 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1113 EXPECT_EQ(100, response->headers->GetContentLength()); 1114 } 1115 1116 TEST_F(HttpNetworkTransactionTest, DoNotSendAuth) { 1117 HttpRequestInfo request; 1118 request.method = "GET"; 1119 request.url = GURL("http://www.google.com/"); 1120 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; 1121 1122 SessionDependencies session_deps; 1123 scoped_ptr<HttpTransaction> trans( 1124 new HttpNetworkTransaction(CreateSession(&session_deps))); 1125 1126 MockWrite data_writes[] = { 1127 MockWrite("GET / HTTP/1.1\r\n" 1128 "Host: www.google.com\r\n" 1129 "Connection: keep-alive\r\n\r\n"), 1130 }; 1131 1132 MockRead data_reads[] = { 1133 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 1134 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1135 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1136 // Large content-length -- won't matter, as connection will be reset. 1137 MockRead("Content-Length: 10000\r\n\r\n"), 1138 MockRead(false, ERR_FAILED), 1139 }; 1140 1141 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 1142 data_writes, arraysize(data_writes)); 1143 session_deps.socket_factory.AddSocketDataProvider(&data); 1144 TestCompletionCallback callback; 1145 1146 int rv = trans->Start(&request, &callback, BoundNetLog()); 1147 EXPECT_EQ(ERR_IO_PENDING, rv); 1148 1149 rv = callback.WaitForResult(); 1150 EXPECT_EQ(0, rv); 1151 1152 const HttpResponseInfo* response = trans->GetResponseInfo(); 1153 ASSERT_FALSE(response == NULL); 1154 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1155 } 1156 1157 // Test the request-challenge-retry sequence for basic auth, over a keep-alive 1158 // connection. 1159 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) { 1160 HttpRequestInfo request; 1161 request.method = "GET"; 1162 request.url = GURL("http://www.google.com/"); 1163 request.load_flags = 0; 1164 1165 SessionDependencies session_deps; 1166 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1167 1168 MockWrite data_writes1[] = { 1169 MockWrite("GET / HTTP/1.1\r\n" 1170 "Host: www.google.com\r\n" 1171 "Connection: keep-alive\r\n\r\n"), 1172 1173 // After calling trans->RestartWithAuth(), this is the request we should 1174 // be issuing -- the final header line contains the credentials. 1175 MockWrite("GET / HTTP/1.1\r\n" 1176 "Host: www.google.com\r\n" 1177 "Connection: keep-alive\r\n" 1178 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 1179 }; 1180 1181 MockRead data_reads1[] = { 1182 MockRead("HTTP/1.1 401 Unauthorized\r\n"), 1183 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1184 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1185 MockRead("Content-Length: 14\r\n\r\n"), 1186 MockRead("Unauthorized\r\n"), 1187 1188 // Lastly, the server responds with the actual content. 1189 MockRead("HTTP/1.1 200 OK\r\n"), 1190 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1191 MockRead("Content-Length: 5\r\n\r\n"), 1192 MockRead("Hello"), 1193 }; 1194 1195 // If there is a regression where we disconnect a Keep-Alive 1196 // connection during an auth roundtrip, we'll end up reading this. 1197 MockRead data_reads2[] = { 1198 MockRead(false, ERR_FAILED), 1199 }; 1200 1201 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 1202 data_writes1, arraysize(data_writes1)); 1203 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 1204 NULL, 0); 1205 session_deps.socket_factory.AddSocketDataProvider(&data1); 1206 session_deps.socket_factory.AddSocketDataProvider(&data2); 1207 1208 TestCompletionCallback callback1; 1209 1210 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1211 int rv = trans->Start(&request, &callback1, BoundNetLog()); 1212 EXPECT_EQ(ERR_IO_PENDING, rv); 1213 1214 rv = callback1.WaitForResult(); 1215 EXPECT_EQ(OK, rv); 1216 1217 const HttpResponseInfo* response = trans->GetResponseInfo(); 1218 EXPECT_FALSE(response == NULL); 1219 1220 // The password prompt info should have been set in response->auth_challenge. 1221 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1222 1223 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 1224 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1225 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1226 1227 TestCompletionCallback callback2; 1228 1229 rv = trans->RestartWithAuth(kFoo, kBar, &callback2); 1230 EXPECT_EQ(ERR_IO_PENDING, rv); 1231 1232 rv = callback2.WaitForResult(); 1233 EXPECT_EQ(OK, rv); 1234 1235 response = trans->GetResponseInfo(); 1236 ASSERT_FALSE(response == NULL); 1237 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1238 EXPECT_EQ(5, response->headers->GetContentLength()); 1239 } 1240 1241 // Test the request-challenge-retry sequence for basic auth, over a keep-alive 1242 // connection and with no response body to drain. 1243 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) { 1244 HttpRequestInfo request; 1245 request.method = "GET"; 1246 request.url = GURL("http://www.google.com/"); 1247 request.load_flags = 0; 1248 1249 SessionDependencies session_deps; 1250 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1251 1252 MockWrite data_writes1[] = { 1253 MockWrite("GET / HTTP/1.1\r\n" 1254 "Host: www.google.com\r\n" 1255 "Connection: keep-alive\r\n\r\n"), 1256 1257 // After calling trans->RestartWithAuth(), this is the request we should 1258 // be issuing -- the final header line contains the credentials. 1259 MockWrite("GET / HTTP/1.1\r\n" 1260 "Host: www.google.com\r\n" 1261 "Connection: keep-alive\r\n" 1262 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 1263 }; 1264 1265 MockRead data_reads1[] = { 1266 MockRead("HTTP/1.1 401 Unauthorized\r\n"), 1267 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1268 MockRead("Content-Length: 0\r\n\r\n"), // No response body. 1269 1270 // Lastly, the server responds with the actual content. 1271 MockRead("HTTP/1.1 200 OK\r\n"), 1272 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1273 MockRead("Content-Length: 5\r\n\r\n"), 1274 MockRead("hello"), 1275 }; 1276 1277 // An incorrect reconnect would cause this to be read. 1278 MockRead data_reads2[] = { 1279 MockRead(false, ERR_FAILED), 1280 }; 1281 1282 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 1283 data_writes1, arraysize(data_writes1)); 1284 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 1285 NULL, 0); 1286 session_deps.socket_factory.AddSocketDataProvider(&data1); 1287 session_deps.socket_factory.AddSocketDataProvider(&data2); 1288 1289 TestCompletionCallback callback1; 1290 1291 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1292 int rv = trans->Start(&request, &callback1, BoundNetLog()); 1293 EXPECT_EQ(ERR_IO_PENDING, rv); 1294 1295 rv = callback1.WaitForResult(); 1296 EXPECT_EQ(OK, rv); 1297 1298 const HttpResponseInfo* response = trans->GetResponseInfo(); 1299 EXPECT_FALSE(response == NULL); 1300 1301 // The password prompt info should have been set in response->auth_challenge. 1302 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1303 1304 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 1305 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1306 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1307 1308 TestCompletionCallback callback2; 1309 1310 rv = trans->RestartWithAuth(kFoo, kBar, &callback2); 1311 EXPECT_EQ(ERR_IO_PENDING, rv); 1312 1313 rv = callback2.WaitForResult(); 1314 EXPECT_EQ(OK, rv); 1315 1316 response = trans->GetResponseInfo(); 1317 ASSERT_FALSE(response == NULL); 1318 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1319 EXPECT_EQ(5, response->headers->GetContentLength()); 1320 } 1321 1322 // Test the request-challenge-retry sequence for basic auth, over a keep-alive 1323 // connection and with a large response body to drain. 1324 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) { 1325 HttpRequestInfo request; 1326 request.method = "GET"; 1327 request.url = GURL("http://www.google.com/"); 1328 request.load_flags = 0; 1329 1330 SessionDependencies session_deps; 1331 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1332 1333 MockWrite data_writes1[] = { 1334 MockWrite("GET / HTTP/1.1\r\n" 1335 "Host: www.google.com\r\n" 1336 "Connection: keep-alive\r\n\r\n"), 1337 1338 // After calling trans->RestartWithAuth(), this is the request we should 1339 // be issuing -- the final header line contains the credentials. 1340 MockWrite("GET / HTTP/1.1\r\n" 1341 "Host: www.google.com\r\n" 1342 "Connection: keep-alive\r\n" 1343 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 1344 }; 1345 1346 // Respond with 5 kb of response body. 1347 std::string large_body_string("Unauthorized"); 1348 large_body_string.append(5 * 1024, ' '); 1349 large_body_string.append("\r\n"); 1350 1351 MockRead data_reads1[] = { 1352 MockRead("HTTP/1.1 401 Unauthorized\r\n"), 1353 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1354 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1355 // 5134 = 12 + 5 * 1024 + 2 1356 MockRead("Content-Length: 5134\r\n\r\n"), 1357 MockRead(true, large_body_string.data(), large_body_string.size()), 1358 1359 // Lastly, the server responds with the actual content. 1360 MockRead("HTTP/1.1 200 OK\r\n"), 1361 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1362 MockRead("Content-Length: 5\r\n\r\n"), 1363 MockRead("hello"), 1364 }; 1365 1366 // An incorrect reconnect would cause this to be read. 1367 MockRead data_reads2[] = { 1368 MockRead(false, ERR_FAILED), 1369 }; 1370 1371 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 1372 data_writes1, arraysize(data_writes1)); 1373 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 1374 NULL, 0); 1375 session_deps.socket_factory.AddSocketDataProvider(&data1); 1376 session_deps.socket_factory.AddSocketDataProvider(&data2); 1377 1378 TestCompletionCallback callback1; 1379 1380 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1381 int rv = trans->Start(&request, &callback1, BoundNetLog()); 1382 EXPECT_EQ(ERR_IO_PENDING, rv); 1383 1384 rv = callback1.WaitForResult(); 1385 EXPECT_EQ(OK, rv); 1386 1387 const HttpResponseInfo* response = trans->GetResponseInfo(); 1388 EXPECT_FALSE(response == NULL); 1389 1390 // The password prompt info should have been set in response->auth_challenge. 1391 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1392 1393 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 1394 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1395 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1396 1397 TestCompletionCallback callback2; 1398 1399 rv = trans->RestartWithAuth(kFoo, kBar, &callback2); 1400 EXPECT_EQ(ERR_IO_PENDING, rv); 1401 1402 rv = callback2.WaitForResult(); 1403 EXPECT_EQ(OK, rv); 1404 1405 response = trans->GetResponseInfo(); 1406 ASSERT_FALSE(response == NULL); 1407 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1408 EXPECT_EQ(5, response->headers->GetContentLength()); 1409 } 1410 1411 // Test the request-challenge-retry sequence for basic auth, over a keep-alive 1412 // connection, but the server gets impatient and closes the connection. 1413 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) { 1414 HttpRequestInfo request; 1415 request.method = "GET"; 1416 request.url = GURL("http://www.google.com/"); 1417 request.load_flags = 0; 1418 1419 SessionDependencies session_deps; 1420 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1421 1422 MockWrite data_writes1[] = { 1423 MockWrite("GET / HTTP/1.1\r\n" 1424 "Host: www.google.com\r\n" 1425 "Connection: keep-alive\r\n\r\n"), 1426 // This simulates the seemingly successful write to a closed connection 1427 // if the bug is not fixed. 1428 MockWrite("GET / HTTP/1.1\r\n" 1429 "Host: www.google.com\r\n" 1430 "Connection: keep-alive\r\n" 1431 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 1432 }; 1433 1434 MockRead data_reads1[] = { 1435 MockRead("HTTP/1.1 401 Unauthorized\r\n"), 1436 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1437 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1438 MockRead("Content-Length: 14\r\n\r\n"), 1439 // Tell MockTCPClientSocket to simulate the server closing the connection. 1440 MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), 1441 MockRead("Unauthorized\r\n"), 1442 MockRead(false, OK), // The server closes the connection. 1443 }; 1444 1445 // After calling trans->RestartWithAuth(), this is the request we should 1446 // be issuing -- the final header line contains the credentials. 1447 MockWrite data_writes2[] = { 1448 MockWrite("GET / HTTP/1.1\r\n" 1449 "Host: www.google.com\r\n" 1450 "Connection: keep-alive\r\n" 1451 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 1452 }; 1453 1454 // Lastly, the server responds with the actual content. 1455 MockRead data_reads2[] = { 1456 MockRead("HTTP/1.1 200 OK\r\n"), 1457 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1458 MockRead("Content-Length: 5\r\n\r\n"), 1459 MockRead("hello"), 1460 }; 1461 1462 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 1463 data_writes1, arraysize(data_writes1)); 1464 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 1465 data_writes2, arraysize(data_writes2)); 1466 session_deps.socket_factory.AddSocketDataProvider(&data1); 1467 session_deps.socket_factory.AddSocketDataProvider(&data2); 1468 1469 TestCompletionCallback callback1; 1470 1471 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1472 int rv = trans->Start(&request, &callback1, BoundNetLog()); 1473 EXPECT_EQ(ERR_IO_PENDING, rv); 1474 1475 rv = callback1.WaitForResult(); 1476 EXPECT_EQ(OK, rv); 1477 1478 const HttpResponseInfo* response = trans->GetResponseInfo(); 1479 EXPECT_FALSE(response == NULL); 1480 1481 // The password prompt info should have been set in response->auth_challenge. 1482 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1483 1484 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 1485 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1486 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1487 1488 TestCompletionCallback callback2; 1489 1490 rv = trans->RestartWithAuth(kFoo, kBar, &callback2); 1491 EXPECT_EQ(ERR_IO_PENDING, rv); 1492 1493 rv = callback2.WaitForResult(); 1494 EXPECT_EQ(OK, rv); 1495 1496 response = trans->GetResponseInfo(); 1497 ASSERT_FALSE(response == NULL); 1498 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1499 EXPECT_EQ(5, response->headers->GetContentLength()); 1500 } 1501 1502 // Test the request-challenge-retry sequence for basic auth, over a connection 1503 // that requires a restart when setting up an SSL tunnel. 1504 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) { 1505 HttpRequestInfo request; 1506 request.method = "GET"; 1507 request.url = GURL("https://www.google.com/"); 1508 // when the no authentication data flag is set. 1509 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; 1510 1511 // Configure against proxy server "myproxy:70". 1512 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); 1513 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 1514 session_deps.net_log = log.bound().net_log(); 1515 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1516 1517 // Since we have proxy, should try to establish tunnel. 1518 MockWrite data_writes1[] = { 1519 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 1520 "Host: www.google.com\r\n" 1521 "Proxy-Connection: keep-alive\r\n\r\n"), 1522 1523 // After calling trans->RestartWithAuth(), this is the request we should 1524 // be issuing -- the final header line contains the credentials. 1525 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 1526 "Host: www.google.com\r\n" 1527 "Proxy-Connection: keep-alive\r\n" 1528 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 1529 1530 MockWrite("GET / HTTP/1.1\r\n" 1531 "Host: www.google.com\r\n" 1532 "Connection: keep-alive\r\n\r\n"), 1533 }; 1534 1535 // The proxy responds to the connect with a 407, using a persistent 1536 // connection. 1537 MockRead data_reads1[] = { 1538 // No credentials. 1539 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), 1540 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1541 MockRead("Proxy-Connection: close\r\n\r\n"), 1542 1543 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), 1544 1545 MockRead("HTTP/1.1 200 OK\r\n"), 1546 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1547 MockRead("Content-Length: 5\r\n\r\n"), 1548 MockRead(false, "hello"), 1549 }; 1550 1551 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 1552 data_writes1, arraysize(data_writes1)); 1553 session_deps.socket_factory.AddSocketDataProvider(&data1); 1554 SSLSocketDataProvider ssl(true, OK); 1555 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 1556 1557 TestCompletionCallback callback1; 1558 1559 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1560 1561 int rv = trans->Start(&request, &callback1, log.bound()); 1562 EXPECT_EQ(ERR_IO_PENDING, rv); 1563 1564 rv = callback1.WaitForResult(); 1565 EXPECT_EQ(OK, rv); 1566 net::CapturingNetLog::EntryList entries; 1567 log.GetEntries(&entries); 1568 size_t pos = ExpectLogContainsSomewhere( 1569 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, 1570 NetLog::PHASE_NONE); 1571 ExpectLogContainsSomewhere( 1572 entries, pos, 1573 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, 1574 NetLog::PHASE_NONE); 1575 1576 const HttpResponseInfo* response = trans->GetResponseInfo(); 1577 ASSERT_FALSE(response == NULL); 1578 1579 EXPECT_EQ(407, response->headers->response_code()); 1580 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 1581 1582 // The password prompt info should have been set in response->auth_challenge. 1583 ASSERT_FALSE(response->auth_challenge.get() == NULL); 1584 1585 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port); 1586 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1587 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1588 1589 TestCompletionCallback callback2; 1590 1591 rv = trans->RestartWithAuth(kFoo, kBar, &callback2); 1592 EXPECT_EQ(ERR_IO_PENDING, rv); 1593 1594 rv = callback2.WaitForResult(); 1595 EXPECT_EQ(OK, rv); 1596 1597 response = trans->GetResponseInfo(); 1598 ASSERT_FALSE(response == NULL); 1599 1600 EXPECT_TRUE(response->headers->IsKeepAlive()); 1601 EXPECT_EQ(200, response->headers->response_code()); 1602 EXPECT_EQ(5, response->headers->GetContentLength()); 1603 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 1604 1605 // The password prompt info should not be set. 1606 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1607 1608 trans.reset(); 1609 session->CloseAllConnections(); 1610 } 1611 1612 // Test the request-challenge-retry sequence for basic auth, over a keep-alive 1613 // proxy connection, when setting up an SSL tunnel. 1614 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) { 1615 HttpRequestInfo request; 1616 request.method = "GET"; 1617 request.url = GURL("https://www.google.com/"); 1618 // Ensure that proxy authentication is attempted even 1619 // when the no authentication data flag is set. 1620 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; 1621 1622 // Configure against proxy server "myproxy:70". 1623 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); 1624 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 1625 session_deps.net_log = log.bound().net_log(); 1626 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1627 1628 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1629 1630 // Since we have proxy, should try to establish tunnel. 1631 MockWrite data_writes1[] = { 1632 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 1633 "Host: www.google.com\r\n" 1634 "Proxy-Connection: keep-alive\r\n\r\n"), 1635 1636 // After calling trans->RestartWithAuth(), this is the request we should 1637 // be issuing -- the final header line contains the credentials. 1638 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 1639 "Host: www.google.com\r\n" 1640 "Proxy-Connection: keep-alive\r\n" 1641 "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), 1642 }; 1643 1644 // The proxy responds to the connect with a 407, using a persistent 1645 // connection. 1646 MockRead data_reads1[] = { 1647 // No credentials. 1648 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), 1649 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1650 MockRead("Content-Length: 10\r\n\r\n"), 1651 MockRead("0123456789"), 1652 1653 // Wrong credentials (wrong password). 1654 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), 1655 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1656 MockRead("Content-Length: 10\r\n\r\n"), 1657 // No response body because the test stops reading here. 1658 MockRead(false, ERR_UNEXPECTED), // Should not be reached. 1659 }; 1660 1661 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 1662 data_writes1, arraysize(data_writes1)); 1663 session_deps.socket_factory.AddSocketDataProvider(&data1); 1664 1665 TestCompletionCallback callback1; 1666 1667 int rv = trans->Start(&request, &callback1, log.bound()); 1668 EXPECT_EQ(ERR_IO_PENDING, rv); 1669 1670 rv = callback1.WaitForResult(); 1671 EXPECT_EQ(OK, rv); 1672 net::CapturingNetLog::EntryList entries; 1673 log.GetEntries(&entries); 1674 size_t pos = ExpectLogContainsSomewhere( 1675 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, 1676 NetLog::PHASE_NONE); 1677 ExpectLogContainsSomewhere( 1678 entries, pos, 1679 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, 1680 NetLog::PHASE_NONE); 1681 1682 const HttpResponseInfo* response = trans->GetResponseInfo(); 1683 EXPECT_FALSE(response == NULL); 1684 1685 EXPECT_TRUE(response->headers->IsKeepAlive()); 1686 EXPECT_EQ(407, response->headers->response_code()); 1687 EXPECT_EQ(10, response->headers->GetContentLength()); 1688 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 1689 1690 // The password prompt info should have been set in response->auth_challenge. 1691 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1692 1693 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port); 1694 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1695 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1696 1697 TestCompletionCallback callback2; 1698 1699 // Wrong password (should be "bar"). 1700 rv = trans->RestartWithAuth(kFoo, kBaz, &callback2); 1701 EXPECT_EQ(ERR_IO_PENDING, rv); 1702 1703 rv = callback2.WaitForResult(); 1704 EXPECT_EQ(OK, rv); 1705 1706 response = trans->GetResponseInfo(); 1707 EXPECT_FALSE(response == NULL); 1708 1709 EXPECT_TRUE(response->headers->IsKeepAlive()); 1710 EXPECT_EQ(407, response->headers->response_code()); 1711 EXPECT_EQ(10, response->headers->GetContentLength()); 1712 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 1713 1714 // The password prompt info should have been set in response->auth_challenge. 1715 EXPECT_FALSE(response->auth_challenge.get() == NULL); 1716 1717 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port); 1718 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 1719 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 1720 1721 // Flush the idle socket before the NetLog and HttpNetworkTransaction go 1722 // out of scope. 1723 session->CloseAllConnections(); 1724 } 1725 1726 // Test that we don't read the response body when we fail to establish a tunnel, 1727 // even if the user cancels the proxy's auth attempt. 1728 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) { 1729 HttpRequestInfo request; 1730 request.method = "GET"; 1731 request.url = GURL("https://www.google.com/"); 1732 request.load_flags = 0; 1733 1734 // Configure against proxy server "myproxy:70". 1735 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); 1736 1737 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1738 1739 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1740 1741 // Since we have proxy, should try to establish tunnel. 1742 MockWrite data_writes[] = { 1743 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 1744 "Host: www.google.com\r\n" 1745 "Proxy-Connection: keep-alive\r\n\r\n"), 1746 }; 1747 1748 // The proxy responds to the connect with a 407. 1749 MockRead data_reads[] = { 1750 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), 1751 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1752 MockRead("Content-Length: 10\r\n\r\n"), 1753 MockRead(false, ERR_UNEXPECTED), // Should not be reached. 1754 }; 1755 1756 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 1757 data_writes, arraysize(data_writes)); 1758 session_deps.socket_factory.AddSocketDataProvider(&data); 1759 1760 TestCompletionCallback callback; 1761 1762 int rv = trans->Start(&request, &callback, BoundNetLog()); 1763 EXPECT_EQ(ERR_IO_PENDING, rv); 1764 1765 rv = callback.WaitForResult(); 1766 EXPECT_EQ(OK, rv); 1767 1768 const HttpResponseInfo* response = trans->GetResponseInfo(); 1769 EXPECT_FALSE(response == NULL); 1770 1771 EXPECT_TRUE(response->headers->IsKeepAlive()); 1772 EXPECT_EQ(407, response->headers->response_code()); 1773 EXPECT_EQ(10, response->headers->GetContentLength()); 1774 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 1775 1776 std::string response_data; 1777 rv = ReadTransaction(trans.get(), &response_data); 1778 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); 1779 1780 // Flush the idle socket before the HttpNetworkTransaction goes out of scope. 1781 session->CloseAllConnections(); 1782 } 1783 1784 // Test when a server (non-proxy) returns a 407 (proxy-authenticate). 1785 // The request should fail with ERR_UNEXPECTED_PROXY_AUTH. 1786 TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) { 1787 HttpRequestInfo request; 1788 request.method = "GET"; 1789 request.url = GURL("http://www.google.com/"); 1790 request.load_flags = 0; 1791 1792 // We are using a DIRECT connection (i.e. no proxy) for this session. 1793 SessionDependencies session_deps; 1794 scoped_ptr<HttpTransaction> trans( 1795 new HttpNetworkTransaction(CreateSession(&session_deps))); 1796 1797 MockWrite data_writes1[] = { 1798 MockWrite("GET / HTTP/1.1\r\n" 1799 "Host: www.google.com\r\n" 1800 "Connection: keep-alive\r\n\r\n"), 1801 }; 1802 1803 MockRead data_reads1[] = { 1804 MockRead("HTTP/1.0 407 Proxy Auth required\r\n"), 1805 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1806 // Large content-length -- won't matter, as connection will be reset. 1807 MockRead("Content-Length: 10000\r\n\r\n"), 1808 MockRead(false, ERR_FAILED), 1809 }; 1810 1811 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 1812 data_writes1, arraysize(data_writes1)); 1813 session_deps.socket_factory.AddSocketDataProvider(&data1); 1814 1815 TestCompletionCallback callback; 1816 1817 int rv = trans->Start(&request, &callback, BoundNetLog()); 1818 EXPECT_EQ(ERR_IO_PENDING, rv); 1819 1820 rv = callback.WaitForResult(); 1821 EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); 1822 } 1823 1824 // Tests when an HTTPS server (non-proxy) returns a 407 (proxy-authentication) 1825 // through a non-authenticating proxy. The request should fail with 1826 // ERR_UNEXPECTED_PROXY_AUTH. 1827 // Note that it is impossible to detect if an HTTP server returns a 407 through 1828 // a non-authenticating proxy - there is nothing to indicate whether the 1829 // response came from the proxy or the server, so it is treated as if the proxy 1830 // issued the challenge. 1831 TEST_F(HttpNetworkTransactionTest, HttpsServerRequestsProxyAuthThroughProxy) { 1832 HttpRequestInfo request; 1833 request.method = "GET"; 1834 request.url = GURL("https://www.google.com/"); 1835 1836 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); 1837 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 1838 session_deps.net_log = log.bound().net_log(); 1839 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1840 1841 // Since we have proxy, should try to establish tunnel. 1842 MockWrite data_writes1[] = { 1843 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 1844 "Host: www.google.com\r\n" 1845 "Proxy-Connection: keep-alive\r\n\r\n"), 1846 1847 MockWrite("GET / HTTP/1.1\r\n" 1848 "Host: www.google.com\r\n" 1849 "Connection: keep-alive\r\n\r\n"), 1850 }; 1851 1852 MockRead data_reads1[] = { 1853 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), 1854 1855 MockRead("HTTP/1.1 407 Unauthorized\r\n"), 1856 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 1857 MockRead("\r\n"), 1858 MockRead(false, OK), 1859 }; 1860 1861 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 1862 data_writes1, arraysize(data_writes1)); 1863 session_deps.socket_factory.AddSocketDataProvider(&data1); 1864 SSLSocketDataProvider ssl(true, OK); 1865 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 1866 1867 TestCompletionCallback callback1; 1868 1869 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1870 1871 int rv = trans->Start(&request, &callback1, log.bound()); 1872 EXPECT_EQ(ERR_IO_PENDING, rv); 1873 1874 rv = callback1.WaitForResult(); 1875 EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); 1876 net::CapturingNetLog::EntryList entries; 1877 log.GetEntries(&entries); 1878 size_t pos = ExpectLogContainsSomewhere( 1879 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, 1880 NetLog::PHASE_NONE); 1881 ExpectLogContainsSomewhere( 1882 entries, pos, 1883 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, 1884 NetLog::PHASE_NONE); 1885 } 1886 1887 // Test a simple get through an HTTPS Proxy. 1888 TEST_F(HttpNetworkTransactionTest, HttpsProxyGet) { 1889 HttpRequestInfo request; 1890 request.method = "GET"; 1891 request.url = GURL("http://www.google.com/"); 1892 1893 // Configure against https proxy server "proxy:70". 1894 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70")); 1895 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 1896 session_deps.net_log = log.bound().net_log(); 1897 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1898 1899 // Since we have proxy, should use full url 1900 MockWrite data_writes1[] = { 1901 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 1902 "Host: www.google.com\r\n" 1903 "Proxy-Connection: keep-alive\r\n\r\n"), 1904 }; 1905 1906 MockRead data_reads1[] = { 1907 MockRead("HTTP/1.1 200 OK\r\n"), 1908 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 1909 MockRead("Content-Length: 100\r\n\r\n"), 1910 MockRead(false, OK), 1911 }; 1912 1913 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 1914 data_writes1, arraysize(data_writes1)); 1915 session_deps.socket_factory.AddSocketDataProvider(&data1); 1916 SSLSocketDataProvider ssl(true, OK); 1917 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 1918 1919 TestCompletionCallback callback1; 1920 1921 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1922 1923 int rv = trans->Start(&request, &callback1, log.bound()); 1924 EXPECT_EQ(ERR_IO_PENDING, rv); 1925 1926 rv = callback1.WaitForResult(); 1927 EXPECT_EQ(OK, rv); 1928 1929 const HttpResponseInfo* response = trans->GetResponseInfo(); 1930 ASSERT_FALSE(response == NULL); 1931 1932 EXPECT_TRUE(response->headers->IsKeepAlive()); 1933 EXPECT_EQ(200, response->headers->response_code()); 1934 EXPECT_EQ(100, response->headers->GetContentLength()); 1935 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 1936 1937 // The password prompt info should not be set. 1938 EXPECT_TRUE(response->auth_challenge.get() == NULL); 1939 } 1940 1941 // Test a SPDY get through an HTTPS Proxy. 1942 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGet) { 1943 HttpRequestInfo request; 1944 request.method = "GET"; 1945 request.url = GURL("http://www.google.com/"); 1946 request.load_flags = 0; 1947 1948 // Configure against https proxy server "proxy:70". 1949 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70")); 1950 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 1951 session_deps.net_log = log.bound().net_log(); 1952 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 1953 1954 // fetch http://www.google.com/ via SPDY 1955 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST, 1956 false)); 1957 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; 1958 1959 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); 1960 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); 1961 MockRead spdy_reads[] = { 1962 CreateMockRead(*resp), 1963 CreateMockRead(*data), 1964 MockRead(true, 0, 0), 1965 }; 1966 1967 scoped_refptr<DelayedSocketData> spdy_data( 1968 new DelayedSocketData( 1969 1, // wait for one write to finish before reading. 1970 spdy_reads, arraysize(spdy_reads), 1971 spdy_writes, arraysize(spdy_writes))); 1972 session_deps.socket_factory.AddSocketDataProvider(spdy_data); 1973 1974 SSLSocketDataProvider ssl(true, OK); 1975 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; 1976 ssl.next_proto = "spdy/2"; 1977 ssl.was_npn_negotiated = true; 1978 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 1979 1980 TestCompletionCallback callback1; 1981 1982 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 1983 1984 int rv = trans->Start(&request, &callback1, log.bound()); 1985 EXPECT_EQ(ERR_IO_PENDING, rv); 1986 1987 rv = callback1.WaitForResult(); 1988 EXPECT_EQ(OK, rv); 1989 1990 const HttpResponseInfo* response = trans->GetResponseInfo(); 1991 ASSERT_TRUE(response != NULL); 1992 ASSERT_TRUE(response->headers != NULL); 1993 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 1994 1995 std::string response_data; 1996 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); 1997 EXPECT_EQ(net::kUploadData, response_data); 1998 } 1999 2000 // Test a SPDY get through an HTTPS Proxy. 2001 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) { 2002 HttpRequestInfo request; 2003 request.method = "GET"; 2004 request.url = GURL("http://www.google.com/"); 2005 request.load_flags = 0; 2006 2007 // Configure against https proxy server "proxy:70". 2008 SessionDependencies session_deps( 2009 ProxyService::CreateFixed("https://proxy:70")); 2010 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 2011 session_deps.net_log = log.bound().net_log(); 2012 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 2013 2014 // The first request will be a bare GET, the second request will be a 2015 // GET with a Proxy-Authorization header. 2016 scoped_ptr<spdy::SpdyFrame> req_get( 2017 ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false)); 2018 const char* const kExtraAuthorizationHeaders[] = { 2019 "proxy-authorization", 2020 "Basic Zm9vOmJhcg==", 2021 }; 2022 scoped_ptr<spdy::SpdyFrame> req_get_authorization( 2023 ConstructSpdyGet( 2024 kExtraAuthorizationHeaders, arraysize(kExtraAuthorizationHeaders)/2, 2025 false, 3, LOWEST, false)); 2026 MockWrite spdy_writes[] = { 2027 CreateMockWrite(*req_get, 1), 2028 CreateMockWrite(*req_get_authorization, 4), 2029 }; 2030 2031 // The first response is a 407 proxy authentication challenge, and the second 2032 // response will be a 200 response since the second request includes a valid 2033 // Authorization header. 2034 const char* const kExtraAuthenticationHeaders[] = { 2035 "Proxy-Authenticate", 2036 "Basic realm=\"MyRealm1\"" 2037 }; 2038 scoped_ptr<spdy::SpdyFrame> resp_authentication( 2039 ConstructSpdySynReplyError( 2040 "407 Proxy Authentication Required", 2041 kExtraAuthenticationHeaders, arraysize(kExtraAuthenticationHeaders)/2, 2042 1)); 2043 scoped_ptr<spdy::SpdyFrame> body_authentication( 2044 ConstructSpdyBodyFrame(1, true)); 2045 scoped_ptr<spdy::SpdyFrame> resp_data(ConstructSpdyGetSynReply(NULL, 0, 3)); 2046 scoped_ptr<spdy::SpdyFrame> body_data(ConstructSpdyBodyFrame(3, true)); 2047 MockRead spdy_reads[] = { 2048 CreateMockRead(*resp_authentication, 2), 2049 CreateMockRead(*body_authentication, 3), 2050 CreateMockRead(*resp_data, 5), 2051 CreateMockRead(*body_data, 6), 2052 MockRead(true, 0, 7), 2053 }; 2054 2055 scoped_refptr<OrderedSocketData> data( 2056 new OrderedSocketData(spdy_reads, arraysize(spdy_reads), 2057 spdy_writes, arraysize(spdy_writes))); 2058 session_deps.socket_factory.AddSocketDataProvider(data); 2059 2060 SSLSocketDataProvider ssl(true, OK); 2061 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; 2062 ssl.next_proto = "spdy/2"; 2063 ssl.was_npn_negotiated = true; 2064 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 2065 2066 TestCompletionCallback callback1; 2067 2068 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2069 2070 int rv = trans->Start(&request, &callback1, log.bound()); 2071 EXPECT_EQ(ERR_IO_PENDING, rv); 2072 2073 rv = callback1.WaitForResult(); 2074 EXPECT_EQ(OK, rv); 2075 2076 const HttpResponseInfo* const response = trans->GetResponseInfo(); 2077 2078 ASSERT_TRUE(response != NULL); 2079 ASSERT_TRUE(response->headers != NULL); 2080 EXPECT_EQ(407, response->headers->response_code()); 2081 EXPECT_TRUE(response->was_fetched_via_spdy); 2082 2083 // The password prompt info should have been set in response->auth_challenge. 2084 ASSERT_TRUE(response->auth_challenge.get() != NULL); 2085 EXPECT_TRUE(response->auth_challenge->is_proxy); 2086 EXPECT_EQ(L"proxy:70", response->auth_challenge->host_and_port); 2087 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 2088 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 2089 2090 TestCompletionCallback callback2; 2091 2092 rv = trans->RestartWithAuth(kFoo, kBar, &callback2); 2093 EXPECT_EQ(ERR_IO_PENDING, rv); 2094 2095 rv = callback2.WaitForResult(); 2096 EXPECT_EQ(OK, rv); 2097 2098 const HttpResponseInfo* const response_restart = trans->GetResponseInfo(); 2099 2100 ASSERT_TRUE(response_restart != NULL); 2101 ASSERT_TRUE(response_restart->headers != NULL); 2102 EXPECT_EQ(200, response_restart->headers->response_code()); 2103 // The password prompt info should not be set. 2104 EXPECT_TRUE(response_restart->auth_challenge.get() == NULL); 2105 } 2106 2107 // Test a SPDY CONNECT through an HTTPS Proxy to an HTTPS (non-SPDY) Server. 2108 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) { 2109 HttpRequestInfo request; 2110 request.method = "GET"; 2111 request.url = GURL("https://www.google.com/"); 2112 request.load_flags = 0; 2113 2114 // Configure against https proxy server "proxy:70". 2115 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70")); 2116 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 2117 session_deps.net_log = log.bound().net_log(); 2118 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 2119 2120 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2121 2122 // CONNECT to www.google.com:443 via SPDY 2123 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); 2124 // fetch https://www.google.com/ via HTTP 2125 2126 const char get[] = "GET / HTTP/1.1\r\n" 2127 "Host: www.google.com\r\n" 2128 "Connection: keep-alive\r\n\r\n"; 2129 scoped_ptr<spdy::SpdyFrame> wrapped_get( 2130 ConstructSpdyBodyFrame(1, get, strlen(get), false)); 2131 MockWrite spdy_writes[] = { 2132 CreateMockWrite(*connect, 1), 2133 CreateMockWrite(*wrapped_get, 3) 2134 }; 2135 2136 scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); 2137 const char resp[] = "HTTP/1.1 200 OK\r\n" 2138 "Content-Length: 10\r\n\r\n"; 2139 2140 scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( 2141 ConstructSpdyBodyFrame(1, resp, strlen(resp), false)); 2142 scoped_ptr<spdy::SpdyFrame> wrapped_body( 2143 ConstructSpdyBodyFrame(1, "1234567890", 10, false)); 2144 MockRead spdy_reads[] = { 2145 CreateMockRead(*conn_resp, 2, true), 2146 CreateMockRead(*wrapped_get_resp, 4, true), 2147 CreateMockRead(*wrapped_body, 5, true), 2148 CreateMockRead(*wrapped_body, 6, true), 2149 MockRead(true, 0, 7), 2150 }; 2151 2152 scoped_refptr<OrderedSocketData> spdy_data( 2153 new OrderedSocketData( 2154 spdy_reads, arraysize(spdy_reads), 2155 spdy_writes, arraysize(spdy_writes))); 2156 session_deps.socket_factory.AddSocketDataProvider(spdy_data); 2157 2158 SSLSocketDataProvider ssl(true, OK); 2159 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; 2160 ssl.next_proto = "spdy/2"; 2161 ssl.was_npn_negotiated = true; 2162 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 2163 SSLSocketDataProvider ssl2(true, OK); 2164 ssl2.was_npn_negotiated = false; 2165 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); 2166 2167 TestCompletionCallback callback1; 2168 2169 int rv = trans->Start(&request, &callback1, log.bound()); 2170 EXPECT_EQ(ERR_IO_PENDING, rv); 2171 2172 rv = callback1.WaitForResult(); 2173 EXPECT_EQ(OK, rv); 2174 2175 const HttpResponseInfo* response = trans->GetResponseInfo(); 2176 ASSERT_TRUE(response != NULL); 2177 ASSERT_TRUE(response->headers != NULL); 2178 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 2179 2180 std::string response_data; 2181 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); 2182 EXPECT_EQ("1234567890", response_data); 2183 } 2184 2185 // Test a SPDY CONNECT through an HTTPS Proxy to a SPDY server. 2186 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) { 2187 HttpRequestInfo request; 2188 request.method = "GET"; 2189 request.url = GURL("https://www.google.com/"); 2190 request.load_flags = 0; 2191 2192 // Configure against https proxy server "proxy:70". 2193 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70")); 2194 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 2195 session_deps.net_log = log.bound().net_log(); 2196 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 2197 2198 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2199 2200 // CONNECT to www.google.com:443 via SPDY 2201 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); 2202 // fetch https://www.google.com/ via SPDY 2203 const char* const kMyUrl = "https://www.google.com/"; 2204 scoped_ptr<spdy::SpdyFrame> get(ConstructSpdyGet(kMyUrl, false, 1, LOWEST)); 2205 scoped_ptr<spdy::SpdyFrame> wrapped_get(ConstructWrappedSpdyFrame(get, 1)); 2206 MockWrite spdy_writes[] = { 2207 CreateMockWrite(*connect, 1), 2208 CreateMockWrite(*wrapped_get, 3) 2209 }; 2210 2211 scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); 2212 scoped_ptr<spdy::SpdyFrame> get_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); 2213 scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( 2214 ConstructWrappedSpdyFrame(get_resp, 1)); 2215 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); 2216 scoped_ptr<spdy::SpdyFrame> wrapped_body(ConstructWrappedSpdyFrame(body, 1)); 2217 MockRead spdy_reads[] = { 2218 CreateMockRead(*conn_resp, 2, true), 2219 CreateMockRead(*wrapped_get_resp, 4, true), 2220 CreateMockRead(*wrapped_body, 5, true), 2221 MockRead(true, 0, 1), 2222 }; 2223 2224 scoped_refptr<OrderedSocketData> spdy_data( 2225 new OrderedSocketData( 2226 spdy_reads, arraysize(spdy_reads), 2227 spdy_writes, arraysize(spdy_writes))); 2228 session_deps.socket_factory.AddSocketDataProvider(spdy_data); 2229 2230 SSLSocketDataProvider ssl(true, OK); 2231 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; 2232 ssl.next_proto = "spdy/2"; 2233 ssl.was_npn_negotiated = true; 2234 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 2235 SSLSocketDataProvider ssl2(true, OK); 2236 ssl2.next_proto_status = SSLClientSocket::kNextProtoNegotiated; 2237 ssl2.next_proto = "spdy/2"; 2238 ssl2.was_npn_negotiated = true; 2239 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); 2240 2241 TestCompletionCallback callback1; 2242 2243 int rv = trans->Start(&request, &callback1, log.bound()); 2244 EXPECT_EQ(ERR_IO_PENDING, rv); 2245 2246 rv = callback1.WaitForResult(); 2247 EXPECT_EQ(OK, rv); 2248 2249 const HttpResponseInfo* response = trans->GetResponseInfo(); 2250 ASSERT_TRUE(response != NULL); 2251 ASSERT_TRUE(response->headers != NULL); 2252 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 2253 2254 std::string response_data; 2255 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); 2256 EXPECT_EQ(net::kUploadData, response_data); 2257 } 2258 2259 // Test a SPDY CONNECT failure through an HTTPS Proxy. 2260 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) { 2261 HttpRequestInfo request; 2262 request.method = "GET"; 2263 request.url = GURL("https://www.google.com/"); 2264 request.load_flags = 0; 2265 2266 // Configure against https proxy server "proxy:70". 2267 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70")); 2268 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 2269 session_deps.net_log = log.bound().net_log(); 2270 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 2271 2272 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2273 2274 // CONNECT to www.google.com:443 via SPDY 2275 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); 2276 scoped_ptr<spdy::SpdyFrame> get(ConstructSpdyRstStream(1, spdy::CANCEL)); 2277 2278 MockWrite spdy_writes[] = { 2279 CreateMockWrite(*connect, 1), 2280 CreateMockWrite(*get, 3), 2281 }; 2282 2283 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdySynReplyError(1)); 2284 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); 2285 MockRead spdy_reads[] = { 2286 CreateMockRead(*resp, 2, true), 2287 MockRead(true, 0, 4), 2288 }; 2289 2290 scoped_refptr<OrderedSocketData> spdy_data( 2291 new OrderedSocketData( 2292 spdy_reads, arraysize(spdy_reads), 2293 spdy_writes, arraysize(spdy_writes))); 2294 session_deps.socket_factory.AddSocketDataProvider(spdy_data); 2295 2296 SSLSocketDataProvider ssl(true, OK); 2297 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; 2298 ssl.next_proto = "spdy/2"; 2299 ssl.was_npn_negotiated = true; 2300 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 2301 SSLSocketDataProvider ssl2(true, OK); 2302 ssl2.next_proto_status = SSLClientSocket::kNextProtoNegotiated; 2303 ssl2.next_proto = "spdy/2"; 2304 ssl2.was_npn_negotiated = true; 2305 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); 2306 2307 TestCompletionCallback callback1; 2308 2309 int rv = trans->Start(&request, &callback1, log.bound()); 2310 EXPECT_EQ(ERR_IO_PENDING, rv); 2311 2312 rv = callback1.WaitForResult(); 2313 EXPECT_EQ(OK, rv); 2314 2315 const HttpResponseInfo* response = trans->GetResponseInfo(); 2316 ASSERT_FALSE(response == NULL); 2317 EXPECT_EQ(500, response->headers->response_code()); 2318 } 2319 2320 // Test the challenge-response-retry sequence through an HTTPS Proxy 2321 TEST_F(HttpNetworkTransactionTest, HttpsProxyAuthRetry) { 2322 HttpRequestInfo request; 2323 request.method = "GET"; 2324 request.url = GURL("http://www.google.com/"); 2325 // when the no authentication data flag is set. 2326 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; 2327 2328 // Configure against https proxy server "proxy:70". 2329 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70")); 2330 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); 2331 session_deps.net_log = log.bound().net_log(); 2332 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 2333 2334 // Since we have proxy, should use full url 2335 MockWrite data_writes1[] = { 2336 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 2337 "Host: www.google.com\r\n" 2338 "Proxy-Connection: keep-alive\r\n\r\n"), 2339 2340 // After calling trans->RestartWithAuth(), this is the request we should 2341 // be issuing -- the final header line contains the credentials. 2342 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 2343 "Host: www.google.com\r\n" 2344 "Proxy-Connection: keep-alive\r\n" 2345 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 2346 }; 2347 2348 // The proxy responds to the GET with a 407, using a persistent 2349 // connection. 2350 MockRead data_reads1[] = { 2351 // No credentials. 2352 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), 2353 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 2354 MockRead("Proxy-Connection: keep-alive\r\n"), 2355 MockRead("Content-Length: 0\r\n\r\n"), 2356 2357 MockRead("HTTP/1.1 200 OK\r\n"), 2358 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 2359 MockRead("Content-Length: 100\r\n\r\n"), 2360 MockRead(false, OK), 2361 }; 2362 2363 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 2364 data_writes1, arraysize(data_writes1)); 2365 session_deps.socket_factory.AddSocketDataProvider(&data1); 2366 SSLSocketDataProvider ssl(true, OK); 2367 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 2368 2369 TestCompletionCallback callback1; 2370 2371 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2372 2373 int rv = trans->Start(&request, &callback1, log.bound()); 2374 EXPECT_EQ(ERR_IO_PENDING, rv); 2375 2376 rv = callback1.WaitForResult(); 2377 EXPECT_EQ(OK, rv); 2378 2379 const HttpResponseInfo* response = trans->GetResponseInfo(); 2380 ASSERT_FALSE(response == NULL); 2381 2382 EXPECT_EQ(407, response->headers->response_code()); 2383 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 2384 2385 // The password prompt info should have been set in response->auth_challenge. 2386 ASSERT_FALSE(response->auth_challenge.get() == NULL); 2387 2388 EXPECT_EQ(L"proxy:70", response->auth_challenge->host_and_port); 2389 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 2390 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 2391 2392 TestCompletionCallback callback2; 2393 2394 rv = trans->RestartWithAuth(kFoo, kBar, &callback2); 2395 EXPECT_EQ(ERR_IO_PENDING, rv); 2396 2397 rv = callback2.WaitForResult(); 2398 EXPECT_EQ(OK, rv); 2399 2400 response = trans->GetResponseInfo(); 2401 ASSERT_FALSE(response == NULL); 2402 2403 EXPECT_TRUE(response->headers->IsKeepAlive()); 2404 EXPECT_EQ(200, response->headers->response_code()); 2405 EXPECT_EQ(100, response->headers->GetContentLength()); 2406 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 2407 2408 // The password prompt info should not be set. 2409 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2410 } 2411 2412 void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus( 2413 const MockRead& status, int expected_status) { 2414 HttpRequestInfo request; 2415 request.method = "GET"; 2416 request.url = GURL("https://www.google.com/"); 2417 request.load_flags = 0; 2418 2419 // Configure against proxy server "myproxy:70". 2420 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); 2421 2422 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 2423 2424 // Since we have proxy, should try to establish tunnel. 2425 MockWrite data_writes[] = { 2426 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 2427 "Host: www.google.com\r\n" 2428 "Proxy-Connection: keep-alive\r\n\r\n"), 2429 }; 2430 2431 MockRead data_reads[] = { 2432 status, 2433 MockRead("Content-Length: 10\r\n\r\n"), 2434 // No response body because the test stops reading here. 2435 MockRead(false, ERR_UNEXPECTED), // Should not be reached. 2436 }; 2437 2438 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 2439 data_writes, arraysize(data_writes)); 2440 session_deps.socket_factory.AddSocketDataProvider(&data); 2441 2442 TestCompletionCallback callback; 2443 2444 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2445 2446 int rv = trans->Start(&request, &callback, BoundNetLog()); 2447 EXPECT_EQ(ERR_IO_PENDING, rv); 2448 2449 rv = callback.WaitForResult(); 2450 EXPECT_EQ(expected_status, rv); 2451 } 2452 2453 void HttpNetworkTransactionTest::ConnectStatusHelper(const MockRead& status) { 2454 ConnectStatusHelperWithExpectedStatus( 2455 status, ERR_TUNNEL_CONNECTION_FAILED); 2456 } 2457 2458 TEST_F(HttpNetworkTransactionTest, ConnectStatus100) { 2459 ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n")); 2460 } 2461 2462 TEST_F(HttpNetworkTransactionTest, ConnectStatus101) { 2463 ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n")); 2464 } 2465 2466 TEST_F(HttpNetworkTransactionTest, ConnectStatus201) { 2467 ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n")); 2468 } 2469 2470 TEST_F(HttpNetworkTransactionTest, ConnectStatus202) { 2471 ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n")); 2472 } 2473 2474 TEST_F(HttpNetworkTransactionTest, ConnectStatus203) { 2475 ConnectStatusHelper( 2476 MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n")); 2477 } 2478 2479 TEST_F(HttpNetworkTransactionTest, ConnectStatus204) { 2480 ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n")); 2481 } 2482 2483 TEST_F(HttpNetworkTransactionTest, ConnectStatus205) { 2484 ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n")); 2485 } 2486 2487 TEST_F(HttpNetworkTransactionTest, ConnectStatus206) { 2488 ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n")); 2489 } 2490 2491 TEST_F(HttpNetworkTransactionTest, ConnectStatus300) { 2492 ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n")); 2493 } 2494 2495 TEST_F(HttpNetworkTransactionTest, ConnectStatus301) { 2496 ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n")); 2497 } 2498 2499 TEST_F(HttpNetworkTransactionTest, ConnectStatus302) { 2500 ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n")); 2501 } 2502 2503 TEST_F(HttpNetworkTransactionTest, ConnectStatus303) { 2504 ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n")); 2505 } 2506 2507 TEST_F(HttpNetworkTransactionTest, ConnectStatus304) { 2508 ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n")); 2509 } 2510 2511 TEST_F(HttpNetworkTransactionTest, ConnectStatus305) { 2512 ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n")); 2513 } 2514 2515 TEST_F(HttpNetworkTransactionTest, ConnectStatus306) { 2516 ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n")); 2517 } 2518 2519 TEST_F(HttpNetworkTransactionTest, ConnectStatus307) { 2520 ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n")); 2521 } 2522 2523 TEST_F(HttpNetworkTransactionTest, ConnectStatus400) { 2524 ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n")); 2525 } 2526 2527 TEST_F(HttpNetworkTransactionTest, ConnectStatus401) { 2528 ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n")); 2529 } 2530 2531 TEST_F(HttpNetworkTransactionTest, ConnectStatus402) { 2532 ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n")); 2533 } 2534 2535 TEST_F(HttpNetworkTransactionTest, ConnectStatus403) { 2536 ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n")); 2537 } 2538 2539 TEST_F(HttpNetworkTransactionTest, ConnectStatus404) { 2540 ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n")); 2541 } 2542 2543 TEST_F(HttpNetworkTransactionTest, ConnectStatus405) { 2544 ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n")); 2545 } 2546 2547 TEST_F(HttpNetworkTransactionTest, ConnectStatus406) { 2548 ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n")); 2549 } 2550 2551 TEST_F(HttpNetworkTransactionTest, ConnectStatus407) { 2552 ConnectStatusHelperWithExpectedStatus( 2553 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), 2554 ERR_PROXY_AUTH_UNSUPPORTED); 2555 } 2556 2557 TEST_F(HttpNetworkTransactionTest, ConnectStatus408) { 2558 ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n")); 2559 } 2560 2561 TEST_F(HttpNetworkTransactionTest, ConnectStatus409) { 2562 ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n")); 2563 } 2564 2565 TEST_F(HttpNetworkTransactionTest, ConnectStatus410) { 2566 ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n")); 2567 } 2568 2569 TEST_F(HttpNetworkTransactionTest, ConnectStatus411) { 2570 ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n")); 2571 } 2572 2573 TEST_F(HttpNetworkTransactionTest, ConnectStatus412) { 2574 ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n")); 2575 } 2576 2577 TEST_F(HttpNetworkTransactionTest, ConnectStatus413) { 2578 ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n")); 2579 } 2580 2581 TEST_F(HttpNetworkTransactionTest, ConnectStatus414) { 2582 ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n")); 2583 } 2584 2585 TEST_F(HttpNetworkTransactionTest, ConnectStatus415) { 2586 ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n")); 2587 } 2588 2589 TEST_F(HttpNetworkTransactionTest, ConnectStatus416) { 2590 ConnectStatusHelper( 2591 MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n")); 2592 } 2593 2594 TEST_F(HttpNetworkTransactionTest, ConnectStatus417) { 2595 ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n")); 2596 } 2597 2598 TEST_F(HttpNetworkTransactionTest, ConnectStatus500) { 2599 ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n")); 2600 } 2601 2602 TEST_F(HttpNetworkTransactionTest, ConnectStatus501) { 2603 ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n")); 2604 } 2605 2606 TEST_F(HttpNetworkTransactionTest, ConnectStatus502) { 2607 ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n")); 2608 } 2609 2610 TEST_F(HttpNetworkTransactionTest, ConnectStatus503) { 2611 ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n")); 2612 } 2613 2614 TEST_F(HttpNetworkTransactionTest, ConnectStatus504) { 2615 ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n")); 2616 } 2617 2618 TEST_F(HttpNetworkTransactionTest, ConnectStatus505) { 2619 ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n")); 2620 } 2621 2622 // Test the flow when both the proxy server AND origin server require 2623 // authentication. Again, this uses basic auth for both since that is 2624 // the simplest to mock. 2625 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) { 2626 HttpRequestInfo request; 2627 request.method = "GET"; 2628 request.url = GURL("http://www.google.com/"); 2629 request.load_flags = 0; 2630 2631 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); 2632 2633 // Configure against proxy server "myproxy:70". 2634 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction( 2635 CreateSession(&session_deps))); 2636 2637 MockWrite data_writes1[] = { 2638 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 2639 "Host: www.google.com\r\n" 2640 "Proxy-Connection: keep-alive\r\n\r\n"), 2641 }; 2642 2643 MockRead data_reads1[] = { 2644 MockRead("HTTP/1.0 407 Unauthorized\r\n"), 2645 // Give a couple authenticate options (only the middle one is actually 2646 // supported). 2647 MockRead("Proxy-Authenticate: Basic invalid\r\n"), // Malformed. 2648 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 2649 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), 2650 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 2651 // Large content-length -- won't matter, as connection will be reset. 2652 MockRead("Content-Length: 10000\r\n\r\n"), 2653 MockRead(false, ERR_FAILED), 2654 }; 2655 2656 // After calling trans->RestartWithAuth() the first time, this is the 2657 // request we should be issuing -- the final header line contains the 2658 // proxy's credentials. 2659 MockWrite data_writes2[] = { 2660 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 2661 "Host: www.google.com\r\n" 2662 "Proxy-Connection: keep-alive\r\n" 2663 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 2664 }; 2665 2666 // Now the proxy server lets the request pass through to origin server. 2667 // The origin server responds with a 401. 2668 MockRead data_reads2[] = { 2669 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 2670 // Note: We are using the same realm-name as the proxy server. This is 2671 // completely valid, as realms are unique across hosts. 2672 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 2673 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 2674 MockRead("Content-Length: 2000\r\n\r\n"), 2675 MockRead(false, ERR_FAILED), // Won't be reached. 2676 }; 2677 2678 // After calling trans->RestartWithAuth() the second time, we should send 2679 // the credentials for both the proxy and origin server. 2680 MockWrite data_writes3[] = { 2681 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" 2682 "Host: www.google.com\r\n" 2683 "Proxy-Connection: keep-alive\r\n" 2684 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" 2685 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), 2686 }; 2687 2688 // Lastly we get the desired content. 2689 MockRead data_reads3[] = { 2690 MockRead("HTTP/1.0 200 OK\r\n"), 2691 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 2692 MockRead("Content-Length: 100\r\n\r\n"), 2693 MockRead(false, OK), 2694 }; 2695 2696 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 2697 data_writes1, arraysize(data_writes1)); 2698 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 2699 data_writes2, arraysize(data_writes2)); 2700 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), 2701 data_writes3, arraysize(data_writes3)); 2702 session_deps.socket_factory.AddSocketDataProvider(&data1); 2703 session_deps.socket_factory.AddSocketDataProvider(&data2); 2704 session_deps.socket_factory.AddSocketDataProvider(&data3); 2705 2706 TestCompletionCallback callback1; 2707 2708 int rv = trans->Start(&request, &callback1, BoundNetLog()); 2709 EXPECT_EQ(ERR_IO_PENDING, rv); 2710 2711 rv = callback1.WaitForResult(); 2712 EXPECT_EQ(OK, rv); 2713 2714 const HttpResponseInfo* response = trans->GetResponseInfo(); 2715 EXPECT_FALSE(response == NULL); 2716 2717 // The password prompt info should have been set in response->auth_challenge. 2718 EXPECT_FALSE(response->auth_challenge.get() == NULL); 2719 2720 EXPECT_EQ(L"myproxy:70", response->auth_challenge->host_and_port); 2721 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 2722 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 2723 2724 TestCompletionCallback callback2; 2725 2726 rv = trans->RestartWithAuth(kFoo, kBar, &callback2); 2727 EXPECT_EQ(ERR_IO_PENDING, rv); 2728 2729 rv = callback2.WaitForResult(); 2730 EXPECT_EQ(OK, rv); 2731 2732 response = trans->GetResponseInfo(); 2733 EXPECT_FALSE(response == NULL); 2734 EXPECT_FALSE(response->auth_challenge.get() == NULL); 2735 2736 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 2737 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 2738 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 2739 2740 TestCompletionCallback callback3; 2741 2742 rv = trans->RestartWithAuth(kFoo2, kBar2, &callback3); 2743 EXPECT_EQ(ERR_IO_PENDING, rv); 2744 2745 rv = callback3.WaitForResult(); 2746 EXPECT_EQ(OK, rv); 2747 2748 response = trans->GetResponseInfo(); 2749 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2750 EXPECT_EQ(100, response->headers->GetContentLength()); 2751 } 2752 2753 // For the NTLM implementation using SSPI, we skip the NTLM tests since we 2754 // can't hook into its internals to cause it to generate predictable NTLM 2755 // authorization headers. 2756 #if defined(NTLM_PORTABLE) 2757 // The NTLM authentication unit tests were generated by capturing the HTTP 2758 // requests and responses using Fiddler 2 and inspecting the generated random 2759 // bytes in the debugger. 2760 2761 // Enter the correct password and authenticate successfully. 2762 TEST_F(HttpNetworkTransactionTest, NTLMAuth1) { 2763 HttpRequestInfo request; 2764 request.method = "GET"; 2765 request.url = GURL("http://172.22.68.17/kids/login.aspx"); 2766 request.load_flags = 0; 2767 2768 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1, 2769 MockGetHostName); 2770 SessionDependencies session_deps; 2771 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 2772 2773 MockWrite data_writes1[] = { 2774 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 2775 "Host: 172.22.68.17\r\n" 2776 "Connection: keep-alive\r\n\r\n"), 2777 }; 2778 2779 MockRead data_reads1[] = { 2780 MockRead("HTTP/1.1 401 Access Denied\r\n"), 2781 // Negotiate and NTLM are often requested together. However, we only want 2782 // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip 2783 // the header that requests Negotiate for this test. 2784 MockRead("WWW-Authenticate: NTLM\r\n"), 2785 MockRead("Connection: close\r\n"), 2786 MockRead("Content-Length: 42\r\n"), 2787 MockRead("Content-Type: text/html\r\n\r\n"), 2788 // Missing content -- won't matter, as connection will be reset. 2789 MockRead(false, ERR_UNEXPECTED), 2790 }; 2791 2792 MockWrite data_writes2[] = { 2793 // After restarting with a null identity, this is the 2794 // request we should be issuing -- the final header line contains a Type 2795 // 1 message. 2796 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 2797 "Host: 172.22.68.17\r\n" 2798 "Connection: keep-alive\r\n" 2799 "Authorization: NTLM " 2800 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), 2801 2802 // After calling trans->RestartWithAuth(), we should send a Type 3 message 2803 // (the credentials for the origin server). The second request continues 2804 // on the same connection. 2805 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 2806 "Host: 172.22.68.17\r\n" 2807 "Connection: keep-alive\r\n" 2808 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" 2809 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" 2810 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW" 2811 "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX" 2812 "ahlhx5I=\r\n\r\n"), 2813 }; 2814 2815 MockRead data_reads2[] = { 2816 // The origin server responds with a Type 2 message. 2817 MockRead("HTTP/1.1 401 Access Denied\r\n"), 2818 MockRead("WWW-Authenticate: NTLM " 2819 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo" 2820 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" 2821 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" 2822 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" 2823 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" 2824 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" 2825 "BtAAAAAAA=\r\n"), 2826 MockRead("Content-Length: 42\r\n"), 2827 MockRead("Content-Type: text/html\r\n\r\n"), 2828 MockRead("You are not authorized to view this page\r\n"), 2829 2830 // Lastly we get the desired content. 2831 MockRead("HTTP/1.1 200 OK\r\n"), 2832 MockRead("Content-Type: text/html; charset=utf-8\r\n"), 2833 MockRead("Content-Length: 13\r\n\r\n"), 2834 MockRead("Please Login\r\n"), 2835 MockRead(false, OK), 2836 }; 2837 2838 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 2839 data_writes1, arraysize(data_writes1)); 2840 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 2841 data_writes2, arraysize(data_writes2)); 2842 session_deps.socket_factory.AddSocketDataProvider(&data1); 2843 session_deps.socket_factory.AddSocketDataProvider(&data2); 2844 2845 TestCompletionCallback callback1; 2846 2847 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 2848 2849 int rv = trans->Start(&request, &callback1, BoundNetLog()); 2850 EXPECT_EQ(ERR_IO_PENDING, rv); 2851 2852 rv = callback1.WaitForResult(); 2853 EXPECT_EQ(OK, rv); 2854 2855 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 2856 2857 const HttpResponseInfo* response = trans->GetResponseInfo(); 2858 ASSERT_TRUE(response != NULL); 2859 2860 // The password prompt info should have been set in 2861 // response->auth_challenge. 2862 ASSERT_FALSE(response->auth_challenge.get() == NULL); 2863 2864 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port); 2865 EXPECT_EQ(L"", response->auth_challenge->realm); 2866 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme); 2867 2868 TestCompletionCallback callback2; 2869 2870 rv = trans->RestartWithAuth(kTestingNTLM, kTestingNTLM, &callback2); 2871 EXPECT_EQ(ERR_IO_PENDING, rv); 2872 2873 rv = callback2.WaitForResult(); 2874 EXPECT_EQ(OK, rv); 2875 2876 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 2877 2878 response = trans->GetResponseInfo(); 2879 ASSERT_TRUE(response != NULL); 2880 2881 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2882 2883 TestCompletionCallback callback3; 2884 2885 rv = trans->RestartWithAuth(string16(), string16(), &callback3); 2886 EXPECT_EQ(ERR_IO_PENDING, rv); 2887 2888 rv = callback3.WaitForResult(); 2889 EXPECT_EQ(OK, rv); 2890 2891 response = trans->GetResponseInfo(); 2892 ASSERT_FALSE(response == NULL); 2893 EXPECT_TRUE(response->auth_challenge.get() == NULL); 2894 EXPECT_EQ(13, response->headers->GetContentLength()); 2895 } 2896 2897 // Enter a wrong password, and then the correct one. 2898 TEST_F(HttpNetworkTransactionTest, NTLMAuth2) { 2899 HttpRequestInfo request; 2900 request.method = "GET"; 2901 request.url = GURL("http://172.22.68.17/kids/login.aspx"); 2902 request.load_flags = 0; 2903 2904 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom2, 2905 MockGetHostName); 2906 SessionDependencies session_deps; 2907 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 2908 2909 MockWrite data_writes1[] = { 2910 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 2911 "Host: 172.22.68.17\r\n" 2912 "Connection: keep-alive\r\n\r\n"), 2913 }; 2914 2915 MockRead data_reads1[] = { 2916 MockRead("HTTP/1.1 401 Access Denied\r\n"), 2917 // Negotiate and NTLM are often requested together. However, we only want 2918 // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip 2919 // the header that requests Negotiate for this test. 2920 MockRead("WWW-Authenticate: NTLM\r\n"), 2921 MockRead("Connection: close\r\n"), 2922 MockRead("Content-Length: 42\r\n"), 2923 MockRead("Content-Type: text/html\r\n\r\n"), 2924 // Missing content -- won't matter, as connection will be reset. 2925 MockRead(false, ERR_UNEXPECTED), 2926 }; 2927 2928 MockWrite data_writes2[] = { 2929 // After restarting with a null identity, this is the 2930 // request we should be issuing -- the final header line contains a Type 2931 // 1 message. 2932 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 2933 "Host: 172.22.68.17\r\n" 2934 "Connection: keep-alive\r\n" 2935 "Authorization: NTLM " 2936 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), 2937 2938 // After calling trans->RestartWithAuth(), we should send a Type 3 message 2939 // (the credentials for the origin server). The second request continues 2940 // on the same connection. 2941 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 2942 "Host: 172.22.68.17\r\n" 2943 "Connection: keep-alive\r\n" 2944 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" 2945 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" 2946 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY" 2947 "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj" 2948 "4Ww7b7E=\r\n\r\n"), 2949 }; 2950 2951 MockRead data_reads2[] = { 2952 // The origin server responds with a Type 2 message. 2953 MockRead("HTTP/1.1 401 Access Denied\r\n"), 2954 MockRead("WWW-Authenticate: NTLM " 2955 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCbVWUZezVGpAAAAAAAAAAALo" 2956 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" 2957 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" 2958 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" 2959 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" 2960 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" 2961 "BtAAAAAAA=\r\n"), 2962 MockRead("Content-Length: 42\r\n"), 2963 MockRead("Content-Type: text/html\r\n\r\n"), 2964 MockRead("You are not authorized to view this page\r\n"), 2965 2966 // Wrong password. 2967 MockRead("HTTP/1.1 401 Access Denied\r\n"), 2968 MockRead("WWW-Authenticate: NTLM\r\n"), 2969 MockRead("Connection: close\r\n"), 2970 MockRead("Content-Length: 42\r\n"), 2971 MockRead("Content-Type: text/html\r\n\r\n"), 2972 // Missing content -- won't matter, as connection will be reset. 2973 MockRead(false, ERR_UNEXPECTED), 2974 }; 2975 2976 MockWrite data_writes3[] = { 2977 // After restarting with a null identity, this is the 2978 // request we should be issuing -- the final header line contains a Type 2979 // 1 message. 2980 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 2981 "Host: 172.22.68.17\r\n" 2982 "Connection: keep-alive\r\n" 2983 "Authorization: NTLM " 2984 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), 2985 2986 // After calling trans->RestartWithAuth(), we should send a Type 3 message 2987 // (the credentials for the origin server). The second request continues 2988 // on the same connection. 2989 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" 2990 "Host: 172.22.68.17\r\n" 2991 "Connection: keep-alive\r\n" 2992 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" 2993 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" 2994 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54" 2995 "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI" 2996 "+4MUm7c=\r\n\r\n"), 2997 }; 2998 2999 MockRead data_reads3[] = { 3000 // The origin server responds with a Type 2 message. 3001 MockRead("HTTP/1.1 401 Access Denied\r\n"), 3002 MockRead("WWW-Authenticate: NTLM " 3003 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCL24VN8dgOR8AAAAAAAAAALo" 3004 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" 3005 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" 3006 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" 3007 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" 3008 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" 3009 "BtAAAAAAA=\r\n"), 3010 MockRead("Content-Length: 42\r\n"), 3011 MockRead("Content-Type: text/html\r\n\r\n"), 3012 MockRead("You are not authorized to view this page\r\n"), 3013 3014 // Lastly we get the desired content. 3015 MockRead("HTTP/1.1 200 OK\r\n"), 3016 MockRead("Content-Type: text/html; charset=utf-8\r\n"), 3017 MockRead("Content-Length: 13\r\n\r\n"), 3018 MockRead("Please Login\r\n"), 3019 MockRead(false, OK), 3020 }; 3021 3022 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 3023 data_writes1, arraysize(data_writes1)); 3024 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 3025 data_writes2, arraysize(data_writes2)); 3026 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), 3027 data_writes3, arraysize(data_writes3)); 3028 session_deps.socket_factory.AddSocketDataProvider(&data1); 3029 session_deps.socket_factory.AddSocketDataProvider(&data2); 3030 session_deps.socket_factory.AddSocketDataProvider(&data3); 3031 3032 TestCompletionCallback callback1; 3033 3034 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 3035 3036 int rv = trans->Start(&request, &callback1, BoundNetLog()); 3037 EXPECT_EQ(ERR_IO_PENDING, rv); 3038 3039 rv = callback1.WaitForResult(); 3040 EXPECT_EQ(OK, rv); 3041 3042 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 3043 3044 const HttpResponseInfo* response = trans->GetResponseInfo(); 3045 EXPECT_FALSE(response == NULL); 3046 3047 // The password prompt info should have been set in response->auth_challenge. 3048 EXPECT_FALSE(response->auth_challenge.get() == NULL); 3049 3050 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port); 3051 EXPECT_EQ(L"", response->auth_challenge->realm); 3052 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme); 3053 3054 TestCompletionCallback callback2; 3055 3056 // Enter the wrong password. 3057 rv = trans->RestartWithAuth(kTestingNTLM, kWrongPassword, &callback2); 3058 EXPECT_EQ(ERR_IO_PENDING, rv); 3059 3060 rv = callback2.WaitForResult(); 3061 EXPECT_EQ(OK, rv); 3062 3063 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 3064 TestCompletionCallback callback3; 3065 rv = trans->RestartWithAuth(string16(), string16(), &callback3); 3066 EXPECT_EQ(ERR_IO_PENDING, rv); 3067 rv = callback3.WaitForResult(); 3068 EXPECT_EQ(OK, rv); 3069 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 3070 3071 response = trans->GetResponseInfo(); 3072 ASSERT_TRUE(response != NULL); 3073 3074 // The password prompt info should have been set in response->auth_challenge. 3075 EXPECT_FALSE(response->auth_challenge.get() == NULL); 3076 3077 EXPECT_EQ(L"172.22.68.17:80", response->auth_challenge->host_and_port); 3078 EXPECT_EQ(L"", response->auth_challenge->realm); 3079 EXPECT_EQ(L"ntlm", response->auth_challenge->scheme); 3080 3081 TestCompletionCallback callback4; 3082 3083 // Now enter the right password. 3084 rv = trans->RestartWithAuth(kTestingNTLM, kTestingNTLM, &callback4); 3085 EXPECT_EQ(ERR_IO_PENDING, rv); 3086 3087 rv = callback4.WaitForResult(); 3088 EXPECT_EQ(OK, rv); 3089 3090 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 3091 3092 TestCompletionCallback callback5; 3093 3094 // One more roundtrip 3095 rv = trans->RestartWithAuth(string16(), string16(), &callback5); 3096 EXPECT_EQ(ERR_IO_PENDING, rv); 3097 3098 rv = callback5.WaitForResult(); 3099 EXPECT_EQ(OK, rv); 3100 3101 response = trans->GetResponseInfo(); 3102 EXPECT_TRUE(response->auth_challenge.get() == NULL); 3103 EXPECT_EQ(13, response->headers->GetContentLength()); 3104 } 3105 #endif // NTLM_PORTABLE 3106 3107 // Test reading a server response which has only headers, and no body. 3108 // After some maximum number of bytes is consumed, the transaction should 3109 // fail with ERR_RESPONSE_HEADERS_TOO_BIG. 3110 TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) { 3111 HttpRequestInfo request; 3112 request.method = "GET"; 3113 request.url = GURL("http://www.google.com/"); 3114 request.load_flags = 0; 3115 3116 SessionDependencies session_deps; 3117 scoped_ptr<HttpTransaction> trans( 3118 new HttpNetworkTransaction(CreateSession(&session_deps))); 3119 3120 // Respond with 300 kb of headers (we should fail after 256 kb). 3121 std::string large_headers_string; 3122 FillLargeHeadersString(&large_headers_string, 300 * 1024); 3123 3124 MockRead data_reads[] = { 3125 MockRead("HTTP/1.0 200 OK\r\n"), 3126 MockRead(true, large_headers_string.data(), large_headers_string.size()), 3127 MockRead("\r\nBODY"), 3128 MockRead(false, OK), 3129 }; 3130 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); 3131 session_deps.socket_factory.AddSocketDataProvider(&data); 3132 3133 TestCompletionCallback callback; 3134 3135 int rv = trans->Start(&request, &callback, BoundNetLog()); 3136 EXPECT_EQ(ERR_IO_PENDING, rv); 3137 3138 rv = callback.WaitForResult(); 3139 EXPECT_EQ(ERR_RESPONSE_HEADERS_TOO_BIG, rv); 3140 3141 const HttpResponseInfo* response = trans->GetResponseInfo(); 3142 EXPECT_TRUE(response == NULL); 3143 } 3144 3145 // Make sure that we don't try to reuse a TCPClientSocket when failing to 3146 // establish tunnel. 3147 // http://code.google.com/p/chromium/issues/detail?id=3772 3148 TEST_F(HttpNetworkTransactionTest, DontRecycleTransportSocketForSSLTunnel) { 3149 HttpRequestInfo request; 3150 request.method = "GET"; 3151 request.url = GURL("https://www.google.com/"); 3152 request.load_flags = 0; 3153 3154 // Configure against proxy server "myproxy:70". 3155 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); 3156 3157 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 3158 3159 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 3160 3161 // Since we have proxy, should try to establish tunnel. 3162 MockWrite data_writes1[] = { 3163 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 3164 "Host: www.google.com\r\n" 3165 "Proxy-Connection: keep-alive\r\n\r\n"), 3166 }; 3167 3168 // The proxy responds to the connect with a 404, using a persistent 3169 // connection. Usually a proxy would return 501 (not implemented), 3170 // or 200 (tunnel established). 3171 MockRead data_reads1[] = { 3172 MockRead("HTTP/1.1 404 Not Found\r\n"), 3173 MockRead("Content-Length: 10\r\n\r\n"), 3174 MockRead(false, ERR_UNEXPECTED), // Should not be reached. 3175 }; 3176 3177 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 3178 data_writes1, arraysize(data_writes1)); 3179 session_deps.socket_factory.AddSocketDataProvider(&data1); 3180 3181 TestCompletionCallback callback1; 3182 3183 int rv = trans->Start(&request, &callback1, BoundNetLog()); 3184 EXPECT_EQ(ERR_IO_PENDING, rv); 3185 3186 rv = callback1.WaitForResult(); 3187 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); 3188 3189 const HttpResponseInfo* response = trans->GetResponseInfo(); 3190 EXPECT_TRUE(response == NULL); 3191 3192 // Empty the current queue. This is necessary because idle sockets are 3193 // added to the connection pool asynchronously with a PostTask. 3194 MessageLoop::current()->RunAllPending(); 3195 3196 // We now check to make sure the TCPClientSocket was not added back to 3197 // the pool. 3198 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); 3199 trans.reset(); 3200 MessageLoop::current()->RunAllPending(); 3201 // Make sure that the socket didn't get recycled after calling the destructor. 3202 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); 3203 } 3204 3205 // Make sure that we recycle a socket after reading all of the response body. 3206 TEST_F(HttpNetworkTransactionTest, RecycleSocket) { 3207 HttpRequestInfo request; 3208 request.method = "GET"; 3209 request.url = GURL("http://www.google.com/"); 3210 request.load_flags = 0; 3211 3212 SessionDependencies session_deps; 3213 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 3214 3215 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 3216 3217 MockRead data_reads[] = { 3218 // A part of the response body is received with the response headers. 3219 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"), 3220 // The rest of the response body is received in two parts. 3221 MockRead("lo"), 3222 MockRead(" world"), 3223 MockRead("junk"), // Should not be read!! 3224 MockRead(false, OK), 3225 }; 3226 3227 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); 3228 session_deps.socket_factory.AddSocketDataProvider(&data); 3229 3230 TestCompletionCallback callback; 3231 3232 int rv = trans->Start(&request, &callback, BoundNetLog()); 3233 EXPECT_EQ(ERR_IO_PENDING, rv); 3234 3235 rv = callback.WaitForResult(); 3236 EXPECT_EQ(OK, rv); 3237 3238 const HttpResponseInfo* response = trans->GetResponseInfo(); 3239 EXPECT_TRUE(response != NULL); 3240 3241 EXPECT_TRUE(response->headers != NULL); 3242 std::string status_line = response->headers->GetStatusLine(); 3243 EXPECT_EQ("HTTP/1.1 200 OK", status_line); 3244 3245 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); 3246 3247 std::string response_data; 3248 rv = ReadTransaction(trans.get(), &response_data); 3249 EXPECT_EQ(OK, rv); 3250 EXPECT_EQ("hello world", response_data); 3251 3252 // Empty the current queue. This is necessary because idle sockets are 3253 // added to the connection pool asynchronously with a PostTask. 3254 MessageLoop::current()->RunAllPending(); 3255 3256 // We now check to make sure the socket was added back to the pool. 3257 EXPECT_EQ(1, session->transport_socket_pool()->IdleSocketCount()); 3258 } 3259 3260 // Make sure that we recycle a SSL socket after reading all of the response 3261 // body. 3262 TEST_F(HttpNetworkTransactionTest, RecycleSSLSocket) { 3263 SessionDependencies session_deps; 3264 HttpRequestInfo request; 3265 request.method = "GET"; 3266 request.url = GURL("https://www.google.com/"); 3267 request.load_flags = 0; 3268 3269 MockWrite data_writes[] = { 3270 MockWrite("GET / HTTP/1.1\r\n" 3271 "Host: www.google.com\r\n" 3272 "Connection: keep-alive\r\n\r\n"), 3273 }; 3274 3275 MockRead data_reads[] = { 3276 MockRead("HTTP/1.1 200 OK\r\n"), 3277 MockRead("Content-Length: 11\r\n\r\n"), 3278 MockRead("hello world"), 3279 MockRead(false, OK), 3280 }; 3281 3282 SSLSocketDataProvider ssl(true, OK); 3283 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 3284 3285 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 3286 data_writes, arraysize(data_writes)); 3287 session_deps.socket_factory.AddSocketDataProvider(&data); 3288 3289 TestCompletionCallback callback; 3290 3291 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 3292 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 3293 3294 int rv = trans->Start(&request, &callback, BoundNetLog()); 3295 3296 EXPECT_EQ(ERR_IO_PENDING, rv); 3297 EXPECT_EQ(OK, callback.WaitForResult()); 3298 3299 const HttpResponseInfo* response = trans->GetResponseInfo(); 3300 ASSERT_TRUE(response != NULL); 3301 ASSERT_TRUE(response->headers != NULL); 3302 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 3303 3304 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); 3305 3306 std::string response_data; 3307 rv = ReadTransaction(trans.get(), &response_data); 3308 EXPECT_EQ(OK, rv); 3309 EXPECT_EQ("hello world", response_data); 3310 3311 // Empty the current queue. This is necessary because idle sockets are 3312 // added to the connection pool asynchronously with a PostTask. 3313 MessageLoop::current()->RunAllPending(); 3314 3315 // We now check to make sure the socket was added back to the pool. 3316 EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount()); 3317 } 3318 3319 // Grab a SSL socket, use it, and put it back into the pool. Then, reuse it 3320 // from the pool and make sure that we recover okay. 3321 TEST_F(HttpNetworkTransactionTest, RecycleDeadSSLSocket) { 3322 SessionDependencies session_deps; 3323 HttpRequestInfo request; 3324 request.method = "GET"; 3325 request.url = GURL("https://www.google.com/"); 3326 request.load_flags = 0; 3327 3328 MockWrite data_writes[] = { 3329 MockWrite("GET / HTTP/1.1\r\n" 3330 "Host: www.google.com\r\n" 3331 "Connection: keep-alive\r\n\r\n"), 3332 MockWrite("GET / HTTP/1.1\r\n" 3333 "Host: www.google.com\r\n" 3334 "Connection: keep-alive\r\n\r\n"), 3335 }; 3336 3337 MockRead data_reads[] = { 3338 MockRead("HTTP/1.1 200 OK\r\n"), 3339 MockRead("Content-Length: 11\r\n\r\n"), 3340 MockRead(false, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), 3341 MockRead("hello world"), 3342 MockRead(true, 0, 0) // EOF 3343 }; 3344 3345 SSLSocketDataProvider ssl(true, OK); 3346 SSLSocketDataProvider ssl2(true, OK); 3347 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 3348 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); 3349 3350 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 3351 data_writes, arraysize(data_writes)); 3352 StaticSocketDataProvider data2(data_reads, arraysize(data_reads), 3353 data_writes, arraysize(data_writes)); 3354 session_deps.socket_factory.AddSocketDataProvider(&data); 3355 session_deps.socket_factory.AddSocketDataProvider(&data2); 3356 3357 TestCompletionCallback callback; 3358 3359 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 3360 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 3361 3362 int rv = trans->Start(&request, &callback, BoundNetLog()); 3363 3364 EXPECT_EQ(ERR_IO_PENDING, rv); 3365 EXPECT_EQ(OK, callback.WaitForResult()); 3366 3367 const HttpResponseInfo* response = trans->GetResponseInfo(); 3368 ASSERT_TRUE(response != NULL); 3369 ASSERT_TRUE(response->headers != NULL); 3370 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 3371 3372 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); 3373 3374 std::string response_data; 3375 rv = ReadTransaction(trans.get(), &response_data); 3376 EXPECT_EQ(OK, rv); 3377 EXPECT_EQ("hello world", response_data); 3378 3379 // Empty the current queue. This is necessary because idle sockets are 3380 // added to the connection pool asynchronously with a PostTask. 3381 MessageLoop::current()->RunAllPending(); 3382 3383 // We now check to make sure the socket was added back to the pool. 3384 EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount()); 3385 3386 // Now start the second transaction, which should reuse the previous socket. 3387 3388 trans.reset(new HttpNetworkTransaction(session)); 3389 3390 rv = trans->Start(&request, &callback, BoundNetLog()); 3391 3392 EXPECT_EQ(ERR_IO_PENDING, rv); 3393 EXPECT_EQ(OK, callback.WaitForResult()); 3394 3395 response = trans->GetResponseInfo(); 3396 ASSERT_TRUE(response != NULL); 3397 ASSERT_TRUE(response->headers != NULL); 3398 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 3399 3400 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); 3401 3402 rv = ReadTransaction(trans.get(), &response_data); 3403 EXPECT_EQ(OK, rv); 3404 EXPECT_EQ("hello world", response_data); 3405 3406 // Empty the current queue. This is necessary because idle sockets are 3407 // added to the connection pool asynchronously with a PostTask. 3408 MessageLoop::current()->RunAllPending(); 3409 3410 // We now check to make sure the socket was added back to the pool. 3411 EXPECT_EQ(1, session->ssl_socket_pool()->IdleSocketCount()); 3412 } 3413 3414 // Make sure that we recycle a socket after a zero-length response. 3415 // http://crbug.com/9880 3416 TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) { 3417 HttpRequestInfo request; 3418 request.method = "GET"; 3419 request.url = GURL("http://www.google.com/csi?v=3&s=web&action=&" 3420 "tran=undefined&ei=mAXcSeegAo-SMurloeUN&" 3421 "e=17259,18167,19592,19773,19981,20133,20173,20233&" 3422 "rt=prt.2642,ol.2649,xjs.2951"); 3423 request.load_flags = 0; 3424 3425 SessionDependencies session_deps; 3426 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 3427 3428 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 3429 3430 MockRead data_reads[] = { 3431 MockRead("HTTP/1.1 204 No Content\r\n" 3432 "Content-Length: 0\r\n" 3433 "Content-Type: text/html\r\n\r\n"), 3434 MockRead("junk"), // Should not be read!! 3435 MockRead(false, OK), 3436 }; 3437 3438 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); 3439 session_deps.socket_factory.AddSocketDataProvider(&data); 3440 3441 TestCompletionCallback callback; 3442 3443 int rv = trans->Start(&request, &callback, BoundNetLog()); 3444 EXPECT_EQ(ERR_IO_PENDING, rv); 3445 3446 rv = callback.WaitForResult(); 3447 EXPECT_EQ(OK, rv); 3448 3449 const HttpResponseInfo* response = trans->GetResponseInfo(); 3450 EXPECT_TRUE(response != NULL); 3451 3452 EXPECT_TRUE(response->headers != NULL); 3453 std::string status_line = response->headers->GetStatusLine(); 3454 EXPECT_EQ("HTTP/1.1 204 No Content", status_line); 3455 3456 EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); 3457 3458 std::string response_data; 3459 rv = ReadTransaction(trans.get(), &response_data); 3460 EXPECT_EQ(OK, rv); 3461 EXPECT_EQ("", response_data); 3462 3463 // Empty the current queue. This is necessary because idle sockets are 3464 // added to the connection pool asynchronously with a PostTask. 3465 MessageLoop::current()->RunAllPending(); 3466 3467 // We now check to make sure the socket was added back to the pool. 3468 EXPECT_EQ(1, session->transport_socket_pool()->IdleSocketCount()); 3469 } 3470 3471 TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) { 3472 HttpRequestInfo request[2]; 3473 // Transaction 1: a GET request that succeeds. The socket is recycled 3474 // after use. 3475 request[0].method = "GET"; 3476 request[0].url = GURL("http://www.google.com/"); 3477 request[0].load_flags = 0; 3478 // Transaction 2: a POST request. Reuses the socket kept alive from 3479 // transaction 1. The first attempts fails when writing the POST data. 3480 // This causes the transaction to retry with a new socket. The second 3481 // attempt succeeds. 3482 request[1].method = "POST"; 3483 request[1].url = GURL("http://www.google.com/login.cgi"); 3484 request[1].upload_data = new UploadData; 3485 request[1].upload_data->AppendBytes("foo", 3); 3486 request[1].load_flags = 0; 3487 3488 SessionDependencies session_deps; 3489 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 3490 3491 // The first socket is used for transaction 1 and the first attempt of 3492 // transaction 2. 3493 3494 // The response of transaction 1. 3495 MockRead data_reads1[] = { 3496 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"), 3497 MockRead("hello world"), 3498 MockRead(false, OK), 3499 }; 3500 // The mock write results of transaction 1 and the first attempt of 3501 // transaction 2. 3502 MockWrite data_writes1[] = { 3503 MockWrite(false, 64), // GET 3504 MockWrite(false, 93), // POST 3505 MockWrite(false, ERR_CONNECTION_ABORTED), // POST data 3506 }; 3507 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 3508 data_writes1, arraysize(data_writes1)); 3509 3510 // The second socket is used for the second attempt of transaction 2. 3511 3512 // The response of transaction 2. 3513 MockRead data_reads2[] = { 3514 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"), 3515 MockRead("welcome"), 3516 MockRead(false, OK), 3517 }; 3518 // The mock write results of the second attempt of transaction 2. 3519 MockWrite data_writes2[] = { 3520 MockWrite(false, 93), // POST 3521 MockWrite(false, 3), // POST data 3522 }; 3523 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 3524 data_writes2, arraysize(data_writes2)); 3525 3526 session_deps.socket_factory.AddSocketDataProvider(&data1); 3527 session_deps.socket_factory.AddSocketDataProvider(&data2); 3528 3529 const char* kExpectedResponseData[] = { 3530 "hello world", "welcome" 3531 }; 3532 3533 for (int i = 0; i < 2; ++i) { 3534 scoped_ptr<HttpTransaction> trans( 3535 new HttpNetworkTransaction(session)); 3536 3537 TestCompletionCallback callback; 3538 3539 int rv = trans->Start(&request[i], &callback, BoundNetLog()); 3540 EXPECT_EQ(ERR_IO_PENDING, rv); 3541 3542 rv = callback.WaitForResult(); 3543 EXPECT_EQ(OK, rv); 3544 3545 const HttpResponseInfo* response = trans->GetResponseInfo(); 3546 EXPECT_TRUE(response != NULL); 3547 3548 EXPECT_TRUE(response->headers != NULL); 3549 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); 3550 3551 std::string response_data; 3552 rv = ReadTransaction(trans.get(), &response_data); 3553 EXPECT_EQ(OK, rv); 3554 EXPECT_EQ(kExpectedResponseData[i], response_data); 3555 } 3556 } 3557 3558 // Test the request-challenge-retry sequence for basic auth when there is 3559 // an identity in the URL. The request should be sent as normal, but when 3560 // it fails the identity from the URL is used to answer the challenge. 3561 TEST_F(HttpNetworkTransactionTest, AuthIdentityInURL) { 3562 HttpRequestInfo request; 3563 request.method = "GET"; 3564 // Note: the URL has a username:password in it. 3565 request.url = GURL("http://foo:b@r@www.google.com/"); 3566 3567 SessionDependencies session_deps; 3568 scoped_ptr<HttpTransaction> trans( 3569 new HttpNetworkTransaction(CreateSession(&session_deps))); 3570 3571 // The password contains an escaped character -- for this test to pass it 3572 // will need to be unescaped by HttpNetworkTransaction. 3573 EXPECT_EQ("b%40r", request.url.password()); 3574 3575 request.load_flags = LOAD_NORMAL; 3576 3577 MockWrite data_writes1[] = { 3578 MockWrite("GET / HTTP/1.1\r\n" 3579 "Host: www.google.com\r\n" 3580 "Connection: keep-alive\r\n\r\n"), 3581 }; 3582 3583 MockRead data_reads1[] = { 3584 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 3585 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 3586 MockRead("Content-Length: 10\r\n\r\n"), 3587 MockRead(false, ERR_FAILED), 3588 }; 3589 3590 // After the challenge above, the transaction will be restarted using the 3591 // identity from the url (foo, b@r) to answer the challenge. 3592 MockWrite data_writes2[] = { 3593 MockWrite("GET / HTTP/1.1\r\n" 3594 "Host: www.google.com\r\n" 3595 "Connection: keep-alive\r\n" 3596 "Authorization: Basic Zm9vOmJAcg==\r\n\r\n"), 3597 }; 3598 3599 MockRead data_reads2[] = { 3600 MockRead("HTTP/1.0 200 OK\r\n"), 3601 MockRead("Content-Length: 100\r\n\r\n"), 3602 MockRead(false, OK), 3603 }; 3604 3605 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 3606 data_writes1, arraysize(data_writes1)); 3607 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 3608 data_writes2, arraysize(data_writes2)); 3609 session_deps.socket_factory.AddSocketDataProvider(&data1); 3610 session_deps.socket_factory.AddSocketDataProvider(&data2); 3611 3612 TestCompletionCallback callback1; 3613 3614 int rv = trans->Start(&request, &callback1, BoundNetLog()); 3615 EXPECT_EQ(ERR_IO_PENDING, rv); 3616 3617 rv = callback1.WaitForResult(); 3618 EXPECT_EQ(OK, rv); 3619 3620 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 3621 TestCompletionCallback callback2; 3622 rv = trans->RestartWithAuth(string16(), string16(), &callback2); 3623 EXPECT_EQ(ERR_IO_PENDING, rv); 3624 rv = callback2.WaitForResult(); 3625 EXPECT_EQ(OK, rv); 3626 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 3627 3628 const HttpResponseInfo* response = trans->GetResponseInfo(); 3629 EXPECT_FALSE(response == NULL); 3630 3631 // There is no challenge info, since the identity in URL worked. 3632 EXPECT_TRUE(response->auth_challenge.get() == NULL); 3633 3634 EXPECT_EQ(100, response->headers->GetContentLength()); 3635 3636 // Empty the current queue. 3637 MessageLoop::current()->RunAllPending(); 3638 } 3639 3640 // Test the request-challenge-retry sequence for basic auth when there is 3641 // an incorrect identity in the URL. The identity from the URL should be used 3642 // only once. 3643 TEST_F(HttpNetworkTransactionTest, WrongAuthIdentityInURL) { 3644 HttpRequestInfo request; 3645 request.method = "GET"; 3646 // Note: the URL has a username:password in it. The password "baz" is 3647 // wrong (should be "bar"). 3648 request.url = GURL("http://foo:baz@www.google.com/"); 3649 3650 request.load_flags = LOAD_NORMAL; 3651 3652 SessionDependencies session_deps; 3653 scoped_ptr<HttpTransaction> trans( 3654 new HttpNetworkTransaction(CreateSession(&session_deps))); 3655 3656 MockWrite data_writes1[] = { 3657 MockWrite("GET / HTTP/1.1\r\n" 3658 "Host: www.google.com\r\n" 3659 "Connection: keep-alive\r\n\r\n"), 3660 }; 3661 3662 MockRead data_reads1[] = { 3663 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 3664 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 3665 MockRead("Content-Length: 10\r\n\r\n"), 3666 MockRead(false, ERR_FAILED), 3667 }; 3668 3669 // After the challenge above, the transaction will be restarted using the 3670 // identity from the url (foo, baz) to answer the challenge. 3671 MockWrite data_writes2[] = { 3672 MockWrite("GET / HTTP/1.1\r\n" 3673 "Host: www.google.com\r\n" 3674 "Connection: keep-alive\r\n" 3675 "Authorization: Basic Zm9vOmJheg==\r\n\r\n"), 3676 }; 3677 3678 MockRead data_reads2[] = { 3679 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 3680 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 3681 MockRead("Content-Length: 10\r\n\r\n"), 3682 MockRead(false, ERR_FAILED), 3683 }; 3684 3685 // After the challenge above, the transaction will be restarted using the 3686 // identity supplied by the user (foo, bar) to answer the challenge. 3687 MockWrite data_writes3[] = { 3688 MockWrite("GET / HTTP/1.1\r\n" 3689 "Host: www.google.com\r\n" 3690 "Connection: keep-alive\r\n" 3691 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 3692 }; 3693 3694 MockRead data_reads3[] = { 3695 MockRead("HTTP/1.0 200 OK\r\n"), 3696 MockRead("Content-Length: 100\r\n\r\n"), 3697 MockRead(false, OK), 3698 }; 3699 3700 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 3701 data_writes1, arraysize(data_writes1)); 3702 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 3703 data_writes2, arraysize(data_writes2)); 3704 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), 3705 data_writes3, arraysize(data_writes3)); 3706 session_deps.socket_factory.AddSocketDataProvider(&data1); 3707 session_deps.socket_factory.AddSocketDataProvider(&data2); 3708 session_deps.socket_factory.AddSocketDataProvider(&data3); 3709 3710 TestCompletionCallback callback1; 3711 3712 int rv = trans->Start(&request, &callback1, BoundNetLog()); 3713 EXPECT_EQ(ERR_IO_PENDING, rv); 3714 3715 rv = callback1.WaitForResult(); 3716 EXPECT_EQ(OK, rv); 3717 3718 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 3719 TestCompletionCallback callback2; 3720 rv = trans->RestartWithAuth(string16(), string16(), &callback2); 3721 EXPECT_EQ(ERR_IO_PENDING, rv); 3722 rv = callback2.WaitForResult(); 3723 EXPECT_EQ(OK, rv); 3724 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 3725 3726 const HttpResponseInfo* response = trans->GetResponseInfo(); 3727 EXPECT_FALSE(response == NULL); 3728 // The password prompt info should have been set in response->auth_challenge. 3729 EXPECT_FALSE(response->auth_challenge.get() == NULL); 3730 3731 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 3732 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 3733 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 3734 3735 TestCompletionCallback callback3; 3736 rv = trans->RestartWithAuth(kFoo, kBar, &callback3); 3737 EXPECT_EQ(ERR_IO_PENDING, rv); 3738 rv = callback3.WaitForResult(); 3739 EXPECT_EQ(OK, rv); 3740 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 3741 3742 response = trans->GetResponseInfo(); 3743 EXPECT_FALSE(response == NULL); 3744 3745 // There is no challenge info, since the identity worked. 3746 EXPECT_TRUE(response->auth_challenge.get() == NULL); 3747 3748 EXPECT_EQ(100, response->headers->GetContentLength()); 3749 3750 // Empty the current queue. 3751 MessageLoop::current()->RunAllPending(); 3752 } 3753 3754 // Test that previously tried username/passwords for a realm get re-used. 3755 TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) { 3756 SessionDependencies session_deps; 3757 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 3758 3759 // Transaction 1: authenticate (foo, bar) on MyRealm1 3760 { 3761 HttpRequestInfo request; 3762 request.method = "GET"; 3763 request.url = GURL("http://www.google.com/x/y/z"); 3764 request.load_flags = 0; 3765 3766 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 3767 3768 MockWrite data_writes1[] = { 3769 MockWrite("GET /x/y/z HTTP/1.1\r\n" 3770 "Host: www.google.com\r\n" 3771 "Connection: keep-alive\r\n\r\n"), 3772 }; 3773 3774 MockRead data_reads1[] = { 3775 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 3776 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 3777 MockRead("Content-Length: 10000\r\n\r\n"), 3778 MockRead(false, ERR_FAILED), 3779 }; 3780 3781 // Resend with authorization (username=foo, password=bar) 3782 MockWrite data_writes2[] = { 3783 MockWrite("GET /x/y/z HTTP/1.1\r\n" 3784 "Host: www.google.com\r\n" 3785 "Connection: keep-alive\r\n" 3786 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 3787 }; 3788 3789 // Sever accepts the authorization. 3790 MockRead data_reads2[] = { 3791 MockRead("HTTP/1.0 200 OK\r\n"), 3792 MockRead("Content-Length: 100\r\n\r\n"), 3793 MockRead(false, OK), 3794 }; 3795 3796 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 3797 data_writes1, arraysize(data_writes1)); 3798 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 3799 data_writes2, arraysize(data_writes2)); 3800 session_deps.socket_factory.AddSocketDataProvider(&data1); 3801 session_deps.socket_factory.AddSocketDataProvider(&data2); 3802 3803 TestCompletionCallback callback1; 3804 3805 int rv = trans->Start(&request, &callback1, BoundNetLog()); 3806 EXPECT_EQ(ERR_IO_PENDING, rv); 3807 3808 rv = callback1.WaitForResult(); 3809 EXPECT_EQ(OK, rv); 3810 3811 const HttpResponseInfo* response = trans->GetResponseInfo(); 3812 EXPECT_FALSE(response == NULL); 3813 3814 // The password prompt info should have been set in 3815 // response->auth_challenge. 3816 EXPECT_FALSE(response->auth_challenge.get() == NULL); 3817 3818 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 3819 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 3820 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 3821 3822 TestCompletionCallback callback2; 3823 3824 rv = trans->RestartWithAuth(kFoo, kBar, &callback2); 3825 EXPECT_EQ(ERR_IO_PENDING, rv); 3826 3827 rv = callback2.WaitForResult(); 3828 EXPECT_EQ(OK, rv); 3829 3830 response = trans->GetResponseInfo(); 3831 EXPECT_FALSE(response == NULL); 3832 EXPECT_TRUE(response->auth_challenge.get() == NULL); 3833 EXPECT_EQ(100, response->headers->GetContentLength()); 3834 } 3835 3836 // ------------------------------------------------------------------------ 3837 3838 // Transaction 2: authenticate (foo2, bar2) on MyRealm2 3839 { 3840 HttpRequestInfo request; 3841 request.method = "GET"; 3842 // Note that Transaction 1 was at /x/y/z, so this is in the same 3843 // protection space as MyRealm1. 3844 request.url = GURL("http://www.google.com/x/y/a/b"); 3845 request.load_flags = 0; 3846 3847 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 3848 3849 MockWrite data_writes1[] = { 3850 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" 3851 "Host: www.google.com\r\n" 3852 "Connection: keep-alive\r\n" 3853 // Send preemptive authorization for MyRealm1 3854 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 3855 }; 3856 3857 // The server didn't like the preemptive authorization, and 3858 // challenges us for a different realm (MyRealm2). 3859 MockRead data_reads1[] = { 3860 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 3861 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"), 3862 MockRead("Content-Length: 10000\r\n\r\n"), 3863 MockRead(false, ERR_FAILED), 3864 }; 3865 3866 // Resend with authorization for MyRealm2 (username=foo2, password=bar2) 3867 MockWrite data_writes2[] = { 3868 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" 3869 "Host: www.google.com\r\n" 3870 "Connection: keep-alive\r\n" 3871 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), 3872 }; 3873 3874 // Sever accepts the authorization. 3875 MockRead data_reads2[] = { 3876 MockRead("HTTP/1.0 200 OK\r\n"), 3877 MockRead("Content-Length: 100\r\n\r\n"), 3878 MockRead(false, OK), 3879 }; 3880 3881 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 3882 data_writes1, arraysize(data_writes1)); 3883 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 3884 data_writes2, arraysize(data_writes2)); 3885 session_deps.socket_factory.AddSocketDataProvider(&data1); 3886 session_deps.socket_factory.AddSocketDataProvider(&data2); 3887 3888 TestCompletionCallback callback1; 3889 3890 int rv = trans->Start(&request, &callback1, BoundNetLog()); 3891 EXPECT_EQ(ERR_IO_PENDING, rv); 3892 3893 rv = callback1.WaitForResult(); 3894 EXPECT_EQ(OK, rv); 3895 3896 const HttpResponseInfo* response = trans->GetResponseInfo(); 3897 EXPECT_FALSE(response == NULL); 3898 3899 // The password prompt info should have been set in 3900 // response->auth_challenge. 3901 EXPECT_FALSE(response->auth_challenge.get() == NULL); 3902 3903 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 3904 EXPECT_EQ(L"MyRealm2", response->auth_challenge->realm); 3905 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 3906 3907 TestCompletionCallback callback2; 3908 3909 rv = trans->RestartWithAuth(kFoo2, kBar2, &callback2); 3910 EXPECT_EQ(ERR_IO_PENDING, rv); 3911 3912 rv = callback2.WaitForResult(); 3913 EXPECT_EQ(OK, rv); 3914 3915 response = trans->GetResponseInfo(); 3916 EXPECT_FALSE(response == NULL); 3917 EXPECT_TRUE(response->auth_challenge.get() == NULL); 3918 EXPECT_EQ(100, response->headers->GetContentLength()); 3919 } 3920 3921 // ------------------------------------------------------------------------ 3922 3923 // Transaction 3: Resend a request in MyRealm's protection space -- 3924 // succeed with preemptive authorization. 3925 { 3926 HttpRequestInfo request; 3927 request.method = "GET"; 3928 request.url = GURL("http://www.google.com/x/y/z2"); 3929 request.load_flags = 0; 3930 3931 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 3932 3933 MockWrite data_writes1[] = { 3934 MockWrite("GET /x/y/z2 HTTP/1.1\r\n" 3935 "Host: www.google.com\r\n" 3936 "Connection: keep-alive\r\n" 3937 // The authorization for MyRealm1 gets sent preemptively 3938 // (since the url is in the same protection space) 3939 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 3940 }; 3941 3942 // Sever accepts the preemptive authorization 3943 MockRead data_reads1[] = { 3944 MockRead("HTTP/1.0 200 OK\r\n"), 3945 MockRead("Content-Length: 100\r\n\r\n"), 3946 MockRead(false, OK), 3947 }; 3948 3949 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 3950 data_writes1, arraysize(data_writes1)); 3951 session_deps.socket_factory.AddSocketDataProvider(&data1); 3952 3953 TestCompletionCallback callback1; 3954 3955 int rv = trans->Start(&request, &callback1, BoundNetLog()); 3956 EXPECT_EQ(ERR_IO_PENDING, rv); 3957 3958 rv = callback1.WaitForResult(); 3959 EXPECT_EQ(OK, rv); 3960 3961 const HttpResponseInfo* response = trans->GetResponseInfo(); 3962 EXPECT_FALSE(response == NULL); 3963 3964 EXPECT_TRUE(response->auth_challenge.get() == NULL); 3965 EXPECT_EQ(100, response->headers->GetContentLength()); 3966 } 3967 3968 // ------------------------------------------------------------------------ 3969 3970 // Transaction 4: request another URL in MyRealm (however the 3971 // url is not known to belong to the protection space, so no pre-auth). 3972 { 3973 HttpRequestInfo request; 3974 request.method = "GET"; 3975 request.url = GURL("http://www.google.com/x/1"); 3976 request.load_flags = 0; 3977 3978 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 3979 3980 MockWrite data_writes1[] = { 3981 MockWrite("GET /x/1 HTTP/1.1\r\n" 3982 "Host: www.google.com\r\n" 3983 "Connection: keep-alive\r\n\r\n"), 3984 }; 3985 3986 MockRead data_reads1[] = { 3987 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 3988 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 3989 MockRead("Content-Length: 10000\r\n\r\n"), 3990 MockRead(false, ERR_FAILED), 3991 }; 3992 3993 // Resend with authorization from MyRealm's cache. 3994 MockWrite data_writes2[] = { 3995 MockWrite("GET /x/1 HTTP/1.1\r\n" 3996 "Host: www.google.com\r\n" 3997 "Connection: keep-alive\r\n" 3998 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 3999 }; 4000 4001 // Sever accepts the authorization. 4002 MockRead data_reads2[] = { 4003 MockRead("HTTP/1.0 200 OK\r\n"), 4004 MockRead("Content-Length: 100\r\n\r\n"), 4005 MockRead(false, OK), 4006 }; 4007 4008 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 4009 data_writes1, arraysize(data_writes1)); 4010 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 4011 data_writes2, arraysize(data_writes2)); 4012 session_deps.socket_factory.AddSocketDataProvider(&data1); 4013 session_deps.socket_factory.AddSocketDataProvider(&data2); 4014 4015 TestCompletionCallback callback1; 4016 4017 int rv = trans->Start(&request, &callback1, BoundNetLog()); 4018 EXPECT_EQ(ERR_IO_PENDING, rv); 4019 4020 rv = callback1.WaitForResult(); 4021 EXPECT_EQ(OK, rv); 4022 4023 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 4024 TestCompletionCallback callback2; 4025 rv = trans->RestartWithAuth(string16(), string16(), &callback2); 4026 EXPECT_EQ(ERR_IO_PENDING, rv); 4027 rv = callback2.WaitForResult(); 4028 EXPECT_EQ(OK, rv); 4029 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 4030 4031 const HttpResponseInfo* response = trans->GetResponseInfo(); 4032 EXPECT_FALSE(response == NULL); 4033 EXPECT_TRUE(response->auth_challenge.get() == NULL); 4034 EXPECT_EQ(100, response->headers->GetContentLength()); 4035 } 4036 4037 // ------------------------------------------------------------------------ 4038 4039 // Transaction 5: request a URL in MyRealm, but the server rejects the 4040 // cached identity. Should invalidate and re-prompt. 4041 { 4042 HttpRequestInfo request; 4043 request.method = "GET"; 4044 request.url = GURL("http://www.google.com/p/q/t"); 4045 request.load_flags = 0; 4046 4047 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 4048 4049 MockWrite data_writes1[] = { 4050 MockWrite("GET /p/q/t HTTP/1.1\r\n" 4051 "Host: www.google.com\r\n" 4052 "Connection: keep-alive\r\n\r\n"), 4053 }; 4054 4055 MockRead data_reads1[] = { 4056 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 4057 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 4058 MockRead("Content-Length: 10000\r\n\r\n"), 4059 MockRead(false, ERR_FAILED), 4060 }; 4061 4062 // Resend with authorization from cache for MyRealm. 4063 MockWrite data_writes2[] = { 4064 MockWrite("GET /p/q/t HTTP/1.1\r\n" 4065 "Host: www.google.com\r\n" 4066 "Connection: keep-alive\r\n" 4067 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), 4068 }; 4069 4070 // Sever rejects the authorization. 4071 MockRead data_reads2[] = { 4072 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 4073 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), 4074 MockRead("Content-Length: 10000\r\n\r\n"), 4075 MockRead(false, ERR_FAILED), 4076 }; 4077 4078 // At this point we should prompt for new credentials for MyRealm. 4079 // Restart with username=foo3, password=foo4. 4080 MockWrite data_writes3[] = { 4081 MockWrite("GET /p/q/t HTTP/1.1\r\n" 4082 "Host: www.google.com\r\n" 4083 "Connection: keep-alive\r\n" 4084 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"), 4085 }; 4086 4087 // Sever accepts the authorization. 4088 MockRead data_reads3[] = { 4089 MockRead("HTTP/1.0 200 OK\r\n"), 4090 MockRead("Content-Length: 100\r\n\r\n"), 4091 MockRead(false, OK), 4092 }; 4093 4094 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 4095 data_writes1, arraysize(data_writes1)); 4096 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 4097 data_writes2, arraysize(data_writes2)); 4098 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), 4099 data_writes3, arraysize(data_writes3)); 4100 session_deps.socket_factory.AddSocketDataProvider(&data1); 4101 session_deps.socket_factory.AddSocketDataProvider(&data2); 4102 session_deps.socket_factory.AddSocketDataProvider(&data3); 4103 4104 TestCompletionCallback callback1; 4105 4106 int rv = trans->Start(&request, &callback1, BoundNetLog()); 4107 EXPECT_EQ(ERR_IO_PENDING, rv); 4108 4109 rv = callback1.WaitForResult(); 4110 EXPECT_EQ(OK, rv); 4111 4112 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); 4113 TestCompletionCallback callback2; 4114 rv = trans->RestartWithAuth(string16(), string16(), &callback2); 4115 EXPECT_EQ(ERR_IO_PENDING, rv); 4116 rv = callback2.WaitForResult(); 4117 EXPECT_EQ(OK, rv); 4118 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); 4119 4120 const HttpResponseInfo* response = trans->GetResponseInfo(); 4121 EXPECT_FALSE(response == NULL); 4122 4123 // The password prompt info should have been set in 4124 // response->auth_challenge. 4125 EXPECT_FALSE(response->auth_challenge.get() == NULL); 4126 4127 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 4128 EXPECT_EQ(L"MyRealm1", response->auth_challenge->realm); 4129 EXPECT_EQ(L"basic", response->auth_challenge->scheme); 4130 4131 TestCompletionCallback callback3; 4132 4133 rv = trans->RestartWithAuth(kFoo3, kBar3, &callback3); 4134 EXPECT_EQ(ERR_IO_PENDING, rv); 4135 4136 rv = callback3.WaitForResult(); 4137 EXPECT_EQ(OK, rv); 4138 4139 response = trans->GetResponseInfo(); 4140 EXPECT_FALSE(response == NULL); 4141 EXPECT_TRUE(response->auth_challenge.get() == NULL); 4142 EXPECT_EQ(100, response->headers->GetContentLength()); 4143 } 4144 } 4145 4146 // Tests that nonce count increments when multiple auth attempts 4147 // are started with the same nonce. 4148 TEST_F(HttpNetworkTransactionTest, DigestPreAuthNonceCount) { 4149 SessionDependencies session_deps; 4150 HttpAuthHandlerDigest::Factory* digest_factory = 4151 new HttpAuthHandlerDigest::Factory(); 4152 HttpAuthHandlerDigest::FixedNonceGenerator* nonce_generator = 4153 new HttpAuthHandlerDigest::FixedNonceGenerator("0123456789abcdef"); 4154 digest_factory->set_nonce_generator(nonce_generator); 4155 session_deps.http_auth_handler_factory.reset(digest_factory); 4156 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); 4157 4158 // Transaction 1: authenticate (foo, bar) on MyRealm1 4159 { 4160 HttpRequestInfo request; 4161 request.method = "GET"; 4162 request.url = GURL("http://www.google.com/x/y/z"); 4163 request.load_flags = 0; 4164 4165 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 4166 4167 MockWrite data_writes1[] = { 4168 MockWrite("GET /x/y/z HTTP/1.1\r\n" 4169 "Host: www.google.com\r\n" 4170 "Connection: keep-alive\r\n\r\n"), 4171 }; 4172 4173 MockRead data_reads1[] = { 4174 MockRead("HTTP/1.0 401 Unauthorized\r\n"), 4175 MockRead("WWW-Authenticate: Digest realm=\"digestive\", nonce=\"OU812\", " 4176 "algorithm=MD5, qop=\"auth\"\r\n\r\n"), 4177 MockRead(false, OK), 4178 }; 4179 4180 // Resend with authorization (username=foo, password=bar) 4181 MockWrite data_writes2[] = { 4182 MockWrite("GET /x/y/z HTTP/1.1\r\n" 4183 "Host: www.google.com\r\n" 4184 "Connection: keep-alive\r\n" 4185 "Authorization: Digest username=\"foo\", realm=\"digestive\", " 4186 "nonce=\"OU812\", uri=\"/x/y/z\", algorithm=MD5, " 4187 "response=\"03ffbcd30add722589c1de345d7a927f\", qop=auth, " 4188 "nc=00000001, cnonce=\"0123456789abcdef\"\r\n\r\n"), 4189 }; 4190 4191 // Sever accepts the authorization. 4192 MockRead data_reads2[] = { 4193 MockRead("HTTP/1.0 200 OK\r\n"), 4194 MockRead(false, OK), 4195 }; 4196 4197 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 4198 data_writes1, arraysize(data_writes1)); 4199 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), 4200 data_writes2, arraysize(data_writes2)); 4201 session_deps.socket_factory.AddSocketDataProvider(&data1); 4202 session_deps.socket_factory.AddSocketDataProvider(&data2); 4203 4204 TestCompletionCallback callback1; 4205 4206 int rv = trans->Start(&request, &callback1, BoundNetLog()); 4207 EXPECT_EQ(ERR_IO_PENDING, rv); 4208 4209 rv = callback1.WaitForResult(); 4210 EXPECT_EQ(OK, rv); 4211 4212 const HttpResponseInfo* response = trans->GetResponseInfo(); 4213 ASSERT_FALSE(response == NULL); 4214 4215 // The password prompt info should have been set in 4216 // response->auth_challenge. 4217 ASSERT_FALSE(response->auth_challenge.get() == NULL); 4218 4219 EXPECT_EQ(L"www.google.com:80", response->auth_challenge->host_and_port); 4220 EXPECT_EQ(L"digestive", response->auth_challenge->realm); 4221 EXPECT_EQ(L"digest", response->auth_challenge->scheme); 4222 4223 TestCompletionCallback callback2; 4224 4225 rv = trans->RestartWithAuth(kFoo, kBar, &callback2); 4226 EXPECT_EQ(ERR_IO_PENDING, rv); 4227 4228 rv = callback2.WaitForResult(); 4229 EXPECT_EQ(OK, rv); 4230 4231 response = trans->GetResponseInfo(); 4232 ASSERT_FALSE(response == NULL); 4233 EXPECT_TRUE(response->auth_challenge.get() == NULL); 4234 } 4235 4236 // ------------------------------------------------------------------------ 4237 4238 // Transaction 2: Request another resource in digestive's protection space. 4239 // This will preemptively add an Authorization header which should have an 4240 // "nc" value of 2 (as compared to 1 in the first use. 4241 { 4242 HttpRequestInfo request; 4243 request.method = "GET"; 4244 // Note that Transaction 1 was at /x/y/z, so this is in the same 4245 // protection space as digest. 4246 request.url = GURL("http://www.google.com/x/y/a/b"); 4247 request.load_flags = 0; 4248 4249 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); 4250 4251 MockWrite data_writes1[] = { 4252 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" 4253 "Host: www.google.com\r\n" 4254 "Connection: keep-alive\r\n" 4255 "Authorization: Digest username=\"foo\", realm=\"digestive\", " 4256 "nonce=\"OU812\", uri=\"/x/y/a/b\", algorithm=MD5, " 4257 "response=\"d6f9a2c07d1c5df7b89379dca1269b35\", qop=auth, " 4258 "nc=00000002, cnonce=\"0123456789abcdef\"\r\n\r\n"), 4259 }; 4260 4261 // Sever accepts the authorization. 4262 MockRead data_reads1[] = { 4263 MockRead("HTTP/1.0 200 OK\r\n"), 4264 MockRead("Content-Length: 100\r\n\r\n"), 4265 MockRead(false, OK), 4266 }; 4267 4268 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), 4269 data_writes1, arraysize(data_writes1)); 4270 session_deps.socket_factory.AddSocketDataProvider(&data1); 4271 4272 TestCompletionCallback callback1; 4273 4274 int rv = trans->Start(&request, &callback1, BoundNetLog()); 4275 EXPECT_EQ(ERR_IO_PENDING, rv); 4276 4277 rv = callback1.WaitForResult(); 4278 EXPECT_EQ(OK, rv); 4279 4280 const HttpResponseInfo* response = trans->GetResponseInfo(); 4281 ASSERT_FALSE(response == NULL); 4282 EXPECT_TRUE(response->auth_challenge.get() == NULL); 4283 } 4284 } 4285 4286 // Test the ResetStateForRestart() private method. 4287 TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) { 4288 // Create a transaction (the dependencies aren't important). 4289 SessionDependencies session_deps; 4290 scoped_ptr<HttpNetworkTransaction> trans( 4291 new HttpNetworkTransaction(CreateSession(&session_deps))); 4292 4293 // Setup some state (which we expect ResetStateForRestart() will clear). 4294 trans->read_buf_ = new IOBuffer(15); 4295 trans->read_buf_len_ = 15; 4296 trans->request_headers_.SetHeader("Authorization", "NTLM"); 4297 4298 // Setup state in response_ 4299 HttpResponseInfo* response = &trans->response_; 4300 response->auth_challenge = new AuthChallengeInfo(); 4301 response->ssl_info.cert_status = -15; 4302 response->response_time = base::Time::Now(); 4303 response->was_cached = true; // (Wouldn't ever actually be true...) 4304 4305 { // Setup state for response_.vary_data 4306 HttpRequestInfo request; 4307 std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n"); 4308 std::replace(temp.begin(), temp.end(), '\n', '\0'); 4309 scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(temp)); 4310 request.extra_headers.SetHeader("Foo", "1"); 4311 request.extra_headers.SetHeader("bar", "23"); 4312 EXPECT_TRUE(response->vary_data.Init(request, *headers)); 4313 } 4314 4315 // Cause the above state to be reset. 4316 trans->ResetStateForRestart(); 4317 4318 // Verify that the state that needed to be reset, has been reset. 4319 EXPECT_TRUE(trans->read_buf_.get() == NULL); 4320 EXPECT_EQ(0, trans->read_buf_len_); 4321 EXPECT_TRUE(trans->request_headers_.IsEmpty()); 4322 EXPECT_TRUE(response->auth_challenge.get() == NULL); 4323 EXPECT_TRUE(response->headers.get() == NULL); 4324 EXPECT_FALSE(response->was_cached); 4325 EXPECT_EQ(0, response->ssl_info.cert_status); 4326 EXPECT_FALSE(response->vary_data.is_valid()); 4327 } 4328 4329 // Test HTTPS connections to a site with a bad certificate 4330 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificate) { 4331 HttpRequestInfo request; 4332 request.method = "GET"; 4333 request.url = GURL("https://www.google.com/"); 4334 request.load_flags = 0; 4335 4336 SessionDependencies session_deps; 4337 scoped_ptr<HttpTransaction> trans( 4338 new HttpNetworkTransaction(CreateSession(&session_deps))); 4339 4340 MockWrite data_writes[] = { 4341 MockWrite("GET / HTTP/1.1\r\n" 4342 "Host: www.google.com\r\n" 4343 "Connection: keep-alive\r\n\r\n"), 4344 }; 4345 4346 MockRead data_reads[] = { 4347 MockRead("HTTP/1.0 200 OK\r\n"), 4348 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 4349 MockRead("Content-Length: 100\r\n\r\n"), 4350 MockRead(false, OK), 4351 }; 4352 4353 StaticSocketDataProvider ssl_bad_certificate; 4354 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 4355 data_writes, arraysize(data_writes)); 4356 SSLSocketDataProvider ssl_bad(true, ERR_CERT_AUTHORITY_INVALID); 4357 SSLSocketDataProvider ssl(true, OK); 4358 4359 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); 4360 session_deps.socket_factory.AddSocketDataProvider(&data); 4361 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); 4362 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 4363 4364 TestCompletionCallback callback; 4365 4366 int rv = trans->Start(&request, &callback, BoundNetLog()); 4367 EXPECT_EQ(ERR_IO_PENDING, rv); 4368 4369 rv = callback.WaitForResult(); 4370 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); 4371 4372 rv = trans->RestartIgnoringLastError(&callback); 4373 EXPECT_EQ(ERR_IO_PENDING, rv); 4374 4375 rv = callback.WaitForResult(); 4376 EXPECT_EQ(OK, rv); 4377 4378 const HttpResponseInfo* response = trans->GetResponseInfo(); 4379 4380 EXPECT_FALSE(response == NULL); 4381 EXPECT_EQ(100, response->headers->GetContentLength()); 4382 } 4383 4384 // Test HTTPS connections to a site with a bad certificate, going through a 4385 // proxy 4386 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) { 4387 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); 4388 4389 HttpRequestInfo request; 4390 request.method = "GET"; 4391 request.url = GURL("https://www.google.com/"); 4392 request.load_flags = 0; 4393 4394 MockWrite proxy_writes[] = { 4395 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 4396 "Host: www.google.com\r\n" 4397 "Proxy-Connection: keep-alive\r\n\r\n"), 4398 }; 4399 4400 MockRead proxy_reads[] = { 4401 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), 4402 MockRead(false, OK) 4403 }; 4404 4405 MockWrite data_writes[] = { 4406 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 4407 "Host: www.google.com\r\n" 4408 "Proxy-Connection: keep-alive\r\n\r\n"), 4409 MockWrite("GET / HTTP/1.1\r\n" 4410 "Host: www.google.com\r\n" 4411 "Connection: keep-alive\r\n\r\n"), 4412 }; 4413 4414 MockRead data_reads[] = { 4415 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), 4416 MockRead("HTTP/1.0 200 OK\r\n"), 4417 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 4418 MockRead("Content-Length: 100\r\n\r\n"), 4419 MockRead(false, OK), 4420 }; 4421 4422 StaticSocketDataProvider ssl_bad_certificate( 4423 proxy_reads, arraysize(proxy_reads), 4424 proxy_writes, arraysize(proxy_writes)); 4425 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 4426 data_writes, arraysize(data_writes)); 4427 SSLSocketDataProvider ssl_bad(true, ERR_CERT_AUTHORITY_INVALID); 4428 SSLSocketDataProvider ssl(true, OK); 4429 4430 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); 4431 session_deps.socket_factory.AddSocketDataProvider(&data); 4432 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); 4433 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); 4434 4435 TestCompletionCallback callback; 4436 4437 for (int i = 0; i < 2; i++) { 4438 session_deps.socket_factory.ResetNextMockIndexes(); 4439 4440 scoped_ptr<HttpTransaction> trans( 4441 new HttpNetworkTransaction(CreateSession(&session_deps))); 4442 4443 int rv = trans->Start(&request, &callback, BoundNetLog()); 4444 EXPECT_EQ(ERR_IO_PENDING, rv); 4445 4446 rv = callback.WaitForResult(); 4447 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); 4448 4449 rv = trans->RestartIgnoringLastError(&callback); 4450 EXPECT_EQ(ERR_IO_PENDING, rv); 4451 4452 rv = callback.WaitForResult(); 4453 EXPECT_EQ(OK, rv); 4454 4455 const HttpResponseInfo* response = trans->GetResponseInfo(); 4456 4457 EXPECT_FALSE(response == NULL); 4458 EXPECT_EQ(100, response->headers->GetContentLength()); 4459 } 4460 } 4461 4462 4463 // Test HTTPS connections to a site, going through an HTTPS proxy 4464 TEST_F(HttpNetworkTransactionTest, HTTPSViaHttpsProxy) { 4465 SessionDependencies session_deps(ProxyService::CreateFixed("https://proxy:70")); 4466 4467 HttpRequestInfo request; 4468 request.method = "GET"; 4469 request.url = GURL("https://www.google.com/"); 4470 request.load_flags = 0; 4471 4472 MockWrite data_writes[] = { 4473 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 4474 "Host: www.google.com\r\n" 4475 "Proxy-Connection: keep-alive\r\n\r\n"), 4476 MockWrite("GET / HTTP/1.1\r\n" 4477 "Host: www.google.com\r\n" 4478 "Connection: keep-alive\r\n\r\n"), 4479 }; 4480 4481 MockRead data_reads[] = { 4482 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), 4483 MockRead("HTTP/1.1 200 OK\r\n"), 4484 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), 4485 MockRead("Content-Length: 100\r\n\r\n"), 4486 MockRead(false, OK), 4487 }; 4488 4489 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 4490 data_writes, arraysize(data_writes)); 4491 SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy 4492 SSLSocketDataProvider tunnel_ssl(true, OK); // SSL through the tunnel 4493 4494 session_deps.socket_factory.AddSocketDataProvider(&data); 4495 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); 4496 session_deps.socket_factory.AddSSLSocketDataProvider(&tunnel_ssl); 4497 4498 TestCompletionCallback callback; 4499 4500 scoped_ptr<HttpTransaction> trans( 4501 new HttpNetworkTransaction(CreateSession(&session_deps))); 4502 4503 int rv = trans->Start(&request, &callback, BoundNetLog()); 4504 EXPECT_EQ(ERR_IO_PENDING, rv); 4505 4506 rv = callback.WaitForResult(); 4507 EXPECT_EQ(OK, rv); 4508 const HttpResponseInfo* response = trans->GetResponseInfo(); 4509 4510 ASSERT_FALSE(response == NULL); 4511 4512 EXPECT_TRUE(response->headers->IsKeepAlive()); 4513 EXPECT_EQ(200, response->headers->response_code()); 4514 EXPECT_EQ(100, response->headers->GetContentLength()); 4515 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 4516 } 4517 4518 // Test an HTTPS Proxy's ability to redirect a CONNECT request 4519 TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) { 4520 SessionDependencies session_deps( 4521 ProxyService::CreateFixed("https://proxy:70")); 4522 4523 HttpRequestInfo request; 4524 request.method = "GET"; 4525 request.url = GURL("https://www.google.com/"); 4526 request.load_flags = 0; 4527 4528 MockWrite data_writes[] = { 4529 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 4530 "Host: www.google.com\r\n" 4531 "Proxy-Connection: keep-alive\r\n\r\n"), 4532 }; 4533 4534 MockRead data_reads[] = { 4535 MockRead("HTTP/1.1 302 Redirect\r\n"), 4536 MockRead("Location: http://login.example.com/\r\n"), 4537 MockRead("Content-Length: 0\r\n\r\n"), 4538 MockRead(false, OK), 4539 }; 4540 4541 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 4542 data_writes, arraysize(data_writes)); 4543 SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy 4544 4545 session_deps.socket_factory.AddSocketDataProvider(&data); 4546 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); 4547 4548 TestCompletionCallback callback; 4549 4550 scoped_ptr<HttpTransaction> trans( 4551 new HttpNetworkTransaction(CreateSession(&session_deps))); 4552 4553 int rv = trans->Start(&request, &callback, BoundNetLog()); 4554 EXPECT_EQ(ERR_IO_PENDING, rv); 4555 4556 rv = callback.WaitForResult(); 4557 EXPECT_EQ(OK, rv); 4558 const HttpResponseInfo* response = trans->GetResponseInfo(); 4559 4560 ASSERT_FALSE(response == NULL); 4561 4562 EXPECT_EQ(302, response->headers->response_code()); 4563 std::string url; 4564 EXPECT_TRUE(response->headers->IsRedirect(&url)); 4565 EXPECT_EQ("http://login.example.com/", url); 4566 } 4567 4568 // Test an HTTPS (SPDY) Proxy's ability to redirect a CONNECT request 4569 TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) { 4570 SessionDependencies session_deps( 4571 ProxyService::CreateFixed("https://proxy:70")); 4572 4573 HttpRequestInfo request; 4574 request.method = "GET"; 4575 request.url = GURL("https://www.google.com/"); 4576 request.load_flags = 0; 4577 4578 scoped_ptr<spdy::SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1)); 4579 scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyRstStream(1, spdy::CANCEL)); 4580 MockWrite data_writes[] = { 4581 CreateMockWrite(*conn.get(), 0, false), 4582 }; 4583 4584 static const char* const kExtraHeaders[] = { 4585 "location", 4586 "http://login.example.com/", 4587 }; 4588 scoped_ptr<spdy::SpdyFrame> resp( 4589 ConstructSpdySynReplyError("302 Redirect", kExtraHeaders, 4590 arraysize(kExtraHeaders)/2, 1)); 4591 MockRead data_reads[] = { 4592 CreateMockRead(*resp.get(), 1, false), 4593 MockRead(true, 0, 2), // EOF 4594 }; 4595 4596 scoped_refptr<DelayedSocketData> data( 4597 new DelayedSocketData( 4598 1, // wait for one write to finish before reading. 4599 data_reads, arraysize(data_reads), 4600 data_writes, arraysize(data_writes))); 4601 SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy 4602 proxy_ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; 4603 proxy_ssl.next_proto = "spdy/2"; 4604 proxy_ssl.was_npn_negotiated = true; 4605 4606 session_deps.socket_factory.AddSocketDataProvider(data.get()); 4607 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); 4608 4609 TestCompletionCallback callback; 4610 4611 scoped_ptr<HttpTransaction> trans( 4612 new HttpNetworkTransaction(CreateSession(&session_deps))); 4613 4614 int rv = trans->Start(&request, &callback, BoundNetLog()); 4615 EXPECT_EQ(ERR_IO_PENDING, rv); 4616 4617 rv = callback.WaitForResult(); 4618 EXPECT_EQ(OK, rv); 4619 const HttpResponseInfo* response = trans->GetResponseInfo(); 4620 4621 ASSERT_FALSE(response == NULL); 4622 4623 EXPECT_EQ(302, response->headers->response_code()); 4624 std::string url; 4625 EXPECT_TRUE(response->headers->IsRedirect(&url)); 4626 EXPECT_EQ("http://login.example.com/", url); 4627 } 4628 4629 // Test an HTTPS Proxy's ability to provide a response to a CONNECT request 4630 TEST_F(HttpNetworkTransactionTest, ErrorResponseTofHttpsConnectViaHttpsProxy) { 4631 SessionDependencies session_deps( 4632 ProxyService::CreateFixed("https://proxy:70")); 4633 4634 HttpRequestInfo request; 4635 request.method = "GET"; 4636 request.url = GURL("https://www.google.com/"); 4637 request.load_flags = 0; 4638 4639 MockWrite data_writes[] = { 4640 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" 4641 "Host: www.google.com\r\n" 4642 "Proxy-Connection: keep-alive\r\n\r\n"), 4643 }; 4644 4645 MockRead data_reads[] = { 4646 MockRead("HTTP/1.1 404 Not Found\r\n"), 4647 MockRead("Content-Length: 23\r\n\r\n"), 4648 MockRead("The host does not exist"), 4649 MockRead(false, OK), 4650 }; 4651 4652 StaticSocketDataProvider data(data_reads, arraysize(data_reads), 4653 data_writes, arraysize(data_writes)); 4654 SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy 4655 4656 session_deps.socket_factory.AddSocketDataProvider(&data); 4657 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); 4658 4659 TestCompletionCallback callback; 4660 4661 scoped_ptr<HttpTransaction> trans( 4662 new HttpNetworkTransaction(CreateSession(&session_deps))); 4663 4664 int rv = trans->Start(&request, &callback, BoundNetLog()); 4665 EXPECT_EQ(ERR_IO_PENDING, rv); 4666 4667 rv = callback.WaitForResult(); 4668 EXPECT_EQ(OK, rv); 4669 const HttpResponseInfo* response = trans->GetResponseInfo(); 4670 4671 ASSERT_FALSE(response == NULL); 4672 4673 EXPECT_EQ(404, response->headers->response_code()); 4674 EXPECT_EQ(23, response->headers->GetContentLength()); 4675 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); 4676 EXPECT_FALSE(response->ssl_info.is_valid()); 4677 4678 std::string response_data; 4679 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); 4680 EXPECT_EQ("The host does not exist", response_data); 4681 } 4682 4683 // Test an HTTPS (SPDY) Proxy's ability to provide a response to a CONNECT 4684 // request 4685 TEST_F(HttpNetworkTransactionTest, ErrorResponseTofHttpsConnectViaSpdyProxy) { 4686 SessionDependencies session_deps( 4687 ProxyService::CreateFixed("https://proxy:70")); 4688 4689 HttpRequestInfo request; 4690 request.method = "GET"; 4691 request.url = GURL("https://www.google.com/"); 4692 request.load_flags = 0; 4693 4694 scoped_ptr<spdy::SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1)); 4695 scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyRstStream(1, spdy::CANCEL)); 4696 MockWrite data_writes[] = { 4697 CreateMockWrite(*conn.get(), 0, false), 4698 }; 4699 4700 static const char* const kExtraHeaders[] = { 4701 "location", 4702 "http://login.example.com/", 4703 }; 4704 scoped_ptr<spdy::SpdyFrame> resp( 4705 ConstructSpdySynReplyError("404 Not Found", kExtraHeaders, 4706 arraysize(kExtraHeaders)/2, 1)); 4707 scoped_ptr<spdy::SpdyFrame> body( 4708 ConstructSpdyBodyFrame(1, "The host does not exist", 23, true)); 4709 MockRead data_reads[] = { 4710 CreateMockRead(*resp.get(), 1, false), 4711 CreateMockRead(*body.get(), 2, false), 4712 MockRead(true, 0, 3), // EOF 4713 }; 4714 4715 scoped_refptr<DelayedSocketData> data( 4716 new DelayedSocketData( 4717 1, // wait for one write to finish before reading. 4718 data_reads, arraysize(data_reads), 4719 data_writes, arraysize(data_writes))); 4720 SSLSocketDataProvider proxy_ssl(true, OK); // SSL to the proxy 4721 proxy_ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; 4722 proxy_ssl.next_proto = "spdy/2"; 4723 proxy_ssl.was_npn_negotiated = true; 4724 4725 session_deps.socket_factory.AddSocketDataProvider(data.get()); 4726 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); 4727 4728 TestCompletionCallback callback; 4729 4730 scoped_ptr<HttpTransaction> trans( 4731 new HttpNetworkTransaction(CreateSession(&session_deps))); 4732 4733 int rv = trans->Start(&request, &callback, BoundNetLog()); 4734 EXPECT_EQ(ERR_IO_PENDING, rv); 4735 4736 rv = callback.WaitForResult(); 4737 EXPECT_EQ(OK, rv); 4738 const HttpResponseInfo* response = trans->GetResponseInfo(); 4739 4740 ASSERT_FALSE(response == NULL); 4741 4742 EXPECT_EQ(404, response->headers->response_code()); 4743 EXPECT_FALSE(response->ssl_info.is_valid()); 4744 4745 std::string response_data; 4746 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); 4747 EXPECT_EQ("The host does not exist", response_data); 4748 } 4749 4750 // Test HTTPS connections to a site with a bad certificate, going through an 4751 // HTTPS proxy 4752 TEST_F(HttpNetworkTransactionTest,