| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/http/http_network_transaction.h" | |
| 6 | |
| 7 #include <math.h> // ceil | |
| 8 #include <stdarg.h> | |
| 9 #include <string> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/basictypes.h" | |
| 13 #include "base/compiler_specific.h" | |
| 14 #include "base/file_path.h" | |
| 15 #include "base/file_util.h" | |
| 16 #include "base/memory/scoped_ptr.h" | |
| 17 #include "base/metrics/histogram.h" | |
| 18 #include "base/test/test_file_util.h" | |
| 19 #include "base/utf_string_conversions.h" | |
| 20 #include "net/base/auth.h" | |
| 21 #include "net/base/capturing_net_log.h" | |
| 22 #include "net/base/completion_callback.h" | |
| 23 #include "net/base/host_cache.h" | |
| 24 #include "net/base/mock_host_resolver.h" | |
| 25 #include "net/base/net_log.h" | |
| 26 #include "net/base/net_log_unittest.h" | |
| 27 #include "net/base/request_priority.h" | |
| 28 #include "net/base/ssl_cert_request_info.h" | |
| 29 #include "net/base/ssl_config_service_defaults.h" | |
| 30 #include "net/base/ssl_info.h" | |
| 31 #include "net/base/test_completion_callback.h" | |
| 32 #include "net/base/upload_data.h" | |
| 33 #include "net/http/http_auth_handler_digest.h" | |
| 34 #include "net/http/http_auth_handler_mock.h" | |
| 35 #include "net/http/http_auth_handler_ntlm.h" | |
| 36 #include "net/http/http_basic_stream.h" | |
| 37 #include "net/http/http_net_log_params.h" | |
| 38 #include "net/http/http_network_session.h" | |
| 39 #include "net/http/http_network_session_peer.h" | |
| 40 #include "net/http/http_server_properties_impl.h" | |
| 41 #include "net/http/http_stream.h" | |
| 42 #include "net/http/http_stream_factory.h" | |
| 43 #include "net/http/http_transaction_unittest.h" | |
| 44 #include "net/proxy/proxy_config_service_fixed.h" | |
| 45 #include "net/proxy/proxy_resolver.h" | |
| 46 #include "net/proxy/proxy_service.h" | |
| 47 #include "net/socket/client_socket_factory.h" | |
| 48 #include "net/socket/mock_client_socket_pool_manager.h" | |
| 49 #include "net/socket/socket_test_util.h" | |
| 50 #include "net/socket/ssl_client_socket.h" | |
| 51 #include "net/spdy/spdy_framer.h" | |
| 52 #include "net/spdy/spdy_session.h" | |
| 53 #include "net/spdy/spdy_session_pool.h" | |
| 54 #include "net/spdy/spdy_test_util.h" | |
| 55 #include "testing/gtest/include/gtest/gtest.h" | |
| 56 #include "testing/platform_test.h" | |
| 57 | |
| 58 //----------------------------------------------------------------------------- | |
| 59 | |
| 60 namespace { | |
| 61 | |
| 62 const string16 kBar(ASCIIToUTF16("bar")); | |
| 63 const string16 kBar2(ASCIIToUTF16("bar2")); | |
| 64 const string16 kBar3(ASCIIToUTF16("bar3")); | |
| 65 const string16 kBaz(ASCIIToUTF16("baz")); | |
| 66 const string16 kFirst(ASCIIToUTF16("first")); | |
| 67 const string16 kFoo(ASCIIToUTF16("foo")); | |
| 68 const string16 kFoo2(ASCIIToUTF16("foo2")); | |
| 69 const string16 kFoo3(ASCIIToUTF16("foo3")); | |
| 70 const string16 kFou(ASCIIToUTF16("fou")); | |
| 71 const string16 kSecond(ASCIIToUTF16("second")); | |
| 72 const string16 kTestingNTLM(ASCIIToUTF16("testing-ntlm")); | |
| 73 const string16 kWrongPassword(ASCIIToUTF16("wrongpassword")); | |
| 74 | |
| 75 // MakeNextProtos is a utility function that returns a vector of std::strings | |
| 76 // from its arguments. Don't forget to terminate the argument list with a NULL. | |
| 77 std::vector<std::string> MakeNextProtos(const char* a, ...) { | |
| 78 std::vector<std::string> ret; | |
| 79 ret.push_back(a); | |
| 80 | |
| 81 va_list args; | |
| 82 va_start(args, a); | |
| 83 | |
| 84 for (;;) { | |
| 85 const char* value = va_arg(args, const char*); | |
| 86 if (value == NULL) | |
| 87 break; | |
| 88 ret.push_back(value); | |
| 89 } | |
| 90 va_end(args); | |
| 91 | |
| 92 return ret; | |
| 93 } | |
| 94 | |
| 95 // SpdyNextProtos returns a vector of NPN protocol strings for negotiating | |
| 96 // SPDY. | |
| 97 std::vector<std::string> SpdyNextProtos() { | |
| 98 return MakeNextProtos("http/1.1", "spdy/2", "spdy/2.1", NULL); | |
| 99 } | |
| 100 | |
| 101 } // namespace | |
| 102 | |
| 103 namespace net { | |
| 104 | |
| 105 // Helper to manage the lifetimes of the dependencies for a | |
| 106 // HttpNetworkTransaction. | |
| 107 struct SessionDependencies { | |
| 108 // Default set of dependencies -- "null" proxy service. | |
| 109 SessionDependencies() | |
| 110 : host_resolver(new MockHostResolver), | |
| 111 cert_verifier(new CertVerifier), | |
| 112 proxy_service(ProxyService::CreateDirect()), | |
| 113 ssl_config_service(new SSLConfigServiceDefaults), | |
| 114 http_auth_handler_factory( | |
| 115 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), | |
| 116 net_log(NULL) {} | |
| 117 | |
| 118 // Custom proxy service dependency. | |
| 119 explicit SessionDependencies(ProxyService* proxy_service) | |
| 120 : host_resolver(new MockHostResolver), | |
| 121 cert_verifier(new CertVerifier), | |
| 122 proxy_service(proxy_service), | |
| 123 ssl_config_service(new SSLConfigServiceDefaults), | |
| 124 http_auth_handler_factory( | |
| 125 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), | |
| 126 net_log(NULL) {} | |
| 127 | |
| 128 scoped_ptr<MockHostResolverBase> host_resolver; | |
| 129 scoped_ptr<CertVerifier> cert_verifier; | |
| 130 scoped_ptr<ProxyService> proxy_service; | |
| 131 scoped_refptr<SSLConfigService> ssl_config_service; | |
| 132 MockClientSocketFactory socket_factory; | |
| 133 scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory; | |
| 134 HttpServerPropertiesImpl http_server_properties; | |
| 135 NetLog* net_log; | |
| 136 }; | |
| 137 | |
| 138 HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { | |
| 139 net::HttpNetworkSession::Params params; | |
| 140 params.client_socket_factory = &session_deps->socket_factory; | |
| 141 params.host_resolver = session_deps->host_resolver.get(); | |
| 142 params.cert_verifier = session_deps->cert_verifier.get(); | |
| 143 params.proxy_service = session_deps->proxy_service.get(); | |
| 144 params.ssl_config_service = session_deps->ssl_config_service; | |
| 145 params.http_auth_handler_factory = | |
| 146 session_deps->http_auth_handler_factory.get(); | |
| 147 params.http_server_properties = &session_deps->http_server_properties; | |
| 148 params.net_log = session_deps->net_log; | |
| 149 return new HttpNetworkSession(params); | |
| 150 } | |
| 151 | |
| 152 class HttpNetworkTransactionTest : public PlatformTest { | |
| 153 protected: | |
| 154 struct SimpleGetHelperResult { | |
| 155 int rv; | |
| 156 std::string status_line; | |
| 157 std::string response_data; | |
| 158 }; | |
| 159 | |
| 160 virtual void SetUp() { | |
| 161 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); | |
| 162 MessageLoop::current()->RunAllPending(); | |
| 163 spdy::SpdyFramer::set_enable_compression_default(false); | |
| 164 } | |
| 165 | |
| 166 virtual void TearDown() { | |
| 167 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); | |
| 168 MessageLoop::current()->RunAllPending(); | |
| 169 spdy::SpdyFramer::set_enable_compression_default(true); | |
| 170 // Empty the current queue. | |
| 171 MessageLoop::current()->RunAllPending(); | |
| 172 PlatformTest::TearDown(); | |
| 173 NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); | |
| 174 MessageLoop::current()->RunAllPending(); | |
| 175 } | |
| 176 | |
| 177 // Either |write_failure| specifies a write failure or |read_failure| | |
| 178 // specifies a read failure when using a reused socket. In either case, the | |
| 179 // failure should cause the network transaction to resend the request, and the | |
| 180 // other argument should be NULL. | |
| 181 void KeepAliveConnectionResendRequestTest(const MockWrite* write_failure, | |
| 182 const MockRead* read_failure); | |
| 183 | |
| 184 SimpleGetHelperResult SimpleGetHelperForData(StaticSocketDataProvider* data[], | |
| 185 size_t data_count) { | |
| 186 SimpleGetHelperResult out; | |
| 187 | |
| 188 HttpRequestInfo request; | |
| 189 request.method = "GET"; | |
| 190 request.url = GURL("http://www.google.com/"); | |
| 191 request.load_flags = 0; | |
| 192 | |
| 193 SessionDependencies session_deps; | |
| 194 scoped_ptr<HttpTransaction> trans( | |
| 195 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 196 | |
| 197 for (size_t i = 0; i < data_count; ++i) { | |
| 198 session_deps.socket_factory.AddSocketDataProvider(data[i]); | |
| 199 } | |
| 200 | |
| 201 TestCompletionCallback callback; | |
| 202 | |
| 203 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 204 EXPECT_TRUE(log.bound().IsLoggingAllEvents()); | |
| 205 int rv = trans->Start(&request, callback.callback(), log.bound()); | |
| 206 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 207 | |
| 208 out.rv = callback.WaitForResult(); | |
| 209 if (out.rv != OK) | |
| 210 return out; | |
| 211 | |
| 212 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 213 // Can't use ASSERT_* inside helper functions like this, so | |
| 214 // return an error. | |
| 215 if (response == NULL || response->headers == NULL) { | |
| 216 out.rv = ERR_UNEXPECTED; | |
| 217 return out; | |
| 218 } | |
| 219 out.status_line = response->headers->GetStatusLine(); | |
| 220 | |
| 221 EXPECT_EQ("192.0.2.33", response->socket_address.host()); | |
| 222 EXPECT_EQ(0, response->socket_address.port()); | |
| 223 | |
| 224 rv = ReadTransaction(trans.get(), &out.response_data); | |
| 225 EXPECT_EQ(OK, rv); | |
| 226 | |
| 227 net::CapturingNetLog::EntryList entries; | |
| 228 log.GetEntries(&entries); | |
| 229 size_t pos = ExpectLogContainsSomewhere( | |
| 230 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS, | |
| 231 NetLog::PHASE_NONE); | |
| 232 ExpectLogContainsSomewhere( | |
| 233 entries, pos, | |
| 234 NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS, | |
| 235 NetLog::PHASE_NONE); | |
| 236 | |
| 237 CapturingNetLog::Entry entry = entries[pos]; | |
| 238 NetLogHttpRequestParameter* request_params = | |
| 239 static_cast<NetLogHttpRequestParameter*>(entry.extra_parameters.get()); | |
| 240 EXPECT_EQ("GET / HTTP/1.1\r\n", request_params->GetLine()); | |
| 241 EXPECT_EQ("Host: www.google.com\r\n" | |
| 242 "Connection: keep-alive\r\n\r\n", | |
| 243 request_params->GetHeaders().ToString()); | |
| 244 | |
| 245 return out; | |
| 246 } | |
| 247 | |
| 248 SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[], | |
| 249 size_t reads_count) { | |
| 250 StaticSocketDataProvider reads(data_reads, reads_count, NULL, 0); | |
| 251 StaticSocketDataProvider* data[] = { &reads }; | |
| 252 return SimpleGetHelperForData(data, 1); | |
| 253 } | |
| 254 | |
| 255 void ConnectStatusHelperWithExpectedStatus(const MockRead& status, | |
| 256 int expected_status); | |
| 257 | |
| 258 void ConnectStatusHelper(const MockRead& status); | |
| 259 }; | |
| 260 | |
| 261 // Fill |str| with a long header list that consumes >= |size| bytes. | |
| 262 void FillLargeHeadersString(std::string* str, int size) { | |
| 263 const char* row = | |
| 264 "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"; | |
| 265 const int sizeof_row = strlen(row); | |
| 266 const int num_rows = static_cast<int>( | |
| 267 ceil(static_cast<float>(size) / sizeof_row)); | |
| 268 const int sizeof_data = num_rows * sizeof_row; | |
| 269 DCHECK(sizeof_data >= size); | |
| 270 str->reserve(sizeof_data); | |
| 271 | |
| 272 for (int i = 0; i < num_rows; ++i) | |
| 273 str->append(row, sizeof_row); | |
| 274 } | |
| 275 | |
| 276 // Alternative functions that eliminate randomness and dependency on the local | |
| 277 // host name so that the generated NTLM messages are reproducible. | |
| 278 void MockGenerateRandom1(uint8* output, size_t n) { | |
| 279 static const uint8 bytes[] = { | |
| 280 0x55, 0x29, 0x66, 0x26, 0x6b, 0x9c, 0x73, 0x54 | |
| 281 }; | |
| 282 static size_t current_byte = 0; | |
| 283 for (size_t i = 0; i < n; ++i) { | |
| 284 output[i] = bytes[current_byte++]; | |
| 285 current_byte %= arraysize(bytes); | |
| 286 } | |
| 287 } | |
| 288 | |
| 289 void MockGenerateRandom2(uint8* output, size_t n) { | |
| 290 static const uint8 bytes[] = { | |
| 291 0x96, 0x79, 0x85, 0xe7, 0x49, 0x93, 0x70, 0xa1, | |
| 292 0x4e, 0xe7, 0x87, 0x45, 0x31, 0x5b, 0xd3, 0x1f | |
| 293 }; | |
| 294 static size_t current_byte = 0; | |
| 295 for (size_t i = 0; i < n; ++i) { | |
| 296 output[i] = bytes[current_byte++]; | |
| 297 current_byte %= arraysize(bytes); | |
| 298 } | |
| 299 } | |
| 300 | |
| 301 std::string MockGetHostName() { | |
| 302 return "WTC-WIN7"; | |
| 303 } | |
| 304 | |
| 305 template<typename ParentPool> | |
| 306 class CaptureGroupNameSocketPool : public ParentPool { | |
| 307 public: | |
| 308 CaptureGroupNameSocketPool(HostResolver* host_resolver, | |
| 309 CertVerifier* cert_verifier); | |
| 310 | |
| 311 const std::string last_group_name_received() const { | |
| 312 return last_group_name_; | |
| 313 } | |
| 314 | |
| 315 virtual int RequestSocket(const std::string& group_name, | |
| 316 const void* socket_params, | |
| 317 RequestPriority priority, | |
| 318 ClientSocketHandle* handle, | |
| 319 const CompletionCallback& callback, | |
| 320 const BoundNetLog& net_log) { | |
| 321 last_group_name_ = group_name; | |
| 322 return ERR_IO_PENDING; | |
| 323 } | |
| 324 virtual void CancelRequest(const std::string& group_name, | |
| 325 ClientSocketHandle* handle) {} | |
| 326 virtual void ReleaseSocket(const std::string& group_name, | |
| 327 StreamSocket* socket, | |
| 328 int id) {} | |
| 329 virtual void CloseIdleSockets() {} | |
| 330 virtual int IdleSocketCount() const { | |
| 331 return 0; | |
| 332 } | |
| 333 virtual int IdleSocketCountInGroup(const std::string& group_name) const { | |
| 334 return 0; | |
| 335 } | |
| 336 virtual LoadState GetLoadState(const std::string& group_name, | |
| 337 const ClientSocketHandle* handle) const { | |
| 338 return LOAD_STATE_IDLE; | |
| 339 } | |
| 340 virtual base::TimeDelta ConnectionTimeout() const { | |
| 341 return base::TimeDelta(); | |
| 342 } | |
| 343 | |
| 344 private: | |
| 345 std::string last_group_name_; | |
| 346 }; | |
| 347 | |
| 348 typedef CaptureGroupNameSocketPool<TransportClientSocketPool> | |
| 349 CaptureGroupNameTransportSocketPool; | |
| 350 typedef CaptureGroupNameSocketPool<HttpProxyClientSocketPool> | |
| 351 CaptureGroupNameHttpProxySocketPool; | |
| 352 typedef CaptureGroupNameSocketPool<SOCKSClientSocketPool> | |
| 353 CaptureGroupNameSOCKSSocketPool; | |
| 354 typedef CaptureGroupNameSocketPool<SSLClientSocketPool> | |
| 355 CaptureGroupNameSSLSocketPool; | |
| 356 | |
| 357 template<typename ParentPool> | |
| 358 CaptureGroupNameSocketPool<ParentPool>::CaptureGroupNameSocketPool( | |
| 359 HostResolver* host_resolver, | |
| 360 CertVerifier* /* cert_verifier */) | |
| 361 : ParentPool(0, 0, NULL, host_resolver, NULL, NULL) {} | |
| 362 | |
| 363 template<> | |
| 364 CaptureGroupNameHttpProxySocketPool::CaptureGroupNameSocketPool( | |
| 365 HostResolver* host_resolver, | |
| 366 CertVerifier* /* cert_verifier */) | |
| 367 : HttpProxyClientSocketPool(0, 0, NULL, host_resolver, NULL, NULL, NULL) {} | |
| 368 | |
| 369 template<> | |
| 370 CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool( | |
| 371 HostResolver* host_resolver, | |
| 372 CertVerifier* cert_verifier) | |
| 373 : SSLClientSocketPool(0, 0, NULL, host_resolver, cert_verifier, NULL, | |
| 374 NULL, NULL, "", NULL, NULL, NULL, NULL, NULL, NULL) {} | |
| 375 | |
| 376 //----------------------------------------------------------------------------- | |
| 377 | |
| 378 // This is the expected return from a current server advertising SPDY. | |
| 379 static const char kAlternateProtocolHttpHeader[] = | |
| 380 "Alternate-Protocol: 443:npn-spdy/2.1\r\n\r\n"; | |
| 381 | |
| 382 // Helper functions for validating that AuthChallengeInfo's are correctly | |
| 383 // configured for common cases. | |
| 384 bool CheckBasicServerAuth(const AuthChallengeInfo* auth_challenge) { | |
| 385 if (!auth_challenge) | |
| 386 return false; | |
| 387 EXPECT_FALSE(auth_challenge->is_proxy); | |
| 388 EXPECT_EQ("www.google.com:80", auth_challenge->challenger.ToString()); | |
| 389 EXPECT_EQ("MyRealm1", auth_challenge->realm); | |
| 390 EXPECT_EQ("basic", auth_challenge->scheme); | |
| 391 return true; | |
| 392 } | |
| 393 | |
| 394 bool CheckBasicProxyAuth(const AuthChallengeInfo* auth_challenge) { | |
| 395 if (!auth_challenge) | |
| 396 return false; | |
| 397 EXPECT_TRUE(auth_challenge->is_proxy); | |
| 398 EXPECT_EQ("myproxy:70", auth_challenge->challenger.ToString()); | |
| 399 EXPECT_EQ("MyRealm1", auth_challenge->realm); | |
| 400 EXPECT_EQ("basic", auth_challenge->scheme); | |
| 401 return true; | |
| 402 } | |
| 403 | |
| 404 bool CheckDigestServerAuth(const AuthChallengeInfo* auth_challenge) { | |
| 405 if (!auth_challenge) | |
| 406 return false; | |
| 407 EXPECT_FALSE(auth_challenge->is_proxy); | |
| 408 EXPECT_EQ("www.google.com:80", auth_challenge->challenger.ToString()); | |
| 409 EXPECT_EQ("digestive", auth_challenge->realm); | |
| 410 EXPECT_EQ("digest", auth_challenge->scheme); | |
| 411 return true; | |
| 412 } | |
| 413 | |
| 414 bool CheckNTLMServerAuth(const AuthChallengeInfo* auth_challenge) { | |
| 415 if (!auth_challenge) | |
| 416 return false; | |
| 417 EXPECT_FALSE(auth_challenge->is_proxy); | |
| 418 EXPECT_EQ("172.22.68.17:80", auth_challenge->challenger.ToString()); | |
| 419 EXPECT_EQ(std::string(), auth_challenge->realm); | |
| 420 EXPECT_EQ("ntlm", auth_challenge->scheme); | |
| 421 return true; | |
| 422 } | |
| 423 | |
| 424 TEST_F(HttpNetworkTransactionTest, Basic) { | |
| 425 SessionDependencies session_deps; | |
| 426 scoped_ptr<HttpTransaction> trans( | |
| 427 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 428 } | |
| 429 | |
| 430 TEST_F(HttpNetworkTransactionTest, SimpleGET) { | |
| 431 MockRead data_reads[] = { | |
| 432 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
| 433 MockRead("hello world"), | |
| 434 MockRead(SYNCHRONOUS, OK), | |
| 435 }; | |
| 436 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 437 arraysize(data_reads)); | |
| 438 EXPECT_EQ(OK, out.rv); | |
| 439 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); | |
| 440 EXPECT_EQ("hello world", out.response_data); | |
| 441 } | |
| 442 | |
| 443 // Response with no status line. | |
| 444 TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) { | |
| 445 MockRead data_reads[] = { | |
| 446 MockRead("hello world"), | |
| 447 MockRead(SYNCHRONOUS, OK), | |
| 448 }; | |
| 449 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 450 arraysize(data_reads)); | |
| 451 EXPECT_EQ(OK, out.rv); | |
| 452 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); | |
| 453 EXPECT_EQ("hello world", out.response_data); | |
| 454 } | |
| 455 | |
| 456 // Allow up to 4 bytes of junk to precede status line. | |
| 457 TEST_F(HttpNetworkTransactionTest, StatusLineJunk2Bytes) { | |
| 458 MockRead data_reads[] = { | |
| 459 MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), | |
| 460 MockRead(SYNCHRONOUS, OK), | |
| 461 }; | |
| 462 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 463 arraysize(data_reads)); | |
| 464 EXPECT_EQ(OK, out.rv); | |
| 465 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); | |
| 466 EXPECT_EQ("DATA", out.response_data); | |
| 467 } | |
| 468 | |
| 469 // Allow up to 4 bytes of junk to precede status line. | |
| 470 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) { | |
| 471 MockRead data_reads[] = { | |
| 472 MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), | |
| 473 MockRead(SYNCHRONOUS, OK), | |
| 474 }; | |
| 475 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 476 arraysize(data_reads)); | |
| 477 EXPECT_EQ(OK, out.rv); | |
| 478 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); | |
| 479 EXPECT_EQ("DATA", out.response_data); | |
| 480 } | |
| 481 | |
| 482 // Beyond 4 bytes of slop and it should fail to find a status line. | |
| 483 TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) { | |
| 484 MockRead data_reads[] = { | |
| 485 MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"), | |
| 486 MockRead(SYNCHRONOUS, OK), | |
| 487 }; | |
| 488 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 489 arraysize(data_reads)); | |
| 490 EXPECT_EQ(OK, out.rv); | |
| 491 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); | |
| 492 EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data); | |
| 493 } | |
| 494 | |
| 495 // Same as StatusLineJunk4Bytes, except the read chunks are smaller. | |
| 496 TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) { | |
| 497 MockRead data_reads[] = { | |
| 498 MockRead("\n"), | |
| 499 MockRead("\n"), | |
| 500 MockRead("Q"), | |
| 501 MockRead("J"), | |
| 502 MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), | |
| 503 MockRead(SYNCHRONOUS, OK), | |
| 504 }; | |
| 505 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 506 arraysize(data_reads)); | |
| 507 EXPECT_EQ(OK, out.rv); | |
| 508 EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); | |
| 509 EXPECT_EQ("DATA", out.response_data); | |
| 510 } | |
| 511 | |
| 512 // Close the connection before enough bytes to have a status line. | |
| 513 TEST_F(HttpNetworkTransactionTest, StatusLinePartial) { | |
| 514 MockRead data_reads[] = { | |
| 515 MockRead("HTT"), | |
| 516 MockRead(SYNCHRONOUS, OK), | |
| 517 }; | |
| 518 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 519 arraysize(data_reads)); | |
| 520 EXPECT_EQ(OK, out.rv); | |
| 521 EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); | |
| 522 EXPECT_EQ("HTT", out.response_data); | |
| 523 } | |
| 524 | |
| 525 // Simulate a 204 response, lacking a Content-Length header, sent over a | |
| 526 // persistent connection. The response should still terminate since a 204 | |
| 527 // cannot have a response body. | |
| 528 TEST_F(HttpNetworkTransactionTest, StopsReading204) { | |
| 529 MockRead data_reads[] = { | |
| 530 MockRead("HTTP/1.1 204 No Content\r\n\r\n"), | |
| 531 MockRead("junk"), // Should not be read!! | |
| 532 MockRead(SYNCHRONOUS, OK), | |
| 533 }; | |
| 534 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 535 arraysize(data_reads)); | |
| 536 EXPECT_EQ(OK, out.rv); | |
| 537 EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line); | |
| 538 EXPECT_EQ("", out.response_data); | |
| 539 } | |
| 540 | |
| 541 // A simple request using chunked encoding with some extra data after. | |
| 542 // (Like might be seen in a pipelined response.) | |
| 543 TEST_F(HttpNetworkTransactionTest, ChunkedEncoding) { | |
| 544 MockRead data_reads[] = { | |
| 545 MockRead("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"), | |
| 546 MockRead("5\r\nHello\r\n"), | |
| 547 MockRead("1\r\n"), | |
| 548 MockRead(" \r\n"), | |
| 549 MockRead("5\r\nworld\r\n"), | |
| 550 MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"), | |
| 551 MockRead(SYNCHRONOUS, OK), | |
| 552 }; | |
| 553 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 554 arraysize(data_reads)); | |
| 555 EXPECT_EQ(OK, out.rv); | |
| 556 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
| 557 EXPECT_EQ("Hello world", out.response_data); | |
| 558 } | |
| 559 | |
| 560 // Next tests deal with http://crbug.com/56344. | |
| 561 | |
| 562 TEST_F(HttpNetworkTransactionTest, | |
| 563 MultipleContentLengthHeadersNoTransferEncoding) { | |
| 564 MockRead data_reads[] = { | |
| 565 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 566 MockRead("Content-Length: 10\r\n"), | |
| 567 MockRead("Content-Length: 5\r\n\r\n"), | |
| 568 }; | |
| 569 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 570 arraysize(data_reads)); | |
| 571 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv); | |
| 572 } | |
| 573 | |
| 574 TEST_F(HttpNetworkTransactionTest, | |
| 575 DuplicateContentLengthHeadersNoTransferEncoding) { | |
| 576 MockRead data_reads[] = { | |
| 577 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 578 MockRead("Content-Length: 5\r\n"), | |
| 579 MockRead("Content-Length: 5\r\n\r\n"), | |
| 580 MockRead("Hello"), | |
| 581 }; | |
| 582 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 583 arraysize(data_reads)); | |
| 584 EXPECT_EQ(OK, out.rv); | |
| 585 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
| 586 EXPECT_EQ("Hello", out.response_data); | |
| 587 } | |
| 588 | |
| 589 TEST_F(HttpNetworkTransactionTest, | |
| 590 ComplexContentLengthHeadersNoTransferEncoding) { | |
| 591 // More than 2 dupes. | |
| 592 { | |
| 593 MockRead data_reads[] = { | |
| 594 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 595 MockRead("Content-Length: 5\r\n"), | |
| 596 MockRead("Content-Length: 5\r\n"), | |
| 597 MockRead("Content-Length: 5\r\n\r\n"), | |
| 598 MockRead("Hello"), | |
| 599 }; | |
| 600 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 601 arraysize(data_reads)); | |
| 602 EXPECT_EQ(OK, out.rv); | |
| 603 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
| 604 EXPECT_EQ("Hello", out.response_data); | |
| 605 } | |
| 606 // HTTP/1.0 | |
| 607 { | |
| 608 MockRead data_reads[] = { | |
| 609 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 610 MockRead("Content-Length: 5\r\n"), | |
| 611 MockRead("Content-Length: 5\r\n"), | |
| 612 MockRead("Content-Length: 5\r\n\r\n"), | |
| 613 MockRead("Hello"), | |
| 614 }; | |
| 615 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 616 arraysize(data_reads)); | |
| 617 EXPECT_EQ(OK, out.rv); | |
| 618 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); | |
| 619 EXPECT_EQ("Hello", out.response_data); | |
| 620 } | |
| 621 // 2 dupes and one mismatched. | |
| 622 { | |
| 623 MockRead data_reads[] = { | |
| 624 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 625 MockRead("Content-Length: 10\r\n"), | |
| 626 MockRead("Content-Length: 10\r\n"), | |
| 627 MockRead("Content-Length: 5\r\n\r\n"), | |
| 628 }; | |
| 629 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 630 arraysize(data_reads)); | |
| 631 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv); | |
| 632 } | |
| 633 } | |
| 634 | |
| 635 TEST_F(HttpNetworkTransactionTest, | |
| 636 MultipleContentLengthHeadersTransferEncoding) { | |
| 637 MockRead data_reads[] = { | |
| 638 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 639 MockRead("Content-Length: 666\r\n"), | |
| 640 MockRead("Content-Length: 1337\r\n"), | |
| 641 MockRead("Transfer-Encoding: chunked\r\n\r\n"), | |
| 642 MockRead("5\r\nHello\r\n"), | |
| 643 MockRead("1\r\n"), | |
| 644 MockRead(" \r\n"), | |
| 645 MockRead("5\r\nworld\r\n"), | |
| 646 MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"), | |
| 647 MockRead(SYNCHRONOUS, OK), | |
| 648 }; | |
| 649 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 650 arraysize(data_reads)); | |
| 651 EXPECT_EQ(OK, out.rv); | |
| 652 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
| 653 EXPECT_EQ("Hello world", out.response_data); | |
| 654 } | |
| 655 | |
| 656 // Next tests deal with http://crbug.com/98895. | |
| 657 | |
| 658 // Checks that a single Content-Disposition header results in no error. | |
| 659 TEST_F(HttpNetworkTransactionTest, SingleContentDispositionHeader) { | |
| 660 MockRead data_reads[] = { | |
| 661 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 662 MockRead("Content-Disposition: attachment;filename=\"salutations.txt\"r\n"), | |
| 663 MockRead("Content-Length: 5\r\n\r\n"), | |
| 664 MockRead("Hello"), | |
| 665 }; | |
| 666 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 667 arraysize(data_reads)); | |
| 668 EXPECT_EQ(OK, out.rv); | |
| 669 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
| 670 EXPECT_EQ("Hello", out.response_data); | |
| 671 } | |
| 672 | |
| 673 // Checks that two identical Content-Disposition headers result in an error. | |
| 674 TEST_F(HttpNetworkTransactionTest, | |
| 675 DuplicateIdenticalContentDispositionHeaders) { | |
| 676 MockRead data_reads[] = { | |
| 677 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 678 MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), | |
| 679 MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), | |
| 680 MockRead("Content-Length: 5\r\n\r\n"), | |
| 681 MockRead("Hello"), | |
| 682 }; | |
| 683 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 684 arraysize(data_reads)); | |
| 685 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION, out.rv); | |
| 686 } | |
| 687 | |
| 688 // Checks that two distinct Content-Disposition headers result in an error. | |
| 689 TEST_F(HttpNetworkTransactionTest, DuplicateDistinctContentDispositionHeaders) { | |
| 690 MockRead data_reads[] = { | |
| 691 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 692 MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), | |
| 693 MockRead("Content-Disposition: attachment;filename=\"hi.txt\"r\n"), | |
| 694 MockRead("Content-Length: 5\r\n\r\n"), | |
| 695 MockRead("Hello"), | |
| 696 }; | |
| 697 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 698 arraysize(data_reads)); | |
| 699 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION, out.rv); | |
| 700 } | |
| 701 | |
| 702 // Checks the behavior of a single Location header. | |
| 703 TEST_F(HttpNetworkTransactionTest, SingleLocationHeader) { | |
| 704 MockRead data_reads[] = { | |
| 705 MockRead("HTTP/1.1 302 Redirect\r\n"), | |
| 706 MockRead("Location: http://good.com/\r\n"), | |
| 707 MockRead("Content-Length: 0\r\n\r\n"), | |
| 708 MockRead(SYNCHRONOUS, OK), | |
| 709 }; | |
| 710 | |
| 711 HttpRequestInfo request; | |
| 712 request.method = "GET"; | |
| 713 request.url = GURL("http://redirect.com/"); | |
| 714 request.load_flags = 0; | |
| 715 | |
| 716 SessionDependencies session_deps; | |
| 717 scoped_ptr<HttpTransaction> trans( | |
| 718 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 719 | |
| 720 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 721 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 722 | |
| 723 TestCompletionCallback callback; | |
| 724 | |
| 725 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 726 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 727 | |
| 728 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 729 | |
| 730 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 731 ASSERT_TRUE(response != NULL && response->headers != NULL); | |
| 732 EXPECT_EQ("HTTP/1.1 302 Redirect", response->headers->GetStatusLine()); | |
| 733 std::string url; | |
| 734 EXPECT_TRUE(response->headers->IsRedirect(&url)); | |
| 735 EXPECT_EQ("http://good.com/", url); | |
| 736 } | |
| 737 | |
| 738 // Checks that two identical Location headers result in an error. | |
| 739 TEST_F(HttpNetworkTransactionTest, DuplicateIdenticalLocationHeaders) { | |
| 740 MockRead data_reads[] = { | |
| 741 MockRead("HTTP/1.1 302 Redirect\r\n"), | |
| 742 MockRead("Location: http://good.com/\r\n"), | |
| 743 MockRead("Location: http://good.com/\r\n"), | |
| 744 MockRead("Content-Length: 0\r\n\r\n"), | |
| 745 MockRead(SYNCHRONOUS, OK), | |
| 746 }; | |
| 747 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 748 arraysize(data_reads)); | |
| 749 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION, out.rv); | |
| 750 } | |
| 751 | |
| 752 // Checks that two distinct Location headers result in an error. | |
| 753 TEST_F(HttpNetworkTransactionTest, DuplicateDistinctLocationHeaders) { | |
| 754 MockRead data_reads[] = { | |
| 755 MockRead("HTTP/1.1 302 Redirect\r\n"), | |
| 756 MockRead("Location: http://good.com/\r\n"), | |
| 757 MockRead("Location: http://evil.com/\r\n"), | |
| 758 MockRead("Content-Length: 0\r\n\r\n"), | |
| 759 MockRead(SYNCHRONOUS, OK), | |
| 760 }; | |
| 761 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 762 arraysize(data_reads)); | |
| 763 EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION, out.rv); | |
| 764 } | |
| 765 | |
| 766 // Do a request using the HEAD method. Verify that we don't try to read the | |
| 767 // message body (since HEAD has none). | |
| 768 TEST_F(HttpNetworkTransactionTest, Head) { | |
| 769 HttpRequestInfo request; | |
| 770 request.method = "HEAD"; | |
| 771 request.url = GURL("http://www.google.com/"); | |
| 772 request.load_flags = 0; | |
| 773 | |
| 774 SessionDependencies session_deps; | |
| 775 scoped_ptr<HttpTransaction> trans( | |
| 776 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 777 | |
| 778 MockWrite data_writes1[] = { | |
| 779 MockWrite("HEAD / HTTP/1.1\r\n" | |
| 780 "Host: www.google.com\r\n" | |
| 781 "Connection: keep-alive\r\n" | |
| 782 "Content-Length: 0\r\n\r\n"), | |
| 783 }; | |
| 784 MockRead data_reads1[] = { | |
| 785 MockRead("HTTP/1.1 404 Not Found\r\n"), | |
| 786 MockRead("Server: Blah\r\n"), | |
| 787 MockRead("Content-Length: 1234\r\n\r\n"), | |
| 788 | |
| 789 // No response body because the test stops reading here. | |
| 790 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 791 }; | |
| 792 | |
| 793 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 794 data_writes1, arraysize(data_writes1)); | |
| 795 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 796 | |
| 797 TestCompletionCallback callback1; | |
| 798 | |
| 799 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 800 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 801 | |
| 802 rv = callback1.WaitForResult(); | |
| 803 EXPECT_EQ(OK, rv); | |
| 804 | |
| 805 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 806 ASSERT_TRUE(response != NULL); | |
| 807 | |
| 808 // Check that the headers got parsed. | |
| 809 EXPECT_TRUE(response->headers != NULL); | |
| 810 EXPECT_EQ(1234, response->headers->GetContentLength()); | |
| 811 EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine()); | |
| 812 | |
| 813 std::string server_header; | |
| 814 void* iter = NULL; | |
| 815 bool has_server_header = response->headers->EnumerateHeader( | |
| 816 &iter, "Server", &server_header); | |
| 817 EXPECT_TRUE(has_server_header); | |
| 818 EXPECT_EQ("Blah", server_header); | |
| 819 | |
| 820 // Reading should give EOF right away, since there is no message body | |
| 821 // (despite non-zero content-length). | |
| 822 std::string response_data; | |
| 823 rv = ReadTransaction(trans.get(), &response_data); | |
| 824 EXPECT_EQ(OK, rv); | |
| 825 EXPECT_EQ("", response_data); | |
| 826 } | |
| 827 | |
| 828 TEST_F(HttpNetworkTransactionTest, ReuseConnection) { | |
| 829 SessionDependencies session_deps; | |
| 830 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 831 | |
| 832 MockRead data_reads[] = { | |
| 833 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
| 834 MockRead("hello"), | |
| 835 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
| 836 MockRead("world"), | |
| 837 MockRead(SYNCHRONOUS, OK), | |
| 838 }; | |
| 839 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 840 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 841 | |
| 842 const char* const kExpectedResponseData[] = { | |
| 843 "hello", "world" | |
| 844 }; | |
| 845 | |
| 846 for (int i = 0; i < 2; ++i) { | |
| 847 HttpRequestInfo request; | |
| 848 request.method = "GET"; | |
| 849 request.url = GURL("http://www.google.com/"); | |
| 850 request.load_flags = 0; | |
| 851 | |
| 852 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 853 | |
| 854 TestCompletionCallback callback; | |
| 855 | |
| 856 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 857 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 858 | |
| 859 rv = callback.WaitForResult(); | |
| 860 EXPECT_EQ(OK, rv); | |
| 861 | |
| 862 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 863 ASSERT_TRUE(response != NULL); | |
| 864 | |
| 865 EXPECT_TRUE(response->headers != NULL); | |
| 866 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 867 | |
| 868 std::string response_data; | |
| 869 rv = ReadTransaction(trans.get(), &response_data); | |
| 870 EXPECT_EQ(OK, rv); | |
| 871 EXPECT_EQ(kExpectedResponseData[i], response_data); | |
| 872 } | |
| 873 } | |
| 874 | |
| 875 TEST_F(HttpNetworkTransactionTest, Ignores100) { | |
| 876 HttpRequestInfo request; | |
| 877 request.method = "POST"; | |
| 878 request.url = GURL("http://www.foo.com/"); | |
| 879 request.upload_data = new UploadData; | |
| 880 request.upload_data->AppendBytes("foo", 3); | |
| 881 request.load_flags = 0; | |
| 882 | |
| 883 SessionDependencies session_deps; | |
| 884 scoped_ptr<HttpTransaction> trans( | |
| 885 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 886 | |
| 887 MockRead data_reads[] = { | |
| 888 MockRead("HTTP/1.0 100 Continue\r\n\r\n"), | |
| 889 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
| 890 MockRead("hello world"), | |
| 891 MockRead(SYNCHRONOUS, OK), | |
| 892 }; | |
| 893 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 894 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 895 | |
| 896 TestCompletionCallback callback; | |
| 897 | |
| 898 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 899 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 900 | |
| 901 rv = callback.WaitForResult(); | |
| 902 EXPECT_EQ(OK, rv); | |
| 903 | |
| 904 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 905 ASSERT_TRUE(response != NULL); | |
| 906 | |
| 907 EXPECT_TRUE(response->headers != NULL); | |
| 908 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
| 909 | |
| 910 std::string response_data; | |
| 911 rv = ReadTransaction(trans.get(), &response_data); | |
| 912 EXPECT_EQ(OK, rv); | |
| 913 EXPECT_EQ("hello world", response_data); | |
| 914 } | |
| 915 | |
| 916 // This test is almost the same as Ignores100 above, but the response contains | |
| 917 // a 102 instead of a 100. Also, instead of HTTP/1.0 the response is | |
| 918 // HTTP/1.1 and the two status headers are read in one read. | |
| 919 TEST_F(HttpNetworkTransactionTest, Ignores1xx) { | |
| 920 HttpRequestInfo request; | |
| 921 request.method = "GET"; | |
| 922 request.url = GURL("http://www.foo.com/"); | |
| 923 request.load_flags = 0; | |
| 924 | |
| 925 SessionDependencies session_deps; | |
| 926 scoped_ptr<HttpTransaction> trans( | |
| 927 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 928 | |
| 929 MockRead data_reads[] = { | |
| 930 MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n" | |
| 931 "HTTP/1.1 200 OK\r\n\r\n"), | |
| 932 MockRead("hello world"), | |
| 933 MockRead(SYNCHRONOUS, OK), | |
| 934 }; | |
| 935 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 936 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 937 | |
| 938 TestCompletionCallback callback; | |
| 939 | |
| 940 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 941 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 942 | |
| 943 rv = callback.WaitForResult(); | |
| 944 EXPECT_EQ(OK, rv); | |
| 945 | |
| 946 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 947 ASSERT_TRUE(response != NULL); | |
| 948 | |
| 949 EXPECT_TRUE(response->headers != NULL); | |
| 950 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 951 | |
| 952 std::string response_data; | |
| 953 rv = ReadTransaction(trans.get(), &response_data); | |
| 954 EXPECT_EQ(OK, rv); | |
| 955 EXPECT_EQ("hello world", response_data); | |
| 956 } | |
| 957 | |
| 958 TEST_F(HttpNetworkTransactionTest, Incomplete100ThenEOF) { | |
| 959 HttpRequestInfo request; | |
| 960 request.method = "POST"; | |
| 961 request.url = GURL("http://www.foo.com/"); | |
| 962 request.load_flags = 0; | |
| 963 | |
| 964 SessionDependencies session_deps; | |
| 965 scoped_ptr<HttpTransaction> trans( | |
| 966 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 967 | |
| 968 MockRead data_reads[] = { | |
| 969 MockRead(SYNCHRONOUS, "HTTP/1.0 100 Continue\r\n"), | |
| 970 MockRead(ASYNC, 0), | |
| 971 }; | |
| 972 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 973 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 974 | |
| 975 TestCompletionCallback callback; | |
| 976 | |
| 977 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 978 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 979 | |
| 980 rv = callback.WaitForResult(); | |
| 981 EXPECT_EQ(OK, rv); | |
| 982 | |
| 983 std::string response_data; | |
| 984 rv = ReadTransaction(trans.get(), &response_data); | |
| 985 EXPECT_EQ(OK, rv); | |
| 986 EXPECT_EQ("", response_data); | |
| 987 } | |
| 988 | |
| 989 TEST_F(HttpNetworkTransactionTest, EmptyResponse) { | |
| 990 HttpRequestInfo request; | |
| 991 request.method = "POST"; | |
| 992 request.url = GURL("http://www.foo.com/"); | |
| 993 request.load_flags = 0; | |
| 994 | |
| 995 SessionDependencies session_deps; | |
| 996 scoped_ptr<HttpTransaction> trans( | |
| 997 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 998 | |
| 999 MockRead data_reads[] = { | |
| 1000 MockRead(ASYNC, 0), | |
| 1001 }; | |
| 1002 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 1003 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 1004 | |
| 1005 TestCompletionCallback callback; | |
| 1006 | |
| 1007 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1008 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1009 | |
| 1010 rv = callback.WaitForResult(); | |
| 1011 EXPECT_EQ(ERR_EMPTY_RESPONSE, rv); | |
| 1012 } | |
| 1013 | |
| 1014 void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest( | |
| 1015 const MockWrite* write_failure, | |
| 1016 const MockRead* read_failure) { | |
| 1017 HttpRequestInfo request; | |
| 1018 request.method = "GET"; | |
| 1019 request.url = GURL("http://www.foo.com/"); | |
| 1020 request.load_flags = 0; | |
| 1021 | |
| 1022 SessionDependencies session_deps; | |
| 1023 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 1024 | |
| 1025 // Written data for successfully sending both requests. | |
| 1026 MockWrite data1_writes[] = { | |
| 1027 MockWrite("GET / HTTP/1.1\r\n" | |
| 1028 "Host: www.foo.com\r\n" | |
| 1029 "Connection: keep-alive\r\n\r\n"), | |
| 1030 MockWrite("GET / HTTP/1.1\r\n" | |
| 1031 "Host: www.foo.com\r\n" | |
| 1032 "Connection: keep-alive\r\n\r\n") | |
| 1033 }; | |
| 1034 | |
| 1035 // Read results for the first request. | |
| 1036 MockRead data1_reads[] = { | |
| 1037 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
| 1038 MockRead("hello"), | |
| 1039 MockRead(ASYNC, OK), | |
| 1040 }; | |
| 1041 | |
| 1042 if (write_failure) { | |
| 1043 ASSERT_TRUE(!read_failure); | |
| 1044 data1_writes[1] = *write_failure; | |
| 1045 } else { | |
| 1046 ASSERT_TRUE(read_failure); | |
| 1047 data1_reads[2] = *read_failure; | |
| 1048 } | |
| 1049 | |
| 1050 StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), | |
| 1051 data1_writes, arraysize(data1_writes)); | |
| 1052 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 1053 | |
| 1054 MockRead data2_reads[] = { | |
| 1055 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
| 1056 MockRead("world"), | |
| 1057 MockRead(ASYNC, OK), | |
| 1058 }; | |
| 1059 StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0); | |
| 1060 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 1061 | |
| 1062 const char* kExpectedResponseData[] = { | |
| 1063 "hello", "world" | |
| 1064 }; | |
| 1065 | |
| 1066 for (int i = 0; i < 2; ++i) { | |
| 1067 TestCompletionCallback callback; | |
| 1068 | |
| 1069 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 1070 | |
| 1071 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1072 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1073 | |
| 1074 rv = callback.WaitForResult(); | |
| 1075 EXPECT_EQ(OK, rv); | |
| 1076 | |
| 1077 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1078 ASSERT_TRUE(response != NULL); | |
| 1079 | |
| 1080 EXPECT_TRUE(response->headers != NULL); | |
| 1081 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 1082 | |
| 1083 std::string response_data; | |
| 1084 rv = ReadTransaction(trans.get(), &response_data); | |
| 1085 EXPECT_EQ(OK, rv); | |
| 1086 EXPECT_EQ(kExpectedResponseData[i], response_data); | |
| 1087 } | |
| 1088 } | |
| 1089 | |
| 1090 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionNotConnectedOnWrite) { | |
| 1091 MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED); | |
| 1092 KeepAliveConnectionResendRequestTest(&write_failure, NULL); | |
| 1093 } | |
| 1094 | |
| 1095 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) { | |
| 1096 MockRead read_failure(ASYNC, ERR_CONNECTION_RESET); | |
| 1097 KeepAliveConnectionResendRequestTest(NULL, &read_failure); | |
| 1098 } | |
| 1099 | |
| 1100 TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) { | |
| 1101 MockRead read_failure(SYNCHRONOUS, OK); // EOF | |
| 1102 KeepAliveConnectionResendRequestTest(NULL, &read_failure); | |
| 1103 } | |
| 1104 | |
| 1105 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) { | |
| 1106 HttpRequestInfo request; | |
| 1107 request.method = "GET"; | |
| 1108 request.url = GURL("http://www.google.com/"); | |
| 1109 request.load_flags = 0; | |
| 1110 | |
| 1111 SessionDependencies session_deps; | |
| 1112 scoped_ptr<HttpTransaction> trans( | |
| 1113 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 1114 | |
| 1115 MockRead data_reads[] = { | |
| 1116 MockRead(ASYNC, ERR_CONNECTION_RESET), | |
| 1117 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used | |
| 1118 MockRead("hello world"), | |
| 1119 MockRead(SYNCHRONOUS, OK), | |
| 1120 }; | |
| 1121 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 1122 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 1123 | |
| 1124 TestCompletionCallback callback; | |
| 1125 | |
| 1126 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1127 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1128 | |
| 1129 rv = callback.WaitForResult(); | |
| 1130 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 1131 | |
| 1132 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1133 EXPECT_TRUE(response == NULL); | |
| 1134 } | |
| 1135 | |
| 1136 // What do various browsers do when the server closes a non-keepalive | |
| 1137 // connection without sending any response header or body? | |
| 1138 // | |
| 1139 // IE7: error page | |
| 1140 // Safari 3.1.2 (Windows): error page | |
| 1141 // Firefox 3.0.1: blank page | |
| 1142 // Opera 9.52: after five attempts, blank page | |
| 1143 // Us with WinHTTP: error page (ERR_INVALID_RESPONSE) | |
| 1144 // Us: error page (EMPTY_RESPONSE) | |
| 1145 TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) { | |
| 1146 MockRead data_reads[] = { | |
| 1147 MockRead(SYNCHRONOUS, OK), // EOF | |
| 1148 MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used | |
| 1149 MockRead("hello world"), | |
| 1150 MockRead(SYNCHRONOUS, OK), | |
| 1151 }; | |
| 1152 SimpleGetHelperResult out = SimpleGetHelper(data_reads, | |
| 1153 arraysize(data_reads)); | |
| 1154 EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv); | |
| 1155 } | |
| 1156 | |
| 1157 // Test that we correctly reuse a keep-alive connection after not explicitly | |
| 1158 // reading the body. | |
| 1159 TEST_F(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) { | |
| 1160 HttpRequestInfo request; | |
| 1161 request.method = "GET"; | |
| 1162 request.url = GURL("http://www.foo.com/"); | |
| 1163 request.load_flags = 0; | |
| 1164 | |
| 1165 SessionDependencies session_deps; | |
| 1166 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 1167 | |
| 1168 // Note that because all these reads happen in the same | |
| 1169 // StaticSocketDataProvider, it shows that the same socket is being reused for | |
| 1170 // all transactions. | |
| 1171 MockRead data1_reads[] = { | |
| 1172 MockRead("HTTP/1.1 204 No Content\r\n\r\n"), | |
| 1173 MockRead("HTTP/1.1 205 Reset Content\r\n\r\n"), | |
| 1174 MockRead("HTTP/1.1 304 Not Modified\r\n\r\n"), | |
| 1175 MockRead("HTTP/1.1 302 Found\r\n" | |
| 1176 "Content-Length: 0\r\n\r\n"), | |
| 1177 MockRead("HTTP/1.1 302 Found\r\n" | |
| 1178 "Content-Length: 5\r\n\r\n" | |
| 1179 "hello"), | |
| 1180 MockRead("HTTP/1.1 301 Moved Permanently\r\n" | |
| 1181 "Content-Length: 0\r\n\r\n"), | |
| 1182 MockRead("HTTP/1.1 301 Moved Permanently\r\n" | |
| 1183 "Content-Length: 5\r\n\r\n" | |
| 1184 "hello"), | |
| 1185 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), | |
| 1186 MockRead("hello"), | |
| 1187 }; | |
| 1188 StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), NULL, 0); | |
| 1189 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 1190 | |
| 1191 MockRead data2_reads[] = { | |
| 1192 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 1193 }; | |
| 1194 StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0); | |
| 1195 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 1196 | |
| 1197 const int kNumUnreadBodies = arraysize(data1_reads) - 2; | |
| 1198 std::string response_lines[kNumUnreadBodies]; | |
| 1199 | |
| 1200 for (size_t i = 0; i < arraysize(data1_reads) - 2; ++i) { | |
| 1201 TestCompletionCallback callback; | |
| 1202 | |
| 1203 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 1204 | |
| 1205 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1206 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1207 | |
| 1208 rv = callback.WaitForResult(); | |
| 1209 EXPECT_EQ(OK, rv); | |
| 1210 | |
| 1211 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1212 ASSERT_TRUE(response != NULL); | |
| 1213 | |
| 1214 ASSERT_TRUE(response->headers != NULL); | |
| 1215 response_lines[i] = response->headers->GetStatusLine(); | |
| 1216 | |
| 1217 // We intentionally don't read the response bodies. | |
| 1218 } | |
| 1219 | |
| 1220 const char* const kStatusLines[] = { | |
| 1221 "HTTP/1.1 204 No Content", | |
| 1222 "HTTP/1.1 205 Reset Content", | |
| 1223 "HTTP/1.1 304 Not Modified", | |
| 1224 "HTTP/1.1 302 Found", | |
| 1225 "HTTP/1.1 302 Found", | |
| 1226 "HTTP/1.1 301 Moved Permanently", | |
| 1227 "HTTP/1.1 301 Moved Permanently", | |
| 1228 }; | |
| 1229 | |
| 1230 COMPILE_ASSERT(kNumUnreadBodies == arraysize(kStatusLines), | |
| 1231 forgot_to_update_kStatusLines); | |
| 1232 | |
| 1233 for (int i = 0; i < kNumUnreadBodies; ++i) | |
| 1234 EXPECT_EQ(kStatusLines[i], response_lines[i]); | |
| 1235 | |
| 1236 TestCompletionCallback callback; | |
| 1237 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 1238 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1239 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1240 rv = callback.WaitForResult(); | |
| 1241 EXPECT_EQ(OK, rv); | |
| 1242 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1243 ASSERT_TRUE(response != NULL); | |
| 1244 ASSERT_TRUE(response->headers != NULL); | |
| 1245 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 1246 std::string response_data; | |
| 1247 rv = ReadTransaction(trans.get(), &response_data); | |
| 1248 EXPECT_EQ(OK, rv); | |
| 1249 EXPECT_EQ("hello", response_data); | |
| 1250 } | |
| 1251 | |
| 1252 // Test the request-challenge-retry sequence for basic auth. | |
| 1253 // (basic auth is the easiest to mock, because it has no randomness). | |
| 1254 TEST_F(HttpNetworkTransactionTest, BasicAuth) { | |
| 1255 HttpRequestInfo request; | |
| 1256 request.method = "GET"; | |
| 1257 request.url = GURL("http://www.google.com/"); | |
| 1258 request.load_flags = 0; | |
| 1259 | |
| 1260 SessionDependencies session_deps; | |
| 1261 scoped_ptr<HttpTransaction> trans( | |
| 1262 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 1263 | |
| 1264 MockWrite data_writes1[] = { | |
| 1265 MockWrite("GET / HTTP/1.1\r\n" | |
| 1266 "Host: www.google.com\r\n" | |
| 1267 "Connection: keep-alive\r\n\r\n"), | |
| 1268 }; | |
| 1269 | |
| 1270 MockRead data_reads1[] = { | |
| 1271 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 1272 // Give a couple authenticate options (only the middle one is actually | |
| 1273 // supported). | |
| 1274 MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed. | |
| 1275 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1276 MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), | |
| 1277 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1278 // Large content-length -- won't matter, as connection will be reset. | |
| 1279 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 1280 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 1281 }; | |
| 1282 | |
| 1283 // After calling trans->RestartWithAuth(), this is the request we should | |
| 1284 // be issuing -- the final header line contains the credentials. | |
| 1285 MockWrite data_writes2[] = { | |
| 1286 MockWrite("GET / HTTP/1.1\r\n" | |
| 1287 "Host: www.google.com\r\n" | |
| 1288 "Connection: keep-alive\r\n" | |
| 1289 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 1290 }; | |
| 1291 | |
| 1292 // Lastly, the server responds with the actual content. | |
| 1293 MockRead data_reads2[] = { | |
| 1294 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 1295 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1296 MockRead("Content-Length: 100\r\n\r\n"), | |
| 1297 MockRead(SYNCHRONOUS, OK), | |
| 1298 }; | |
| 1299 | |
| 1300 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 1301 data_writes1, arraysize(data_writes1)); | |
| 1302 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 1303 data_writes2, arraysize(data_writes2)); | |
| 1304 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 1305 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 1306 | |
| 1307 TestCompletionCallback callback1; | |
| 1308 | |
| 1309 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 1310 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1311 | |
| 1312 rv = callback1.WaitForResult(); | |
| 1313 EXPECT_EQ(OK, rv); | |
| 1314 | |
| 1315 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1316 ASSERT_TRUE(response != NULL); | |
| 1317 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 1318 | |
| 1319 TestCompletionCallback callback2; | |
| 1320 | |
| 1321 rv = trans->RestartWithAuth( | |
| 1322 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 1323 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1324 | |
| 1325 rv = callback2.WaitForResult(); | |
| 1326 EXPECT_EQ(OK, rv); | |
| 1327 | |
| 1328 response = trans->GetResponseInfo(); | |
| 1329 ASSERT_TRUE(response != NULL); | |
| 1330 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 1331 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 1332 } | |
| 1333 | |
| 1334 TEST_F(HttpNetworkTransactionTest, DoNotSendAuth) { | |
| 1335 HttpRequestInfo request; | |
| 1336 request.method = "GET"; | |
| 1337 request.url = GURL("http://www.google.com/"); | |
| 1338 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
| 1339 | |
| 1340 SessionDependencies session_deps; | |
| 1341 scoped_ptr<HttpTransaction> trans( | |
| 1342 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 1343 | |
| 1344 MockWrite data_writes[] = { | |
| 1345 MockWrite("GET / HTTP/1.1\r\n" | |
| 1346 "Host: www.google.com\r\n" | |
| 1347 "Connection: keep-alive\r\n\r\n"), | |
| 1348 }; | |
| 1349 | |
| 1350 MockRead data_reads[] = { | |
| 1351 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 1352 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1353 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1354 // Large content-length -- won't matter, as connection will be reset. | |
| 1355 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 1356 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 1357 }; | |
| 1358 | |
| 1359 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 1360 data_writes, arraysize(data_writes)); | |
| 1361 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 1362 TestCompletionCallback callback; | |
| 1363 | |
| 1364 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1365 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1366 | |
| 1367 rv = callback.WaitForResult(); | |
| 1368 EXPECT_EQ(0, rv); | |
| 1369 | |
| 1370 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1371 ASSERT_TRUE(response != NULL); | |
| 1372 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 1373 } | |
| 1374 | |
| 1375 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
| 1376 // connection. | |
| 1377 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) { | |
| 1378 HttpRequestInfo request; | |
| 1379 request.method = "GET"; | |
| 1380 request.url = GURL("http://www.google.com/"); | |
| 1381 request.load_flags = 0; | |
| 1382 | |
| 1383 SessionDependencies session_deps; | |
| 1384 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 1385 | |
| 1386 MockWrite data_writes1[] = { | |
| 1387 MockWrite("GET / HTTP/1.1\r\n" | |
| 1388 "Host: www.google.com\r\n" | |
| 1389 "Connection: keep-alive\r\n\r\n"), | |
| 1390 | |
| 1391 // After calling trans->RestartWithAuth(), this is the request we should | |
| 1392 // be issuing -- the final header line contains the credentials. | |
| 1393 MockWrite("GET / HTTP/1.1\r\n" | |
| 1394 "Host: www.google.com\r\n" | |
| 1395 "Connection: keep-alive\r\n" | |
| 1396 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 1397 }; | |
| 1398 | |
| 1399 MockRead data_reads1[] = { | |
| 1400 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
| 1401 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1402 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1403 MockRead("Content-Length: 14\r\n\r\n"), | |
| 1404 MockRead("Unauthorized\r\n"), | |
| 1405 | |
| 1406 // Lastly, the server responds with the actual content. | |
| 1407 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 1408 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1409 MockRead("Content-Length: 5\r\n\r\n"), | |
| 1410 MockRead("Hello"), | |
| 1411 }; | |
| 1412 | |
| 1413 // If there is a regression where we disconnect a Keep-Alive | |
| 1414 // connection during an auth roundtrip, we'll end up reading this. | |
| 1415 MockRead data_reads2[] = { | |
| 1416 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 1417 }; | |
| 1418 | |
| 1419 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 1420 data_writes1, arraysize(data_writes1)); | |
| 1421 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 1422 NULL, 0); | |
| 1423 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 1424 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 1425 | |
| 1426 TestCompletionCallback callback1; | |
| 1427 | |
| 1428 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 1429 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 1430 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1431 | |
| 1432 rv = callback1.WaitForResult(); | |
| 1433 EXPECT_EQ(OK, rv); | |
| 1434 | |
| 1435 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1436 ASSERT_TRUE(response != NULL); | |
| 1437 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 1438 | |
| 1439 TestCompletionCallback callback2; | |
| 1440 | |
| 1441 rv = trans->RestartWithAuth( | |
| 1442 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 1443 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1444 | |
| 1445 rv = callback2.WaitForResult(); | |
| 1446 EXPECT_EQ(OK, rv); | |
| 1447 | |
| 1448 response = trans->GetResponseInfo(); | |
| 1449 ASSERT_TRUE(response != NULL); | |
| 1450 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 1451 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 1452 } | |
| 1453 | |
| 1454 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
| 1455 // connection and with no response body to drain. | |
| 1456 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) { | |
| 1457 HttpRequestInfo request; | |
| 1458 request.method = "GET"; | |
| 1459 request.url = GURL("http://www.google.com/"); | |
| 1460 request.load_flags = 0; | |
| 1461 | |
| 1462 SessionDependencies session_deps; | |
| 1463 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 1464 | |
| 1465 MockWrite data_writes1[] = { | |
| 1466 MockWrite("GET / HTTP/1.1\r\n" | |
| 1467 "Host: www.google.com\r\n" | |
| 1468 "Connection: keep-alive\r\n\r\n"), | |
| 1469 | |
| 1470 // After calling trans->RestartWithAuth(), this is the request we should | |
| 1471 // be issuing -- the final header line contains the credentials. | |
| 1472 MockWrite("GET / HTTP/1.1\r\n" | |
| 1473 "Host: www.google.com\r\n" | |
| 1474 "Connection: keep-alive\r\n" | |
| 1475 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 1476 }; | |
| 1477 | |
| 1478 MockRead data_reads1[] = { | |
| 1479 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
| 1480 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1481 MockRead("Content-Length: 0\r\n\r\n"), // No response body. | |
| 1482 | |
| 1483 // Lastly, the server responds with the actual content. | |
| 1484 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 1485 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1486 MockRead("Content-Length: 5\r\n\r\n"), | |
| 1487 MockRead("hello"), | |
| 1488 }; | |
| 1489 | |
| 1490 // An incorrect reconnect would cause this to be read. | |
| 1491 MockRead data_reads2[] = { | |
| 1492 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 1493 }; | |
| 1494 | |
| 1495 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 1496 data_writes1, arraysize(data_writes1)); | |
| 1497 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 1498 NULL, 0); | |
| 1499 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 1500 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 1501 | |
| 1502 TestCompletionCallback callback1; | |
| 1503 | |
| 1504 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 1505 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 1506 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1507 | |
| 1508 rv = callback1.WaitForResult(); | |
| 1509 EXPECT_EQ(OK, rv); | |
| 1510 | |
| 1511 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1512 ASSERT_TRUE(response != NULL); | |
| 1513 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 1514 | |
| 1515 TestCompletionCallback callback2; | |
| 1516 | |
| 1517 rv = trans->RestartWithAuth( | |
| 1518 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 1519 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1520 | |
| 1521 rv = callback2.WaitForResult(); | |
| 1522 EXPECT_EQ(OK, rv); | |
| 1523 | |
| 1524 response = trans->GetResponseInfo(); | |
| 1525 ASSERT_TRUE(response != NULL); | |
| 1526 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 1527 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 1528 } | |
| 1529 | |
| 1530 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
| 1531 // connection and with a large response body to drain. | |
| 1532 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) { | |
| 1533 HttpRequestInfo request; | |
| 1534 request.method = "GET"; | |
| 1535 request.url = GURL("http://www.google.com/"); | |
| 1536 request.load_flags = 0; | |
| 1537 | |
| 1538 SessionDependencies session_deps; | |
| 1539 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 1540 | |
| 1541 MockWrite data_writes1[] = { | |
| 1542 MockWrite("GET / HTTP/1.1\r\n" | |
| 1543 "Host: www.google.com\r\n" | |
| 1544 "Connection: keep-alive\r\n\r\n"), | |
| 1545 | |
| 1546 // After calling trans->RestartWithAuth(), this is the request we should | |
| 1547 // be issuing -- the final header line contains the credentials. | |
| 1548 MockWrite("GET / HTTP/1.1\r\n" | |
| 1549 "Host: www.google.com\r\n" | |
| 1550 "Connection: keep-alive\r\n" | |
| 1551 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 1552 }; | |
| 1553 | |
| 1554 // Respond with 5 kb of response body. | |
| 1555 std::string large_body_string("Unauthorized"); | |
| 1556 large_body_string.append(5 * 1024, ' '); | |
| 1557 large_body_string.append("\r\n"); | |
| 1558 | |
| 1559 MockRead data_reads1[] = { | |
| 1560 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
| 1561 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1562 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1563 // 5134 = 12 + 5 * 1024 + 2 | |
| 1564 MockRead("Content-Length: 5134\r\n\r\n"), | |
| 1565 MockRead(ASYNC, large_body_string.data(), large_body_string.size()), | |
| 1566 | |
| 1567 // Lastly, the server responds with the actual content. | |
| 1568 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 1569 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1570 MockRead("Content-Length: 5\r\n\r\n"), | |
| 1571 MockRead("hello"), | |
| 1572 }; | |
| 1573 | |
| 1574 // An incorrect reconnect would cause this to be read. | |
| 1575 MockRead data_reads2[] = { | |
| 1576 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 1577 }; | |
| 1578 | |
| 1579 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 1580 data_writes1, arraysize(data_writes1)); | |
| 1581 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 1582 NULL, 0); | |
| 1583 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 1584 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 1585 | |
| 1586 TestCompletionCallback callback1; | |
| 1587 | |
| 1588 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 1589 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 1590 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1591 | |
| 1592 rv = callback1.WaitForResult(); | |
| 1593 EXPECT_EQ(OK, rv); | |
| 1594 | |
| 1595 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1596 ASSERT_TRUE(response != NULL); | |
| 1597 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 1598 | |
| 1599 TestCompletionCallback callback2; | |
| 1600 | |
| 1601 rv = trans->RestartWithAuth( | |
| 1602 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 1603 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1604 | |
| 1605 rv = callback2.WaitForResult(); | |
| 1606 EXPECT_EQ(OK, rv); | |
| 1607 | |
| 1608 response = trans->GetResponseInfo(); | |
| 1609 ASSERT_TRUE(response != NULL); | |
| 1610 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 1611 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 1612 } | |
| 1613 | |
| 1614 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
| 1615 // connection, but the server gets impatient and closes the connection. | |
| 1616 TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) { | |
| 1617 HttpRequestInfo request; | |
| 1618 request.method = "GET"; | |
| 1619 request.url = GURL("http://www.google.com/"); | |
| 1620 request.load_flags = 0; | |
| 1621 | |
| 1622 SessionDependencies session_deps; | |
| 1623 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 1624 | |
| 1625 MockWrite data_writes1[] = { | |
| 1626 MockWrite("GET / HTTP/1.1\r\n" | |
| 1627 "Host: www.google.com\r\n" | |
| 1628 "Connection: keep-alive\r\n\r\n"), | |
| 1629 // This simulates the seemingly successful write to a closed connection | |
| 1630 // if the bug is not fixed. | |
| 1631 MockWrite("GET / HTTP/1.1\r\n" | |
| 1632 "Host: www.google.com\r\n" | |
| 1633 "Connection: keep-alive\r\n" | |
| 1634 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 1635 }; | |
| 1636 | |
| 1637 MockRead data_reads1[] = { | |
| 1638 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
| 1639 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1640 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1641 MockRead("Content-Length: 14\r\n\r\n"), | |
| 1642 // Tell MockTCPClientSocket to simulate the server closing the connection. | |
| 1643 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 1644 MockRead("Unauthorized\r\n"), | |
| 1645 MockRead(SYNCHRONOUS, OK), // The server closes the connection. | |
| 1646 }; | |
| 1647 | |
| 1648 // After calling trans->RestartWithAuth(), this is the request we should | |
| 1649 // be issuing -- the final header line contains the credentials. | |
| 1650 MockWrite data_writes2[] = { | |
| 1651 MockWrite("GET / HTTP/1.1\r\n" | |
| 1652 "Host: www.google.com\r\n" | |
| 1653 "Connection: keep-alive\r\n" | |
| 1654 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 1655 }; | |
| 1656 | |
| 1657 // Lastly, the server responds with the actual content. | |
| 1658 MockRead data_reads2[] = { | |
| 1659 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 1660 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1661 MockRead("Content-Length: 5\r\n\r\n"), | |
| 1662 MockRead("hello"), | |
| 1663 }; | |
| 1664 | |
| 1665 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 1666 data_writes1, arraysize(data_writes1)); | |
| 1667 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 1668 data_writes2, arraysize(data_writes2)); | |
| 1669 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 1670 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 1671 | |
| 1672 TestCompletionCallback callback1; | |
| 1673 | |
| 1674 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 1675 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 1676 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1677 | |
| 1678 rv = callback1.WaitForResult(); | |
| 1679 EXPECT_EQ(OK, rv); | |
| 1680 | |
| 1681 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1682 ASSERT_TRUE(response != NULL); | |
| 1683 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 1684 | |
| 1685 TestCompletionCallback callback2; | |
| 1686 | |
| 1687 rv = trans->RestartWithAuth( | |
| 1688 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 1689 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1690 | |
| 1691 rv = callback2.WaitForResult(); | |
| 1692 EXPECT_EQ(OK, rv); | |
| 1693 | |
| 1694 response = trans->GetResponseInfo(); | |
| 1695 ASSERT_TRUE(response != NULL); | |
| 1696 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 1697 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 1698 } | |
| 1699 | |
| 1700 // Test the request-challenge-retry sequence for basic auth, over a connection | |
| 1701 // that requires a restart when setting up an SSL tunnel. | |
| 1702 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAlive) { | |
| 1703 HttpRequestInfo request; | |
| 1704 request.method = "GET"; | |
| 1705 request.url = GURL("https://www.google.com/"); | |
| 1706 // when the no authentication data flag is set. | |
| 1707 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
| 1708 | |
| 1709 // Configure against proxy server "myproxy:70". | |
| 1710 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 1711 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 1712 session_deps.net_log = log.bound().net_log(); | |
| 1713 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 1714 | |
| 1715 // Since we have proxy, should try to establish tunnel. | |
| 1716 MockWrite data_writes1[] = { | |
| 1717 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 1718 "Host: www.google.com\r\n" | |
| 1719 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 1720 | |
| 1721 // After calling trans->RestartWithAuth(), this is the request we should | |
| 1722 // be issuing -- the final header line contains the credentials. | |
| 1723 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 1724 "Host: www.google.com\r\n" | |
| 1725 "Proxy-Connection: keep-alive\r\n" | |
| 1726 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 1727 | |
| 1728 MockWrite("GET / HTTP/1.1\r\n" | |
| 1729 "Host: www.google.com\r\n" | |
| 1730 "Connection: keep-alive\r\n\r\n"), | |
| 1731 }; | |
| 1732 | |
| 1733 // The proxy responds to the connect with a 407, using a persistent | |
| 1734 // connection. | |
| 1735 MockRead data_reads1[] = { | |
| 1736 // No credentials. | |
| 1737 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 1738 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1739 MockRead("Proxy-Connection: close\r\n\r\n"), | |
| 1740 | |
| 1741 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 1742 | |
| 1743 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 1744 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 1745 MockRead("Content-Length: 5\r\n\r\n"), | |
| 1746 MockRead(SYNCHRONOUS, "hello"), | |
| 1747 }; | |
| 1748 | |
| 1749 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 1750 data_writes1, arraysize(data_writes1)); | |
| 1751 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 1752 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 1753 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 1754 | |
| 1755 TestCompletionCallback callback1; | |
| 1756 | |
| 1757 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 1758 | |
| 1759 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 1760 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1761 | |
| 1762 rv = callback1.WaitForResult(); | |
| 1763 EXPECT_EQ(OK, rv); | |
| 1764 net::CapturingNetLog::EntryList entries; | |
| 1765 log.GetEntries(&entries); | |
| 1766 size_t pos = ExpectLogContainsSomewhere( | |
| 1767 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 1768 NetLog::PHASE_NONE); | |
| 1769 ExpectLogContainsSomewhere( | |
| 1770 entries, pos, | |
| 1771 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 1772 NetLog::PHASE_NONE); | |
| 1773 | |
| 1774 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1775 ASSERT_TRUE(response != NULL); | |
| 1776 ASSERT_FALSE(response->headers == NULL); | |
| 1777 EXPECT_EQ(407, response->headers->response_code()); | |
| 1778 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 1779 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 1780 | |
| 1781 TestCompletionCallback callback2; | |
| 1782 | |
| 1783 rv = trans->RestartWithAuth( | |
| 1784 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 1785 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1786 | |
| 1787 rv = callback2.WaitForResult(); | |
| 1788 EXPECT_EQ(OK, rv); | |
| 1789 | |
| 1790 response = trans->GetResponseInfo(); | |
| 1791 ASSERT_TRUE(response != NULL); | |
| 1792 | |
| 1793 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 1794 EXPECT_EQ(200, response->headers->response_code()); | |
| 1795 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 1796 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 1797 | |
| 1798 // The password prompt info should not be set. | |
| 1799 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 1800 | |
| 1801 trans.reset(); | |
| 1802 session->CloseAllConnections(); | |
| 1803 } | |
| 1804 | |
| 1805 // Test the request-challenge-retry sequence for basic auth, over a keep-alive | |
| 1806 // proxy connection, when setting up an SSL tunnel. | |
| 1807 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAlive) { | |
| 1808 HttpRequestInfo request; | |
| 1809 request.method = "GET"; | |
| 1810 request.url = GURL("https://www.google.com/"); | |
| 1811 // Ensure that proxy authentication is attempted even | |
| 1812 // when the no authentication data flag is set. | |
| 1813 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
| 1814 | |
| 1815 // Configure against proxy server "myproxy:70". | |
| 1816 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 1817 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 1818 session_deps.net_log = log.bound().net_log(); | |
| 1819 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 1820 | |
| 1821 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 1822 | |
| 1823 // Since we have proxy, should try to establish tunnel. | |
| 1824 MockWrite data_writes1[] = { | |
| 1825 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 1826 "Host: www.google.com\r\n" | |
| 1827 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 1828 | |
| 1829 // After calling trans->RestartWithAuth(), this is the request we should | |
| 1830 // be issuing -- the final header line contains the credentials. | |
| 1831 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 1832 "Host: www.google.com\r\n" | |
| 1833 "Proxy-Connection: keep-alive\r\n" | |
| 1834 "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), | |
| 1835 }; | |
| 1836 | |
| 1837 // The proxy responds to the connect with a 407, using a persistent | |
| 1838 // connection. | |
| 1839 MockRead data_reads1[] = { | |
| 1840 // No credentials. | |
| 1841 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 1842 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1843 MockRead("Content-Length: 10\r\n\r\n"), | |
| 1844 MockRead("0123456789"), | |
| 1845 | |
| 1846 // Wrong credentials (wrong password). | |
| 1847 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 1848 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1849 MockRead("Content-Length: 10\r\n\r\n"), | |
| 1850 // No response body because the test stops reading here. | |
| 1851 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 1852 }; | |
| 1853 | |
| 1854 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 1855 data_writes1, arraysize(data_writes1)); | |
| 1856 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 1857 | |
| 1858 TestCompletionCallback callback1; | |
| 1859 | |
| 1860 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 1861 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1862 | |
| 1863 rv = callback1.WaitForResult(); | |
| 1864 EXPECT_EQ(OK, rv); | |
| 1865 net::CapturingNetLog::EntryList entries; | |
| 1866 log.GetEntries(&entries); | |
| 1867 size_t pos = ExpectLogContainsSomewhere( | |
| 1868 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 1869 NetLog::PHASE_NONE); | |
| 1870 ExpectLogContainsSomewhere( | |
| 1871 entries, pos, | |
| 1872 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 1873 NetLog::PHASE_NONE); | |
| 1874 | |
| 1875 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1876 ASSERT_TRUE(response != NULL); | |
| 1877 ASSERT_FALSE(response->headers == NULL); | |
| 1878 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 1879 EXPECT_EQ(407, response->headers->response_code()); | |
| 1880 EXPECT_EQ(10, response->headers->GetContentLength()); | |
| 1881 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 1882 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 1883 | |
| 1884 TestCompletionCallback callback2; | |
| 1885 | |
| 1886 // Wrong password (should be "bar"). | |
| 1887 rv = trans->RestartWithAuth( | |
| 1888 AuthCredentials(kFoo, kBaz), callback2.callback()); | |
| 1889 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1890 | |
| 1891 rv = callback2.WaitForResult(); | |
| 1892 EXPECT_EQ(OK, rv); | |
| 1893 | |
| 1894 response = trans->GetResponseInfo(); | |
| 1895 ASSERT_TRUE(response != NULL); | |
| 1896 ASSERT_FALSE(response->headers == NULL); | |
| 1897 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 1898 EXPECT_EQ(407, response->headers->response_code()); | |
| 1899 EXPECT_EQ(10, response->headers->GetContentLength()); | |
| 1900 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 1901 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 1902 | |
| 1903 // Flush the idle socket before the NetLog and HttpNetworkTransaction go | |
| 1904 // out of scope. | |
| 1905 session->CloseAllConnections(); | |
| 1906 } | |
| 1907 | |
| 1908 // Test that we don't read the response body when we fail to establish a tunnel, | |
| 1909 // even if the user cancels the proxy's auth attempt. | |
| 1910 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) { | |
| 1911 HttpRequestInfo request; | |
| 1912 request.method = "GET"; | |
| 1913 request.url = GURL("https://www.google.com/"); | |
| 1914 request.load_flags = 0; | |
| 1915 | |
| 1916 // Configure against proxy server "myproxy:70". | |
| 1917 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 1918 | |
| 1919 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 1920 | |
| 1921 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 1922 | |
| 1923 // Since we have proxy, should try to establish tunnel. | |
| 1924 MockWrite data_writes[] = { | |
| 1925 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 1926 "Host: www.google.com\r\n" | |
| 1927 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 1928 }; | |
| 1929 | |
| 1930 // The proxy responds to the connect with a 407. | |
| 1931 MockRead data_reads[] = { | |
| 1932 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 1933 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1934 MockRead("Content-Length: 10\r\n\r\n"), | |
| 1935 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 1936 }; | |
| 1937 | |
| 1938 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 1939 data_writes, arraysize(data_writes)); | |
| 1940 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 1941 | |
| 1942 TestCompletionCallback callback; | |
| 1943 | |
| 1944 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 1945 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 1946 | |
| 1947 rv = callback.WaitForResult(); | |
| 1948 EXPECT_EQ(OK, rv); | |
| 1949 | |
| 1950 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 1951 ASSERT_TRUE(response != NULL); | |
| 1952 | |
| 1953 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 1954 EXPECT_EQ(407, response->headers->response_code()); | |
| 1955 EXPECT_EQ(10, response->headers->GetContentLength()); | |
| 1956 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 1957 | |
| 1958 std::string response_data; | |
| 1959 rv = ReadTransaction(trans.get(), &response_data); | |
| 1960 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
| 1961 | |
| 1962 // Flush the idle socket before the HttpNetworkTransaction goes out of scope. | |
| 1963 session->CloseAllConnections(); | |
| 1964 } | |
| 1965 | |
| 1966 // Test when a server (non-proxy) returns a 407 (proxy-authenticate). | |
| 1967 // The request should fail with ERR_UNEXPECTED_PROXY_AUTH. | |
| 1968 TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) { | |
| 1969 HttpRequestInfo request; | |
| 1970 request.method = "GET"; | |
| 1971 request.url = GURL("http://www.google.com/"); | |
| 1972 request.load_flags = 0; | |
| 1973 | |
| 1974 // We are using a DIRECT connection (i.e. no proxy) for this session. | |
| 1975 SessionDependencies session_deps; | |
| 1976 scoped_ptr<HttpTransaction> trans( | |
| 1977 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 1978 | |
| 1979 MockWrite data_writes1[] = { | |
| 1980 MockWrite("GET / HTTP/1.1\r\n" | |
| 1981 "Host: www.google.com\r\n" | |
| 1982 "Connection: keep-alive\r\n\r\n"), | |
| 1983 }; | |
| 1984 | |
| 1985 MockRead data_reads1[] = { | |
| 1986 MockRead("HTTP/1.0 407 Proxy Auth required\r\n"), | |
| 1987 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 1988 // Large content-length -- won't matter, as connection will be reset. | |
| 1989 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 1990 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 1991 }; | |
| 1992 | |
| 1993 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 1994 data_writes1, arraysize(data_writes1)); | |
| 1995 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 1996 | |
| 1997 TestCompletionCallback callback; | |
| 1998 | |
| 1999 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 2000 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2001 | |
| 2002 rv = callback.WaitForResult(); | |
| 2003 EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); | |
| 2004 } | |
| 2005 | |
| 2006 // Tests when an HTTPS server (non-proxy) returns a 407 (proxy-authentication) | |
| 2007 // through a non-authenticating proxy. The request should fail with | |
| 2008 // ERR_UNEXPECTED_PROXY_AUTH. | |
| 2009 // Note that it is impossible to detect if an HTTP server returns a 407 through | |
| 2010 // a non-authenticating proxy - there is nothing to indicate whether the | |
| 2011 // response came from the proxy or the server, so it is treated as if the proxy | |
| 2012 // issued the challenge. | |
| 2013 TEST_F(HttpNetworkTransactionTest, HttpsServerRequestsProxyAuthThroughProxy) { | |
| 2014 HttpRequestInfo request; | |
| 2015 request.method = "GET"; | |
| 2016 request.url = GURL("https://www.google.com/"); | |
| 2017 | |
| 2018 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 2019 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 2020 session_deps.net_log = log.bound().net_log(); | |
| 2021 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 2022 | |
| 2023 // Since we have proxy, should try to establish tunnel. | |
| 2024 MockWrite data_writes1[] = { | |
| 2025 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 2026 "Host: www.google.com\r\n" | |
| 2027 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2028 | |
| 2029 MockWrite("GET / HTTP/1.1\r\n" | |
| 2030 "Host: www.google.com\r\n" | |
| 2031 "Connection: keep-alive\r\n\r\n"), | |
| 2032 }; | |
| 2033 | |
| 2034 MockRead data_reads1[] = { | |
| 2035 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 2036 | |
| 2037 MockRead("HTTP/1.1 407 Unauthorized\r\n"), | |
| 2038 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2039 MockRead("\r\n"), | |
| 2040 MockRead(SYNCHRONOUS, OK), | |
| 2041 }; | |
| 2042 | |
| 2043 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2044 data_writes1, arraysize(data_writes1)); | |
| 2045 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 2046 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2047 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 2048 | |
| 2049 TestCompletionCallback callback1; | |
| 2050 | |
| 2051 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 2052 | |
| 2053 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 2054 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2055 | |
| 2056 rv = callback1.WaitForResult(); | |
| 2057 EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); | |
| 2058 net::CapturingNetLog::EntryList entries; | |
| 2059 log.GetEntries(&entries); | |
| 2060 size_t pos = ExpectLogContainsSomewhere( | |
| 2061 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 2062 NetLog::PHASE_NONE); | |
| 2063 ExpectLogContainsSomewhere( | |
| 2064 entries, pos, | |
| 2065 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 2066 NetLog::PHASE_NONE); | |
| 2067 } | |
| 2068 | |
| 2069 // Test a simple get through an HTTPS Proxy. | |
| 2070 TEST_F(HttpNetworkTransactionTest, HttpsProxyGet) { | |
| 2071 HttpRequestInfo request; | |
| 2072 request.method = "GET"; | |
| 2073 request.url = GURL("http://www.google.com/"); | |
| 2074 | |
| 2075 // Configure against https proxy server "proxy:70". | |
| 2076 SessionDependencies session_deps(ProxyService::CreateFixed( | |
| 2077 "https://proxy:70")); | |
| 2078 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 2079 session_deps.net_log = log.bound().net_log(); | |
| 2080 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 2081 | |
| 2082 // Since we have proxy, should use full url | |
| 2083 MockWrite data_writes1[] = { | |
| 2084 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 2085 "Host: www.google.com\r\n" | |
| 2086 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2087 }; | |
| 2088 | |
| 2089 MockRead data_reads1[] = { | |
| 2090 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 2091 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2092 MockRead("Content-Length: 100\r\n\r\n"), | |
| 2093 MockRead(SYNCHRONOUS, OK), | |
| 2094 }; | |
| 2095 | |
| 2096 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2097 data_writes1, arraysize(data_writes1)); | |
| 2098 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 2099 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2100 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 2101 | |
| 2102 TestCompletionCallback callback1; | |
| 2103 | |
| 2104 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 2105 | |
| 2106 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 2107 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2108 | |
| 2109 rv = callback1.WaitForResult(); | |
| 2110 EXPECT_EQ(OK, rv); | |
| 2111 | |
| 2112 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2113 ASSERT_TRUE(response != NULL); | |
| 2114 | |
| 2115 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 2116 EXPECT_EQ(200, response->headers->response_code()); | |
| 2117 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 2118 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 2119 | |
| 2120 // The password prompt info should not be set. | |
| 2121 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 2122 } | |
| 2123 | |
| 2124 // Test a SPDY get through an HTTPS Proxy. | |
| 2125 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGet) { | |
| 2126 HttpRequestInfo request; | |
| 2127 request.method = "GET"; | |
| 2128 request.url = GURL("http://www.google.com/"); | |
| 2129 request.load_flags = 0; | |
| 2130 | |
| 2131 // Configure against https proxy server "proxy:70". | |
| 2132 SessionDependencies session_deps(ProxyService::CreateFixed( | |
| 2133 "https://proxy:70")); | |
| 2134 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 2135 session_deps.net_log = log.bound().net_log(); | |
| 2136 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 2137 | |
| 2138 // fetch http://www.google.com/ via SPDY | |
| 2139 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST, | |
| 2140 false)); | |
| 2141 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
| 2142 | |
| 2143 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 2144 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
| 2145 MockRead spdy_reads[] = { | |
| 2146 CreateMockRead(*resp), | |
| 2147 CreateMockRead(*data), | |
| 2148 MockRead(ASYNC, 0, 0), | |
| 2149 }; | |
| 2150 | |
| 2151 scoped_ptr<DelayedSocketData> spdy_data( | |
| 2152 new DelayedSocketData( | |
| 2153 1, // wait for one write to finish before reading. | |
| 2154 spdy_reads, arraysize(spdy_reads), | |
| 2155 spdy_writes, arraysize(spdy_writes))); | |
| 2156 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 2157 | |
| 2158 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2159 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 2160 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 2161 | |
| 2162 TestCompletionCallback callback1; | |
| 2163 | |
| 2164 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 2165 | |
| 2166 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 2167 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2168 | |
| 2169 rv = callback1.WaitForResult(); | |
| 2170 EXPECT_EQ(OK, rv); | |
| 2171 | |
| 2172 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2173 ASSERT_TRUE(response != NULL); | |
| 2174 ASSERT_TRUE(response->headers != NULL); | |
| 2175 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 2176 | |
| 2177 std::string response_data; | |
| 2178 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 2179 EXPECT_EQ(net::kUploadData, response_data); | |
| 2180 } | |
| 2181 | |
| 2182 // Test a SPDY get through an HTTPS Proxy. | |
| 2183 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) { | |
| 2184 HttpRequestInfo request; | |
| 2185 request.method = "GET"; | |
| 2186 request.url = GURL("http://www.google.com/"); | |
| 2187 request.load_flags = 0; | |
| 2188 | |
| 2189 // Configure against https proxy server "myproxy:70". | |
| 2190 SessionDependencies session_deps( | |
| 2191 ProxyService::CreateFixed("https://myproxy:70")); | |
| 2192 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 2193 session_deps.net_log = log.bound().net_log(); | |
| 2194 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 2195 | |
| 2196 // The first request will be a bare GET, the second request will be a | |
| 2197 // GET with a Proxy-Authorization header. | |
| 2198 scoped_ptr<spdy::SpdyFrame> req_get( | |
| 2199 ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false)); | |
| 2200 const char* const kExtraAuthorizationHeaders[] = { | |
| 2201 "proxy-authorization", | |
| 2202 "Basic Zm9vOmJhcg==", | |
| 2203 }; | |
| 2204 scoped_ptr<spdy::SpdyFrame> req_get_authorization( | |
| 2205 ConstructSpdyGet( | |
| 2206 kExtraAuthorizationHeaders, arraysize(kExtraAuthorizationHeaders)/2, | |
| 2207 false, 3, LOWEST, false)); | |
| 2208 MockWrite spdy_writes[] = { | |
| 2209 CreateMockWrite(*req_get, 1), | |
| 2210 CreateMockWrite(*req_get_authorization, 4), | |
| 2211 }; | |
| 2212 | |
| 2213 // The first response is a 407 proxy authentication challenge, and the second | |
| 2214 // response will be a 200 response since the second request includes a valid | |
| 2215 // Authorization header. | |
| 2216 const char* const kExtraAuthenticationHeaders[] = { | |
| 2217 "proxy-authenticate", | |
| 2218 "Basic realm=\"MyRealm1\"" | |
| 2219 }; | |
| 2220 scoped_ptr<spdy::SpdyFrame> resp_authentication( | |
| 2221 ConstructSpdySynReplyError( | |
| 2222 "407 Proxy Authentication Required", | |
| 2223 kExtraAuthenticationHeaders, arraysize(kExtraAuthenticationHeaders)/2, | |
| 2224 1)); | |
| 2225 scoped_ptr<spdy::SpdyFrame> body_authentication( | |
| 2226 ConstructSpdyBodyFrame(1, true)); | |
| 2227 scoped_ptr<spdy::SpdyFrame> resp_data(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 2228 scoped_ptr<spdy::SpdyFrame> body_data(ConstructSpdyBodyFrame(3, true)); | |
| 2229 MockRead spdy_reads[] = { | |
| 2230 CreateMockRead(*resp_authentication, 2), | |
| 2231 CreateMockRead(*body_authentication, 3), | |
| 2232 CreateMockRead(*resp_data, 5), | |
| 2233 CreateMockRead(*body_data, 6), | |
| 2234 MockRead(ASYNC, 0, 7), | |
| 2235 }; | |
| 2236 | |
| 2237 scoped_ptr<OrderedSocketData> data( | |
| 2238 new OrderedSocketData(spdy_reads, arraysize(spdy_reads), | |
| 2239 spdy_writes, arraysize(spdy_writes))); | |
| 2240 session_deps.socket_factory.AddSocketDataProvider(data.get()); | |
| 2241 | |
| 2242 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2243 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 2244 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 2245 | |
| 2246 TestCompletionCallback callback1; | |
| 2247 | |
| 2248 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 2249 | |
| 2250 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 2251 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2252 | |
| 2253 rv = callback1.WaitForResult(); | |
| 2254 EXPECT_EQ(OK, rv); | |
| 2255 | |
| 2256 const HttpResponseInfo* const response = trans->GetResponseInfo(); | |
| 2257 | |
| 2258 ASSERT_TRUE(response != NULL); | |
| 2259 ASSERT_TRUE(response->headers != NULL); | |
| 2260 EXPECT_EQ(407, response->headers->response_code()); | |
| 2261 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 2262 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 2263 | |
| 2264 TestCompletionCallback callback2; | |
| 2265 | |
| 2266 rv = trans->RestartWithAuth( | |
| 2267 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 2268 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2269 | |
| 2270 rv = callback2.WaitForResult(); | |
| 2271 EXPECT_EQ(OK, rv); | |
| 2272 | |
| 2273 const HttpResponseInfo* const response_restart = trans->GetResponseInfo(); | |
| 2274 | |
| 2275 ASSERT_TRUE(response_restart != NULL); | |
| 2276 ASSERT_TRUE(response_restart->headers != NULL); | |
| 2277 EXPECT_EQ(200, response_restart->headers->response_code()); | |
| 2278 // The password prompt info should not be set. | |
| 2279 EXPECT_TRUE(response_restart->auth_challenge.get() == NULL); | |
| 2280 } | |
| 2281 | |
| 2282 // Test a SPDY CONNECT through an HTTPS Proxy to an HTTPS (non-SPDY) Server. | |
| 2283 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) { | |
| 2284 HttpRequestInfo request; | |
| 2285 request.method = "GET"; | |
| 2286 request.url = GURL("https://www.google.com/"); | |
| 2287 request.load_flags = 0; | |
| 2288 | |
| 2289 // Configure against https proxy server "proxy:70". | |
| 2290 SessionDependencies session_deps(ProxyService::CreateFixed( | |
| 2291 "https://proxy:70")); | |
| 2292 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 2293 session_deps.net_log = log.bound().net_log(); | |
| 2294 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 2295 | |
| 2296 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 2297 | |
| 2298 // CONNECT to www.google.com:443 via SPDY | |
| 2299 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); | |
| 2300 // fetch https://www.google.com/ via HTTP | |
| 2301 | |
| 2302 const char get[] = "GET / HTTP/1.1\r\n" | |
| 2303 "Host: www.google.com\r\n" | |
| 2304 "Connection: keep-alive\r\n\r\n"; | |
| 2305 scoped_ptr<spdy::SpdyFrame> wrapped_get( | |
| 2306 ConstructSpdyBodyFrame(1, get, strlen(get), false)); | |
| 2307 scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 2308 const char resp[] = "HTTP/1.1 200 OK\r\n" | |
| 2309 "Content-Length: 10\r\n\r\n"; | |
| 2310 scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( | |
| 2311 ConstructSpdyBodyFrame(1, resp, strlen(resp), false)); | |
| 2312 scoped_ptr<spdy::SpdyFrame> wrapped_body( | |
| 2313 ConstructSpdyBodyFrame(1, "1234567890", 10, false)); | |
| 2314 scoped_ptr<spdy::SpdyFrame> window_update( | |
| 2315 ConstructSpdyWindowUpdate(1, wrapped_get_resp->length())); | |
| 2316 | |
| 2317 MockWrite spdy_writes[] = { | |
| 2318 CreateMockWrite(*connect, 1), | |
| 2319 CreateMockWrite(*wrapped_get, 3), | |
| 2320 CreateMockWrite(*window_update, 5) | |
| 2321 }; | |
| 2322 | |
| 2323 MockRead spdy_reads[] = { | |
| 2324 CreateMockRead(*conn_resp, 2, ASYNC), | |
| 2325 CreateMockRead(*wrapped_get_resp, 4, ASYNC), | |
| 2326 CreateMockRead(*wrapped_body, 6, ASYNC), | |
| 2327 CreateMockRead(*wrapped_body, 7, ASYNC), | |
| 2328 MockRead(ASYNC, 0, 8), | |
| 2329 }; | |
| 2330 | |
| 2331 scoped_ptr<OrderedSocketData> spdy_data( | |
| 2332 new OrderedSocketData( | |
| 2333 spdy_reads, arraysize(spdy_reads), | |
| 2334 spdy_writes, arraysize(spdy_writes))); | |
| 2335 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 2336 | |
| 2337 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2338 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 2339 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 2340 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 2341 ssl2.was_npn_negotiated = false; | |
| 2342 ssl2.protocol_negotiated = SSLClientSocket::kProtoUnknown; | |
| 2343 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); | |
| 2344 | |
| 2345 TestCompletionCallback callback1; | |
| 2346 | |
| 2347 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 2348 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2349 | |
| 2350 rv = callback1.WaitForResult(); | |
| 2351 EXPECT_EQ(OK, rv); | |
| 2352 | |
| 2353 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2354 ASSERT_TRUE(response != NULL); | |
| 2355 ASSERT_TRUE(response->headers != NULL); | |
| 2356 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 2357 | |
| 2358 std::string response_data; | |
| 2359 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 2360 EXPECT_EQ("1234567890", response_data); | |
| 2361 } | |
| 2362 | |
| 2363 // Test a SPDY CONNECT through an HTTPS Proxy to a SPDY server. | |
| 2364 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) { | |
| 2365 HttpRequestInfo request; | |
| 2366 request.method = "GET"; | |
| 2367 request.url = GURL("https://www.google.com/"); | |
| 2368 request.load_flags = 0; | |
| 2369 | |
| 2370 // Configure against https proxy server "proxy:70". | |
| 2371 SessionDependencies session_deps(ProxyService::CreateFixed( | |
| 2372 "https://proxy:70")); | |
| 2373 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 2374 session_deps.net_log = log.bound().net_log(); | |
| 2375 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 2376 | |
| 2377 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 2378 | |
| 2379 // CONNECT to www.google.com:443 via SPDY | |
| 2380 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); | |
| 2381 // fetch https://www.google.com/ via SPDY | |
| 2382 const char* const kMyUrl = "https://www.google.com/"; | |
| 2383 scoped_ptr<spdy::SpdyFrame> get(ConstructSpdyGet(kMyUrl, false, 1, LOWEST)); | |
| 2384 scoped_ptr<spdy::SpdyFrame> wrapped_get(ConstructWrappedSpdyFrame(get, 1)); | |
| 2385 scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 2386 scoped_ptr<spdy::SpdyFrame> get_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 2387 scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( | |
| 2388 ConstructWrappedSpdyFrame(get_resp, 1)); | |
| 2389 scoped_ptr<spdy::SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); | |
| 2390 scoped_ptr<spdy::SpdyFrame> wrapped_body(ConstructWrappedSpdyFrame(body, 1)); | |
| 2391 scoped_ptr<spdy::SpdyFrame> window_update_get_resp( | |
| 2392 ConstructSpdyWindowUpdate(1, wrapped_get_resp->length())); | |
| 2393 scoped_ptr<spdy::SpdyFrame> window_update_body( | |
| 2394 ConstructSpdyWindowUpdate(1, wrapped_body->length())); | |
| 2395 | |
| 2396 MockWrite spdy_writes[] = { | |
| 2397 CreateMockWrite(*connect, 1), | |
| 2398 CreateMockWrite(*wrapped_get, 3), | |
| 2399 CreateMockWrite(*window_update_get_resp, 5), | |
| 2400 CreateMockWrite(*window_update_body, 7), | |
| 2401 }; | |
| 2402 | |
| 2403 MockRead spdy_reads[] = { | |
| 2404 CreateMockRead(*conn_resp, 2, ASYNC), | |
| 2405 CreateMockRead(*wrapped_get_resp, 4, ASYNC), | |
| 2406 CreateMockRead(*wrapped_body, 6, ASYNC), | |
| 2407 MockRead(ASYNC, 0, 8), | |
| 2408 }; | |
| 2409 | |
| 2410 scoped_ptr<OrderedSocketData> spdy_data( | |
| 2411 new OrderedSocketData( | |
| 2412 spdy_reads, arraysize(spdy_reads), | |
| 2413 spdy_writes, arraysize(spdy_writes))); | |
| 2414 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 2415 | |
| 2416 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2417 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 2418 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 2419 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 2420 ssl2.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 2421 ssl2.protocol_negotiated = SSLClientSocket::kProtoSPDY21; | |
| 2422 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); | |
| 2423 | |
| 2424 TestCompletionCallback callback1; | |
| 2425 | |
| 2426 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 2427 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2428 | |
| 2429 rv = callback1.WaitForResult(); | |
| 2430 EXPECT_EQ(OK, rv); | |
| 2431 | |
| 2432 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2433 ASSERT_TRUE(response != NULL); | |
| 2434 ASSERT_TRUE(response->headers != NULL); | |
| 2435 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 2436 | |
| 2437 std::string response_data; | |
| 2438 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 2439 EXPECT_EQ(net::kUploadData, response_data); | |
| 2440 } | |
| 2441 | |
| 2442 // Test a SPDY CONNECT failure through an HTTPS Proxy. | |
| 2443 TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) { | |
| 2444 HttpRequestInfo request; | |
| 2445 request.method = "GET"; | |
| 2446 request.url = GURL("https://www.google.com/"); | |
| 2447 request.load_flags = 0; | |
| 2448 | |
| 2449 // Configure against https proxy server "proxy:70". | |
| 2450 SessionDependencies session_deps(ProxyService::CreateFixed( | |
| 2451 "https://proxy:70")); | |
| 2452 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 2453 session_deps.net_log = log.bound().net_log(); | |
| 2454 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 2455 | |
| 2456 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 2457 | |
| 2458 // CONNECT to www.google.com:443 via SPDY | |
| 2459 scoped_ptr<spdy::SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); | |
| 2460 scoped_ptr<spdy::SpdyFrame> get(ConstructSpdyRstStream(1, spdy::CANCEL)); | |
| 2461 | |
| 2462 MockWrite spdy_writes[] = { | |
| 2463 CreateMockWrite(*connect, 1), | |
| 2464 CreateMockWrite(*get, 3), | |
| 2465 }; | |
| 2466 | |
| 2467 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdySynReplyError(1)); | |
| 2468 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
| 2469 MockRead spdy_reads[] = { | |
| 2470 CreateMockRead(*resp, 2, ASYNC), | |
| 2471 MockRead(ASYNC, 0, 4), | |
| 2472 }; | |
| 2473 | |
| 2474 scoped_ptr<OrderedSocketData> spdy_data( | |
| 2475 new OrderedSocketData( | |
| 2476 spdy_reads, arraysize(spdy_reads), | |
| 2477 spdy_writes, arraysize(spdy_writes))); | |
| 2478 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 2479 | |
| 2480 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2481 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 2482 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 2483 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 2484 ssl2.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 2485 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); | |
| 2486 | |
| 2487 TestCompletionCallback callback1; | |
| 2488 | |
| 2489 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 2490 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2491 | |
| 2492 rv = callback1.WaitForResult(); | |
| 2493 EXPECT_EQ(OK, rv); | |
| 2494 | |
| 2495 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2496 ASSERT_TRUE(response != NULL); | |
| 2497 EXPECT_EQ(500, response->headers->response_code()); | |
| 2498 } | |
| 2499 | |
| 2500 // Test the challenge-response-retry sequence through an HTTPS Proxy | |
| 2501 TEST_F(HttpNetworkTransactionTest, HttpsProxyAuthRetry) { | |
| 2502 HttpRequestInfo request; | |
| 2503 request.method = "GET"; | |
| 2504 request.url = GURL("http://www.google.com/"); | |
| 2505 // when the no authentication data flag is set. | |
| 2506 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
| 2507 | |
| 2508 // Configure against https proxy server "myproxy:70". | |
| 2509 SessionDependencies session_deps( | |
| 2510 ProxyService::CreateFixed("https://myproxy:70")); | |
| 2511 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 2512 session_deps.net_log = log.bound().net_log(); | |
| 2513 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 2514 | |
| 2515 // Since we have proxy, should use full url | |
| 2516 MockWrite data_writes1[] = { | |
| 2517 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 2518 "Host: www.google.com\r\n" | |
| 2519 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2520 | |
| 2521 // After calling trans->RestartWithAuth(), this is the request we should | |
| 2522 // be issuing -- the final header line contains the credentials. | |
| 2523 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 2524 "Host: www.google.com\r\n" | |
| 2525 "Proxy-Connection: keep-alive\r\n" | |
| 2526 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 2527 }; | |
| 2528 | |
| 2529 // The proxy responds to the GET with a 407, using a persistent | |
| 2530 // connection. | |
| 2531 MockRead data_reads1[] = { | |
| 2532 // No credentials. | |
| 2533 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 2534 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2535 MockRead("Proxy-Connection: keep-alive\r\n"), | |
| 2536 MockRead("Content-Length: 0\r\n\r\n"), | |
| 2537 | |
| 2538 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 2539 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2540 MockRead("Content-Length: 100\r\n\r\n"), | |
| 2541 MockRead(SYNCHRONOUS, OK), | |
| 2542 }; | |
| 2543 | |
| 2544 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2545 data_writes1, arraysize(data_writes1)); | |
| 2546 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 2547 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 2548 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 2549 | |
| 2550 TestCompletionCallback callback1; | |
| 2551 | |
| 2552 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 2553 | |
| 2554 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 2555 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2556 | |
| 2557 rv = callback1.WaitForResult(); | |
| 2558 EXPECT_EQ(OK, rv); | |
| 2559 | |
| 2560 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2561 ASSERT_TRUE(response != NULL); | |
| 2562 ASSERT_FALSE(response->headers == NULL); | |
| 2563 EXPECT_EQ(407, response->headers->response_code()); | |
| 2564 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 2565 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 2566 | |
| 2567 TestCompletionCallback callback2; | |
| 2568 | |
| 2569 rv = trans->RestartWithAuth( | |
| 2570 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 2571 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2572 | |
| 2573 rv = callback2.WaitForResult(); | |
| 2574 EXPECT_EQ(OK, rv); | |
| 2575 | |
| 2576 response = trans->GetResponseInfo(); | |
| 2577 ASSERT_TRUE(response != NULL); | |
| 2578 | |
| 2579 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 2580 EXPECT_EQ(200, response->headers->response_code()); | |
| 2581 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 2582 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 2583 | |
| 2584 // The password prompt info should not be set. | |
| 2585 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 2586 } | |
| 2587 | |
| 2588 void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus( | |
| 2589 const MockRead& status, int expected_status) { | |
| 2590 HttpRequestInfo request; | |
| 2591 request.method = "GET"; | |
| 2592 request.url = GURL("https://www.google.com/"); | |
| 2593 request.load_flags = 0; | |
| 2594 | |
| 2595 // Configure against proxy server "myproxy:70". | |
| 2596 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 2597 | |
| 2598 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 2599 | |
| 2600 // Since we have proxy, should try to establish tunnel. | |
| 2601 MockWrite data_writes[] = { | |
| 2602 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 2603 "Host: www.google.com\r\n" | |
| 2604 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2605 }; | |
| 2606 | |
| 2607 MockRead data_reads[] = { | |
| 2608 status, | |
| 2609 MockRead("Content-Length: 10\r\n\r\n"), | |
| 2610 // No response body because the test stops reading here. | |
| 2611 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 2612 }; | |
| 2613 | |
| 2614 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 2615 data_writes, arraysize(data_writes)); | |
| 2616 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 2617 | |
| 2618 TestCompletionCallback callback; | |
| 2619 | |
| 2620 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 2621 | |
| 2622 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 2623 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2624 | |
| 2625 rv = callback.WaitForResult(); | |
| 2626 EXPECT_EQ(expected_status, rv); | |
| 2627 } | |
| 2628 | |
| 2629 void HttpNetworkTransactionTest::ConnectStatusHelper(const MockRead& status) { | |
| 2630 ConnectStatusHelperWithExpectedStatus( | |
| 2631 status, ERR_TUNNEL_CONNECTION_FAILED); | |
| 2632 } | |
| 2633 | |
| 2634 TEST_F(HttpNetworkTransactionTest, ConnectStatus100) { | |
| 2635 ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n")); | |
| 2636 } | |
| 2637 | |
| 2638 TEST_F(HttpNetworkTransactionTest, ConnectStatus101) { | |
| 2639 ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n")); | |
| 2640 } | |
| 2641 | |
| 2642 TEST_F(HttpNetworkTransactionTest, ConnectStatus201) { | |
| 2643 ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n")); | |
| 2644 } | |
| 2645 | |
| 2646 TEST_F(HttpNetworkTransactionTest, ConnectStatus202) { | |
| 2647 ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n")); | |
| 2648 } | |
| 2649 | |
| 2650 TEST_F(HttpNetworkTransactionTest, ConnectStatus203) { | |
| 2651 ConnectStatusHelper( | |
| 2652 MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n")); | |
| 2653 } | |
| 2654 | |
| 2655 TEST_F(HttpNetworkTransactionTest, ConnectStatus204) { | |
| 2656 ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n")); | |
| 2657 } | |
| 2658 | |
| 2659 TEST_F(HttpNetworkTransactionTest, ConnectStatus205) { | |
| 2660 ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n")); | |
| 2661 } | |
| 2662 | |
| 2663 TEST_F(HttpNetworkTransactionTest, ConnectStatus206) { | |
| 2664 ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n")); | |
| 2665 } | |
| 2666 | |
| 2667 TEST_F(HttpNetworkTransactionTest, ConnectStatus300) { | |
| 2668 ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n")); | |
| 2669 } | |
| 2670 | |
| 2671 TEST_F(HttpNetworkTransactionTest, ConnectStatus301) { | |
| 2672 ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n")); | |
| 2673 } | |
| 2674 | |
| 2675 TEST_F(HttpNetworkTransactionTest, ConnectStatus302) { | |
| 2676 ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n")); | |
| 2677 } | |
| 2678 | |
| 2679 TEST_F(HttpNetworkTransactionTest, ConnectStatus303) { | |
| 2680 ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n")); | |
| 2681 } | |
| 2682 | |
| 2683 TEST_F(HttpNetworkTransactionTest, ConnectStatus304) { | |
| 2684 ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n")); | |
| 2685 } | |
| 2686 | |
| 2687 TEST_F(HttpNetworkTransactionTest, ConnectStatus305) { | |
| 2688 ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n")); | |
| 2689 } | |
| 2690 | |
| 2691 TEST_F(HttpNetworkTransactionTest, ConnectStatus306) { | |
| 2692 ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n")); | |
| 2693 } | |
| 2694 | |
| 2695 TEST_F(HttpNetworkTransactionTest, ConnectStatus307) { | |
| 2696 ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n")); | |
| 2697 } | |
| 2698 | |
| 2699 TEST_F(HttpNetworkTransactionTest, ConnectStatus400) { | |
| 2700 ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n")); | |
| 2701 } | |
| 2702 | |
| 2703 TEST_F(HttpNetworkTransactionTest, ConnectStatus401) { | |
| 2704 ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n")); | |
| 2705 } | |
| 2706 | |
| 2707 TEST_F(HttpNetworkTransactionTest, ConnectStatus402) { | |
| 2708 ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n")); | |
| 2709 } | |
| 2710 | |
| 2711 TEST_F(HttpNetworkTransactionTest, ConnectStatus403) { | |
| 2712 ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n")); | |
| 2713 } | |
| 2714 | |
| 2715 TEST_F(HttpNetworkTransactionTest, ConnectStatus404) { | |
| 2716 ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n")); | |
| 2717 } | |
| 2718 | |
| 2719 TEST_F(HttpNetworkTransactionTest, ConnectStatus405) { | |
| 2720 ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n")); | |
| 2721 } | |
| 2722 | |
| 2723 TEST_F(HttpNetworkTransactionTest, ConnectStatus406) { | |
| 2724 ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n")); | |
| 2725 } | |
| 2726 | |
| 2727 TEST_F(HttpNetworkTransactionTest, ConnectStatus407) { | |
| 2728 ConnectStatusHelperWithExpectedStatus( | |
| 2729 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 2730 ERR_PROXY_AUTH_UNSUPPORTED); | |
| 2731 } | |
| 2732 | |
| 2733 TEST_F(HttpNetworkTransactionTest, ConnectStatus408) { | |
| 2734 ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n")); | |
| 2735 } | |
| 2736 | |
| 2737 TEST_F(HttpNetworkTransactionTest, ConnectStatus409) { | |
| 2738 ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n")); | |
| 2739 } | |
| 2740 | |
| 2741 TEST_F(HttpNetworkTransactionTest, ConnectStatus410) { | |
| 2742 ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n")); | |
| 2743 } | |
| 2744 | |
| 2745 TEST_F(HttpNetworkTransactionTest, ConnectStatus411) { | |
| 2746 ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n")); | |
| 2747 } | |
| 2748 | |
| 2749 TEST_F(HttpNetworkTransactionTest, ConnectStatus412) { | |
| 2750 ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n")); | |
| 2751 } | |
| 2752 | |
| 2753 TEST_F(HttpNetworkTransactionTest, ConnectStatus413) { | |
| 2754 ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n")); | |
| 2755 } | |
| 2756 | |
| 2757 TEST_F(HttpNetworkTransactionTest, ConnectStatus414) { | |
| 2758 ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n")); | |
| 2759 } | |
| 2760 | |
| 2761 TEST_F(HttpNetworkTransactionTest, ConnectStatus415) { | |
| 2762 ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n")); | |
| 2763 } | |
| 2764 | |
| 2765 TEST_F(HttpNetworkTransactionTest, ConnectStatus416) { | |
| 2766 ConnectStatusHelper( | |
| 2767 MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n")); | |
| 2768 } | |
| 2769 | |
| 2770 TEST_F(HttpNetworkTransactionTest, ConnectStatus417) { | |
| 2771 ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n")); | |
| 2772 } | |
| 2773 | |
| 2774 TEST_F(HttpNetworkTransactionTest, ConnectStatus500) { | |
| 2775 ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n")); | |
| 2776 } | |
| 2777 | |
| 2778 TEST_F(HttpNetworkTransactionTest, ConnectStatus501) { | |
| 2779 ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n")); | |
| 2780 } | |
| 2781 | |
| 2782 TEST_F(HttpNetworkTransactionTest, ConnectStatus502) { | |
| 2783 ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n")); | |
| 2784 } | |
| 2785 | |
| 2786 TEST_F(HttpNetworkTransactionTest, ConnectStatus503) { | |
| 2787 ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n")); | |
| 2788 } | |
| 2789 | |
| 2790 TEST_F(HttpNetworkTransactionTest, ConnectStatus504) { | |
| 2791 ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n")); | |
| 2792 } | |
| 2793 | |
| 2794 TEST_F(HttpNetworkTransactionTest, ConnectStatus505) { | |
| 2795 ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n")); | |
| 2796 } | |
| 2797 | |
| 2798 // Test the flow when both the proxy server AND origin server require | |
| 2799 // authentication. Again, this uses basic auth for both since that is | |
| 2800 // the simplest to mock. | |
| 2801 TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) { | |
| 2802 HttpRequestInfo request; | |
| 2803 request.method = "GET"; | |
| 2804 request.url = GURL("http://www.google.com/"); | |
| 2805 request.load_flags = 0; | |
| 2806 | |
| 2807 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 2808 | |
| 2809 // Configure against proxy server "myproxy:70". | |
| 2810 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction( | |
| 2811 CreateSession(&session_deps))); | |
| 2812 | |
| 2813 MockWrite data_writes1[] = { | |
| 2814 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 2815 "Host: www.google.com\r\n" | |
| 2816 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 2817 }; | |
| 2818 | |
| 2819 MockRead data_reads1[] = { | |
| 2820 MockRead("HTTP/1.0 407 Unauthorized\r\n"), | |
| 2821 // Give a couple authenticate options (only the middle one is actually | |
| 2822 // supported). | |
| 2823 MockRead("Proxy-Authenticate: Basic invalid\r\n"), // Malformed. | |
| 2824 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2825 MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), | |
| 2826 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2827 // Large content-length -- won't matter, as connection will be reset. | |
| 2828 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 2829 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 2830 }; | |
| 2831 | |
| 2832 // After calling trans->RestartWithAuth() the first time, this is the | |
| 2833 // request we should be issuing -- the final header line contains the | |
| 2834 // proxy's credentials. | |
| 2835 MockWrite data_writes2[] = { | |
| 2836 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 2837 "Host: www.google.com\r\n" | |
| 2838 "Proxy-Connection: keep-alive\r\n" | |
| 2839 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 2840 }; | |
| 2841 | |
| 2842 // Now the proxy server lets the request pass through to origin server. | |
| 2843 // The origin server responds with a 401. | |
| 2844 MockRead data_reads2[] = { | |
| 2845 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 2846 // Note: We are using the same realm-name as the proxy server. This is | |
| 2847 // completely valid, as realms are unique across hosts. | |
| 2848 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 2849 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2850 MockRead("Content-Length: 2000\r\n\r\n"), | |
| 2851 MockRead(SYNCHRONOUS, ERR_FAILED), // Won't be reached. | |
| 2852 }; | |
| 2853 | |
| 2854 // After calling trans->RestartWithAuth() the second time, we should send | |
| 2855 // the credentials for both the proxy and origin server. | |
| 2856 MockWrite data_writes3[] = { | |
| 2857 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 2858 "Host: www.google.com\r\n" | |
| 2859 "Proxy-Connection: keep-alive\r\n" | |
| 2860 "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" | |
| 2861 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), | |
| 2862 }; | |
| 2863 | |
| 2864 // Lastly we get the desired content. | |
| 2865 MockRead data_reads3[] = { | |
| 2866 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 2867 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 2868 MockRead("Content-Length: 100\r\n\r\n"), | |
| 2869 MockRead(SYNCHRONOUS, OK), | |
| 2870 }; | |
| 2871 | |
| 2872 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 2873 data_writes1, arraysize(data_writes1)); | |
| 2874 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 2875 data_writes2, arraysize(data_writes2)); | |
| 2876 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
| 2877 data_writes3, arraysize(data_writes3)); | |
| 2878 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 2879 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 2880 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
| 2881 | |
| 2882 TestCompletionCallback callback1; | |
| 2883 | |
| 2884 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 2885 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2886 | |
| 2887 rv = callback1.WaitForResult(); | |
| 2888 EXPECT_EQ(OK, rv); | |
| 2889 | |
| 2890 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 2891 ASSERT_TRUE(response != NULL); | |
| 2892 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 2893 | |
| 2894 TestCompletionCallback callback2; | |
| 2895 | |
| 2896 rv = trans->RestartWithAuth( | |
| 2897 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 2898 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2899 | |
| 2900 rv = callback2.WaitForResult(); | |
| 2901 EXPECT_EQ(OK, rv); | |
| 2902 | |
| 2903 response = trans->GetResponseInfo(); | |
| 2904 ASSERT_TRUE(response != NULL); | |
| 2905 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 2906 | |
| 2907 TestCompletionCallback callback3; | |
| 2908 | |
| 2909 rv = trans->RestartWithAuth( | |
| 2910 AuthCredentials(kFoo2, kBar2), callback3.callback()); | |
| 2911 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 2912 | |
| 2913 rv = callback3.WaitForResult(); | |
| 2914 EXPECT_EQ(OK, rv); | |
| 2915 | |
| 2916 response = trans->GetResponseInfo(); | |
| 2917 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 2918 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 2919 } | |
| 2920 | |
| 2921 // For the NTLM implementation using SSPI, we skip the NTLM tests since we | |
| 2922 // can't hook into its internals to cause it to generate predictable NTLM | |
| 2923 // authorization headers. | |
| 2924 #if defined(NTLM_PORTABLE) | |
| 2925 // The NTLM authentication unit tests were generated by capturing the HTTP | |
| 2926 // requests and responses using Fiddler 2 and inspecting the generated random | |
| 2927 // bytes in the debugger. | |
| 2928 | |
| 2929 // Enter the correct password and authenticate successfully. | |
| 2930 TEST_F(HttpNetworkTransactionTest, NTLMAuth1) { | |
| 2931 HttpRequestInfo request; | |
| 2932 request.method = "GET"; | |
| 2933 request.url = GURL("http://172.22.68.17/kids/login.aspx"); | |
| 2934 request.load_flags = 0; | |
| 2935 | |
| 2936 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1, | |
| 2937 MockGetHostName); | |
| 2938 SessionDependencies session_deps; | |
| 2939 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 2940 | |
| 2941 MockWrite data_writes1[] = { | |
| 2942 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 2943 "Host: 172.22.68.17\r\n" | |
| 2944 "Connection: keep-alive\r\n\r\n"), | |
| 2945 }; | |
| 2946 | |
| 2947 MockRead data_reads1[] = { | |
| 2948 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 2949 // Negotiate and NTLM are often requested together. However, we only want | |
| 2950 // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip | |
| 2951 // the header that requests Negotiate for this test. | |
| 2952 MockRead("WWW-Authenticate: NTLM\r\n"), | |
| 2953 MockRead("Connection: close\r\n"), | |
| 2954 MockRead("Content-Length: 42\r\n"), | |
| 2955 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 2956 // Missing content -- won't matter, as connection will be reset. | |
| 2957 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), | |
| 2958 }; | |
| 2959 | |
| 2960 MockWrite data_writes2[] = { | |
| 2961 // After restarting with a null identity, this is the | |
| 2962 // request we should be issuing -- the final header line contains a Type | |
| 2963 // 1 message. | |
| 2964 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 2965 "Host: 172.22.68.17\r\n" | |
| 2966 "Connection: keep-alive\r\n" | |
| 2967 "Authorization: NTLM " | |
| 2968 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), | |
| 2969 | |
| 2970 // After calling trans->RestartWithAuth(), we should send a Type 3 message | |
| 2971 // (the credentials for the origin server). The second request continues | |
| 2972 // on the same connection. | |
| 2973 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 2974 "Host: 172.22.68.17\r\n" | |
| 2975 "Connection: keep-alive\r\n" | |
| 2976 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" | |
| 2977 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" | |
| 2978 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW" | |
| 2979 "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX" | |
| 2980 "ahlhx5I=\r\n\r\n"), | |
| 2981 }; | |
| 2982 | |
| 2983 MockRead data_reads2[] = { | |
| 2984 // The origin server responds with a Type 2 message. | |
| 2985 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 2986 MockRead("WWW-Authenticate: NTLM " | |
| 2987 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo" | |
| 2988 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" | |
| 2989 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" | |
| 2990 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" | |
| 2991 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" | |
| 2992 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" | |
| 2993 "BtAAAAAAA=\r\n"), | |
| 2994 MockRead("Content-Length: 42\r\n"), | |
| 2995 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 2996 MockRead("You are not authorized to view this page\r\n"), | |
| 2997 | |
| 2998 // Lastly we get the desired content. | |
| 2999 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 3000 MockRead("Content-Type: text/html; charset=utf-8\r\n"), | |
| 3001 MockRead("Content-Length: 13\r\n\r\n"), | |
| 3002 MockRead("Please Login\r\n"), | |
| 3003 MockRead(SYNCHRONOUS, OK), | |
| 3004 }; | |
| 3005 | |
| 3006 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 3007 data_writes1, arraysize(data_writes1)); | |
| 3008 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 3009 data_writes2, arraysize(data_writes2)); | |
| 3010 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 3011 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 3012 | |
| 3013 TestCompletionCallback callback1; | |
| 3014 | |
| 3015 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 3016 | |
| 3017 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 3018 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3019 | |
| 3020 rv = callback1.WaitForResult(); | |
| 3021 EXPECT_EQ(OK, rv); | |
| 3022 | |
| 3023 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 3024 | |
| 3025 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3026 ASSERT_FALSE(response == NULL); | |
| 3027 EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); | |
| 3028 | |
| 3029 TestCompletionCallback callback2; | |
| 3030 | |
| 3031 rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM), | |
| 3032 callback2.callback()); | |
| 3033 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3034 | |
| 3035 rv = callback2.WaitForResult(); | |
| 3036 EXPECT_EQ(OK, rv); | |
| 3037 | |
| 3038 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 3039 | |
| 3040 response = trans->GetResponseInfo(); | |
| 3041 ASSERT_TRUE(response != NULL); | |
| 3042 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 3043 | |
| 3044 TestCompletionCallback callback3; | |
| 3045 | |
| 3046 rv = trans->RestartWithAuth(AuthCredentials(), callback3.callback()); | |
| 3047 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3048 | |
| 3049 rv = callback3.WaitForResult(); | |
| 3050 EXPECT_EQ(OK, rv); | |
| 3051 | |
| 3052 response = trans->GetResponseInfo(); | |
| 3053 ASSERT_TRUE(response != NULL); | |
| 3054 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 3055 EXPECT_EQ(13, response->headers->GetContentLength()); | |
| 3056 } | |
| 3057 | |
| 3058 // Enter a wrong password, and then the correct one. | |
| 3059 TEST_F(HttpNetworkTransactionTest, NTLMAuth2) { | |
| 3060 HttpRequestInfo request; | |
| 3061 request.method = "GET"; | |
| 3062 request.url = GURL("http://172.22.68.17/kids/login.aspx"); | |
| 3063 request.load_flags = 0; | |
| 3064 | |
| 3065 HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom2, | |
| 3066 MockGetHostName); | |
| 3067 SessionDependencies session_deps; | |
| 3068 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 3069 | |
| 3070 MockWrite data_writes1[] = { | |
| 3071 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 3072 "Host: 172.22.68.17\r\n" | |
| 3073 "Connection: keep-alive\r\n\r\n"), | |
| 3074 }; | |
| 3075 | |
| 3076 MockRead data_reads1[] = { | |
| 3077 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 3078 // Negotiate and NTLM are often requested together. However, we only want | |
| 3079 // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip | |
| 3080 // the header that requests Negotiate for this test. | |
| 3081 MockRead("WWW-Authenticate: NTLM\r\n"), | |
| 3082 MockRead("Connection: close\r\n"), | |
| 3083 MockRead("Content-Length: 42\r\n"), | |
| 3084 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 3085 // Missing content -- won't matter, as connection will be reset. | |
| 3086 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), | |
| 3087 }; | |
| 3088 | |
| 3089 MockWrite data_writes2[] = { | |
| 3090 // After restarting with a null identity, this is the | |
| 3091 // request we should be issuing -- the final header line contains a Type | |
| 3092 // 1 message. | |
| 3093 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 3094 "Host: 172.22.68.17\r\n" | |
| 3095 "Connection: keep-alive\r\n" | |
| 3096 "Authorization: NTLM " | |
| 3097 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), | |
| 3098 | |
| 3099 // After calling trans->RestartWithAuth(), we should send a Type 3 message | |
| 3100 // (the credentials for the origin server). The second request continues | |
| 3101 // on the same connection. | |
| 3102 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 3103 "Host: 172.22.68.17\r\n" | |
| 3104 "Connection: keep-alive\r\n" | |
| 3105 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" | |
| 3106 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" | |
| 3107 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY" | |
| 3108 "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj" | |
| 3109 "4Ww7b7E=\r\n\r\n"), | |
| 3110 }; | |
| 3111 | |
| 3112 MockRead data_reads2[] = { | |
| 3113 // The origin server responds with a Type 2 message. | |
| 3114 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 3115 MockRead("WWW-Authenticate: NTLM " | |
| 3116 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCbVWUZezVGpAAAAAAAAAAALo" | |
| 3117 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" | |
| 3118 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" | |
| 3119 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" | |
| 3120 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" | |
| 3121 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" | |
| 3122 "BtAAAAAAA=\r\n"), | |
| 3123 MockRead("Content-Length: 42\r\n"), | |
| 3124 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 3125 MockRead("You are not authorized to view this page\r\n"), | |
| 3126 | |
| 3127 // Wrong password. | |
| 3128 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 3129 MockRead("WWW-Authenticate: NTLM\r\n"), | |
| 3130 MockRead("Connection: close\r\n"), | |
| 3131 MockRead("Content-Length: 42\r\n"), | |
| 3132 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 3133 // Missing content -- won't matter, as connection will be reset. | |
| 3134 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), | |
| 3135 }; | |
| 3136 | |
| 3137 MockWrite data_writes3[] = { | |
| 3138 // After restarting with a null identity, this is the | |
| 3139 // request we should be issuing -- the final header line contains a Type | |
| 3140 // 1 message. | |
| 3141 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 3142 "Host: 172.22.68.17\r\n" | |
| 3143 "Connection: keep-alive\r\n" | |
| 3144 "Authorization: NTLM " | |
| 3145 "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), | |
| 3146 | |
| 3147 // After calling trans->RestartWithAuth(), we should send a Type 3 message | |
| 3148 // (the credentials for the origin server). The second request continues | |
| 3149 // on the same connection. | |
| 3150 MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" | |
| 3151 "Host: 172.22.68.17\r\n" | |
| 3152 "Connection: keep-alive\r\n" | |
| 3153 "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" | |
| 3154 "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" | |
| 3155 "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54" | |
| 3156 "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI" | |
| 3157 "+4MUm7c=\r\n\r\n"), | |
| 3158 }; | |
| 3159 | |
| 3160 MockRead data_reads3[] = { | |
| 3161 // The origin server responds with a Type 2 message. | |
| 3162 MockRead("HTTP/1.1 401 Access Denied\r\n"), | |
| 3163 MockRead("WWW-Authenticate: NTLM " | |
| 3164 "TlRMTVNTUAACAAAADAAMADgAAAAFgokCL24VN8dgOR8AAAAAAAAAALo" | |
| 3165 "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" | |
| 3166 "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" | |
| 3167 "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" | |
| 3168 "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" | |
| 3169 "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" | |
| 3170 "BtAAAAAAA=\r\n"), | |
| 3171 MockRead("Content-Length: 42\r\n"), | |
| 3172 MockRead("Content-Type: text/html\r\n\r\n"), | |
| 3173 MockRead("You are not authorized to view this page\r\n"), | |
| 3174 | |
| 3175 // Lastly we get the desired content. | |
| 3176 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 3177 MockRead("Content-Type: text/html; charset=utf-8\r\n"), | |
| 3178 MockRead("Content-Length: 13\r\n\r\n"), | |
| 3179 MockRead("Please Login\r\n"), | |
| 3180 MockRead(SYNCHRONOUS, OK), | |
| 3181 }; | |
| 3182 | |
| 3183 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 3184 data_writes1, arraysize(data_writes1)); | |
| 3185 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 3186 data_writes2, arraysize(data_writes2)); | |
| 3187 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
| 3188 data_writes3, arraysize(data_writes3)); | |
| 3189 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 3190 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 3191 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
| 3192 | |
| 3193 TestCompletionCallback callback1; | |
| 3194 | |
| 3195 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 3196 | |
| 3197 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 3198 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3199 | |
| 3200 rv = callback1.WaitForResult(); | |
| 3201 EXPECT_EQ(OK, rv); | |
| 3202 | |
| 3203 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 3204 | |
| 3205 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3206 ASSERT_TRUE(response != NULL); | |
| 3207 EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); | |
| 3208 | |
| 3209 TestCompletionCallback callback2; | |
| 3210 | |
| 3211 // Enter the wrong password. | |
| 3212 rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kWrongPassword), | |
| 3213 callback2.callback()); | |
| 3214 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3215 | |
| 3216 rv = callback2.WaitForResult(); | |
| 3217 EXPECT_EQ(OK, rv); | |
| 3218 | |
| 3219 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 3220 TestCompletionCallback callback3; | |
| 3221 rv = trans->RestartWithAuth(AuthCredentials(), callback3.callback()); | |
| 3222 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3223 rv = callback3.WaitForResult(); | |
| 3224 EXPECT_EQ(OK, rv); | |
| 3225 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 3226 | |
| 3227 response = trans->GetResponseInfo(); | |
| 3228 ASSERT_FALSE(response == NULL); | |
| 3229 EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); | |
| 3230 | |
| 3231 TestCompletionCallback callback4; | |
| 3232 | |
| 3233 // Now enter the right password. | |
| 3234 rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM), | |
| 3235 callback4.callback()); | |
| 3236 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3237 | |
| 3238 rv = callback4.WaitForResult(); | |
| 3239 EXPECT_EQ(OK, rv); | |
| 3240 | |
| 3241 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 3242 | |
| 3243 TestCompletionCallback callback5; | |
| 3244 | |
| 3245 // One more roundtrip | |
| 3246 rv = trans->RestartWithAuth(AuthCredentials(), callback5.callback()); | |
| 3247 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3248 | |
| 3249 rv = callback5.WaitForResult(); | |
| 3250 EXPECT_EQ(OK, rv); | |
| 3251 | |
| 3252 response = trans->GetResponseInfo(); | |
| 3253 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 3254 EXPECT_EQ(13, response->headers->GetContentLength()); | |
| 3255 } | |
| 3256 #endif // NTLM_PORTABLE | |
| 3257 | |
| 3258 // Test reading a server response which has only headers, and no body. | |
| 3259 // After some maximum number of bytes is consumed, the transaction should | |
| 3260 // fail with ERR_RESPONSE_HEADERS_TOO_BIG. | |
| 3261 TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) { | |
| 3262 HttpRequestInfo request; | |
| 3263 request.method = "GET"; | |
| 3264 request.url = GURL("http://www.google.com/"); | |
| 3265 request.load_flags = 0; | |
| 3266 | |
| 3267 SessionDependencies session_deps; | |
| 3268 scoped_ptr<HttpTransaction> trans( | |
| 3269 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 3270 | |
| 3271 // Respond with 300 kb of headers (we should fail after 256 kb). | |
| 3272 std::string large_headers_string; | |
| 3273 FillLargeHeadersString(&large_headers_string, 300 * 1024); | |
| 3274 | |
| 3275 MockRead data_reads[] = { | |
| 3276 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 3277 MockRead(ASYNC, large_headers_string.data(), large_headers_string.size()), | |
| 3278 MockRead("\r\nBODY"), | |
| 3279 MockRead(SYNCHRONOUS, OK), | |
| 3280 }; | |
| 3281 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 3282 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 3283 | |
| 3284 TestCompletionCallback callback; | |
| 3285 | |
| 3286 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 3287 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3288 | |
| 3289 rv = callback.WaitForResult(); | |
| 3290 EXPECT_EQ(ERR_RESPONSE_HEADERS_TOO_BIG, rv); | |
| 3291 | |
| 3292 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3293 EXPECT_TRUE(response == NULL); | |
| 3294 } | |
| 3295 | |
| 3296 // Make sure that we don't try to reuse a TCPClientSocket when failing to | |
| 3297 // establish tunnel. | |
| 3298 // http://code.google.com/p/chromium/issues/detail?id=3772 | |
| 3299 TEST_F(HttpNetworkTransactionTest, DontRecycleTransportSocketForSSLTunnel) { | |
| 3300 HttpRequestInfo request; | |
| 3301 request.method = "GET"; | |
| 3302 request.url = GURL("https://www.google.com/"); | |
| 3303 request.load_flags = 0; | |
| 3304 | |
| 3305 // Configure against proxy server "myproxy:70". | |
| 3306 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 3307 | |
| 3308 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 3309 | |
| 3310 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 3311 | |
| 3312 // Since we have proxy, should try to establish tunnel. | |
| 3313 MockWrite data_writes1[] = { | |
| 3314 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 3315 "Host: www.google.com\r\n" | |
| 3316 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 3317 }; | |
| 3318 | |
| 3319 // The proxy responds to the connect with a 404, using a persistent | |
| 3320 // connection. Usually a proxy would return 501 (not implemented), | |
| 3321 // or 200 (tunnel established). | |
| 3322 MockRead data_reads1[] = { | |
| 3323 MockRead("HTTP/1.1 404 Not Found\r\n"), | |
| 3324 MockRead("Content-Length: 10\r\n\r\n"), | |
| 3325 MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. | |
| 3326 }; | |
| 3327 | |
| 3328 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 3329 data_writes1, arraysize(data_writes1)); | |
| 3330 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 3331 | |
| 3332 TestCompletionCallback callback1; | |
| 3333 | |
| 3334 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 3335 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3336 | |
| 3337 rv = callback1.WaitForResult(); | |
| 3338 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
| 3339 | |
| 3340 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3341 EXPECT_TRUE(response == NULL); | |
| 3342 | |
| 3343 // Empty the current queue. This is necessary because idle sockets are | |
| 3344 // added to the connection pool asynchronously with a PostTask. | |
| 3345 MessageLoop::current()->RunAllPending(); | |
| 3346 | |
| 3347 // We now check to make sure the TCPClientSocket was not added back to | |
| 3348 // the pool. | |
| 3349 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
| 3350 trans.reset(); | |
| 3351 MessageLoop::current()->RunAllPending(); | |
| 3352 // Make sure that the socket didn't get recycled after calling the destructor. | |
| 3353 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
| 3354 } | |
| 3355 | |
| 3356 // Make sure that we recycle a socket after reading all of the response body. | |
| 3357 TEST_F(HttpNetworkTransactionTest, RecycleSocket) { | |
| 3358 HttpRequestInfo request; | |
| 3359 request.method = "GET"; | |
| 3360 request.url = GURL("http://www.google.com/"); | |
| 3361 request.load_flags = 0; | |
| 3362 | |
| 3363 SessionDependencies session_deps; | |
| 3364 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 3365 | |
| 3366 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 3367 | |
| 3368 MockRead data_reads[] = { | |
| 3369 // A part of the response body is received with the response headers. | |
| 3370 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"), | |
| 3371 // The rest of the response body is received in two parts. | |
| 3372 MockRead("lo"), | |
| 3373 MockRead(" world"), | |
| 3374 MockRead("junk"), // Should not be read!! | |
| 3375 MockRead(SYNCHRONOUS, OK), | |
| 3376 }; | |
| 3377 | |
| 3378 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 3379 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 3380 | |
| 3381 TestCompletionCallback callback; | |
| 3382 | |
| 3383 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 3384 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3385 | |
| 3386 rv = callback.WaitForResult(); | |
| 3387 EXPECT_EQ(OK, rv); | |
| 3388 | |
| 3389 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3390 ASSERT_TRUE(response != NULL); | |
| 3391 | |
| 3392 EXPECT_TRUE(response->headers != NULL); | |
| 3393 std::string status_line = response->headers->GetStatusLine(); | |
| 3394 EXPECT_EQ("HTTP/1.1 200 OK", status_line); | |
| 3395 | |
| 3396 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
| 3397 | |
| 3398 std::string response_data; | |
| 3399 rv = ReadTransaction(trans.get(), &response_data); | |
| 3400 EXPECT_EQ(OK, rv); | |
| 3401 EXPECT_EQ("hello world", response_data); | |
| 3402 | |
| 3403 // Empty the current queue. This is necessary because idle sockets are | |
| 3404 // added to the connection pool asynchronously with a PostTask. | |
| 3405 MessageLoop::current()->RunAllPending(); | |
| 3406 | |
| 3407 // We now check to make sure the socket was added back to the pool. | |
| 3408 EXPECT_EQ(1, session->GetTransportSocketPool()->IdleSocketCount()); | |
| 3409 } | |
| 3410 | |
| 3411 // Make sure that we recycle a SSL socket after reading all of the response | |
| 3412 // body. | |
| 3413 TEST_F(HttpNetworkTransactionTest, RecycleSSLSocket) { | |
| 3414 SessionDependencies session_deps; | |
| 3415 HttpRequestInfo request; | |
| 3416 request.method = "GET"; | |
| 3417 request.url = GURL("https://www.google.com/"); | |
| 3418 request.load_flags = 0; | |
| 3419 | |
| 3420 MockWrite data_writes[] = { | |
| 3421 MockWrite("GET / HTTP/1.1\r\n" | |
| 3422 "Host: www.google.com\r\n" | |
| 3423 "Connection: keep-alive\r\n\r\n"), | |
| 3424 }; | |
| 3425 | |
| 3426 MockRead data_reads[] = { | |
| 3427 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 3428 MockRead("Content-Length: 11\r\n\r\n"), | |
| 3429 MockRead("hello world"), | |
| 3430 MockRead(SYNCHRONOUS, OK), | |
| 3431 }; | |
| 3432 | |
| 3433 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3434 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 3435 | |
| 3436 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 3437 data_writes, arraysize(data_writes)); | |
| 3438 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 3439 | |
| 3440 TestCompletionCallback callback; | |
| 3441 | |
| 3442 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 3443 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 3444 | |
| 3445 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 3446 | |
| 3447 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3448 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 3449 | |
| 3450 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3451 ASSERT_TRUE(response != NULL); | |
| 3452 ASSERT_TRUE(response->headers != NULL); | |
| 3453 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 3454 | |
| 3455 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
| 3456 | |
| 3457 std::string response_data; | |
| 3458 rv = ReadTransaction(trans.get(), &response_data); | |
| 3459 EXPECT_EQ(OK, rv); | |
| 3460 EXPECT_EQ("hello world", response_data); | |
| 3461 | |
| 3462 // Empty the current queue. This is necessary because idle sockets are | |
| 3463 // added to the connection pool asynchronously with a PostTask. | |
| 3464 MessageLoop::current()->RunAllPending(); | |
| 3465 | |
| 3466 // We now check to make sure the socket was added back to the pool. | |
| 3467 EXPECT_EQ(1, session->GetSSLSocketPool()->IdleSocketCount()); | |
| 3468 } | |
| 3469 | |
| 3470 // Grab a SSL socket, use it, and put it back into the pool. Then, reuse it | |
| 3471 // from the pool and make sure that we recover okay. | |
| 3472 TEST_F(HttpNetworkTransactionTest, RecycleDeadSSLSocket) { | |
| 3473 SessionDependencies session_deps; | |
| 3474 HttpRequestInfo request; | |
| 3475 request.method = "GET"; | |
| 3476 request.url = GURL("https://www.google.com/"); | |
| 3477 request.load_flags = 0; | |
| 3478 | |
| 3479 MockWrite data_writes[] = { | |
| 3480 MockWrite("GET / HTTP/1.1\r\n" | |
| 3481 "Host: www.google.com\r\n" | |
| 3482 "Connection: keep-alive\r\n\r\n"), | |
| 3483 MockWrite("GET / HTTP/1.1\r\n" | |
| 3484 "Host: www.google.com\r\n" | |
| 3485 "Connection: keep-alive\r\n\r\n"), | |
| 3486 }; | |
| 3487 | |
| 3488 MockRead data_reads[] = { | |
| 3489 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 3490 MockRead("Content-Length: 11\r\n\r\n"), | |
| 3491 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 3492 MockRead("hello world"), | |
| 3493 MockRead(ASYNC, 0, 0) // EOF | |
| 3494 }; | |
| 3495 | |
| 3496 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 3497 SSLSocketDataProvider ssl2(ASYNC, OK); | |
| 3498 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 3499 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); | |
| 3500 | |
| 3501 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 3502 data_writes, arraysize(data_writes)); | |
| 3503 StaticSocketDataProvider data2(data_reads, arraysize(data_reads), | |
| 3504 data_writes, arraysize(data_writes)); | |
| 3505 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 3506 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 3507 | |
| 3508 TestCompletionCallback callback; | |
| 3509 | |
| 3510 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 3511 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 3512 | |
| 3513 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 3514 | |
| 3515 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3516 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 3517 | |
| 3518 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3519 ASSERT_TRUE(response != NULL); | |
| 3520 ASSERT_TRUE(response->headers != NULL); | |
| 3521 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 3522 | |
| 3523 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
| 3524 | |
| 3525 std::string response_data; | |
| 3526 rv = ReadTransaction(trans.get(), &response_data); | |
| 3527 EXPECT_EQ(OK, rv); | |
| 3528 EXPECT_EQ("hello world", response_data); | |
| 3529 | |
| 3530 // Empty the current queue. This is necessary because idle sockets are | |
| 3531 // added to the connection pool asynchronously with a PostTask. | |
| 3532 MessageLoop::current()->RunAllPending(); | |
| 3533 | |
| 3534 // We now check to make sure the socket was added back to the pool. | |
| 3535 EXPECT_EQ(1, session->GetSSLSocketPool()->IdleSocketCount()); | |
| 3536 | |
| 3537 // Now start the second transaction, which should reuse the previous socket. | |
| 3538 | |
| 3539 trans.reset(new HttpNetworkTransaction(session)); | |
| 3540 | |
| 3541 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 3542 | |
| 3543 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3544 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 3545 | |
| 3546 response = trans->GetResponseInfo(); | |
| 3547 ASSERT_TRUE(response != NULL); | |
| 3548 ASSERT_TRUE(response->headers != NULL); | |
| 3549 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 3550 | |
| 3551 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
| 3552 | |
| 3553 rv = ReadTransaction(trans.get(), &response_data); | |
| 3554 EXPECT_EQ(OK, rv); | |
| 3555 EXPECT_EQ("hello world", response_data); | |
| 3556 | |
| 3557 // Empty the current queue. This is necessary because idle sockets are | |
| 3558 // added to the connection pool asynchronously with a PostTask. | |
| 3559 MessageLoop::current()->RunAllPending(); | |
| 3560 | |
| 3561 // We now check to make sure the socket was added back to the pool. | |
| 3562 EXPECT_EQ(1, session->GetSSLSocketPool()->IdleSocketCount()); | |
| 3563 } | |
| 3564 | |
| 3565 // Make sure that we recycle a socket after a zero-length response. | |
| 3566 // http://crbug.com/9880 | |
| 3567 TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) { | |
| 3568 HttpRequestInfo request; | |
| 3569 request.method = "GET"; | |
| 3570 request.url = GURL("http://www.google.com/csi?v=3&s=web&action=&" | |
| 3571 "tran=undefined&ei=mAXcSeegAo-SMurloeUN&" | |
| 3572 "e=17259,18167,19592,19773,19981,20133,20173,20233&" | |
| 3573 "rt=prt.2642,ol.2649,xjs.2951"); | |
| 3574 request.load_flags = 0; | |
| 3575 | |
| 3576 SessionDependencies session_deps; | |
| 3577 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 3578 | |
| 3579 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 3580 | |
| 3581 MockRead data_reads[] = { | |
| 3582 MockRead("HTTP/1.1 204 No Content\r\n" | |
| 3583 "Content-Length: 0\r\n" | |
| 3584 "Content-Type: text/html\r\n\r\n"), | |
| 3585 MockRead("junk"), // Should not be read!! | |
| 3586 MockRead(SYNCHRONOUS, OK), | |
| 3587 }; | |
| 3588 | |
| 3589 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 3590 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 3591 | |
| 3592 TestCompletionCallback callback; | |
| 3593 | |
| 3594 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 3595 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3596 | |
| 3597 rv = callback.WaitForResult(); | |
| 3598 EXPECT_EQ(OK, rv); | |
| 3599 | |
| 3600 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3601 ASSERT_TRUE(response != NULL); | |
| 3602 | |
| 3603 EXPECT_TRUE(response->headers != NULL); | |
| 3604 std::string status_line = response->headers->GetStatusLine(); | |
| 3605 EXPECT_EQ("HTTP/1.1 204 No Content", status_line); | |
| 3606 | |
| 3607 EXPECT_EQ(0, session->GetTransportSocketPool()->IdleSocketCount()); | |
| 3608 | |
| 3609 std::string response_data; | |
| 3610 rv = ReadTransaction(trans.get(), &response_data); | |
| 3611 EXPECT_EQ(OK, rv); | |
| 3612 EXPECT_EQ("", response_data); | |
| 3613 | |
| 3614 // Empty the current queue. This is necessary because idle sockets are | |
| 3615 // added to the connection pool asynchronously with a PostTask. | |
| 3616 MessageLoop::current()->RunAllPending(); | |
| 3617 | |
| 3618 // We now check to make sure the socket was added back to the pool. | |
| 3619 EXPECT_EQ(1, session->GetTransportSocketPool()->IdleSocketCount()); | |
| 3620 } | |
| 3621 | |
| 3622 TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) { | |
| 3623 HttpRequestInfo request[2]; | |
| 3624 // Transaction 1: a GET request that succeeds. The socket is recycled | |
| 3625 // after use. | |
| 3626 request[0].method = "GET"; | |
| 3627 request[0].url = GURL("http://www.google.com/"); | |
| 3628 request[0].load_flags = 0; | |
| 3629 // Transaction 2: a POST request. Reuses the socket kept alive from | |
| 3630 // transaction 1. The first attempts fails when writing the POST data. | |
| 3631 // This causes the transaction to retry with a new socket. The second | |
| 3632 // attempt succeeds. | |
| 3633 request[1].method = "POST"; | |
| 3634 request[1].url = GURL("http://www.google.com/login.cgi"); | |
| 3635 request[1].upload_data = new UploadData; | |
| 3636 request[1].upload_data->AppendBytes("foo", 3); | |
| 3637 request[1].load_flags = 0; | |
| 3638 | |
| 3639 SessionDependencies session_deps; | |
| 3640 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 3641 | |
| 3642 // The first socket is used for transaction 1 and the first attempt of | |
| 3643 // transaction 2. | |
| 3644 | |
| 3645 // The response of transaction 1. | |
| 3646 MockRead data_reads1[] = { | |
| 3647 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"), | |
| 3648 MockRead("hello world"), | |
| 3649 MockRead(SYNCHRONOUS, OK), | |
| 3650 }; | |
| 3651 // The mock write results of transaction 1 and the first attempt of | |
| 3652 // transaction 2. | |
| 3653 MockWrite data_writes1[] = { | |
| 3654 MockWrite(SYNCHRONOUS, 64), // GET | |
| 3655 MockWrite(SYNCHRONOUS, 93), // POST | |
| 3656 MockWrite(SYNCHRONOUS, ERR_CONNECTION_ABORTED), // POST data | |
| 3657 }; | |
| 3658 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 3659 data_writes1, arraysize(data_writes1)); | |
| 3660 | |
| 3661 // The second socket is used for the second attempt of transaction 2. | |
| 3662 | |
| 3663 // The response of transaction 2. | |
| 3664 MockRead data_reads2[] = { | |
| 3665 MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"), | |
| 3666 MockRead("welcome"), | |
| 3667 MockRead(SYNCHRONOUS, OK), | |
| 3668 }; | |
| 3669 // The mock write results of the second attempt of transaction 2. | |
| 3670 MockWrite data_writes2[] = { | |
| 3671 MockWrite(SYNCHRONOUS, 93), // POST | |
| 3672 MockWrite(SYNCHRONOUS, 3), // POST data | |
| 3673 }; | |
| 3674 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 3675 data_writes2, arraysize(data_writes2)); | |
| 3676 | |
| 3677 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 3678 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 3679 | |
| 3680 const char* kExpectedResponseData[] = { | |
| 3681 "hello world", "welcome" | |
| 3682 }; | |
| 3683 | |
| 3684 for (int i = 0; i < 2; ++i) { | |
| 3685 scoped_ptr<HttpTransaction> trans( | |
| 3686 new HttpNetworkTransaction(session)); | |
| 3687 | |
| 3688 TestCompletionCallback callback; | |
| 3689 | |
| 3690 int rv = trans->Start(&request[i], callback.callback(), BoundNetLog()); | |
| 3691 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3692 | |
| 3693 rv = callback.WaitForResult(); | |
| 3694 EXPECT_EQ(OK, rv); | |
| 3695 | |
| 3696 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3697 ASSERT_TRUE(response != NULL); | |
| 3698 | |
| 3699 EXPECT_TRUE(response->headers != NULL); | |
| 3700 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 3701 | |
| 3702 std::string response_data; | |
| 3703 rv = ReadTransaction(trans.get(), &response_data); | |
| 3704 EXPECT_EQ(OK, rv); | |
| 3705 EXPECT_EQ(kExpectedResponseData[i], response_data); | |
| 3706 } | |
| 3707 } | |
| 3708 | |
| 3709 // Test the request-challenge-retry sequence for basic auth when there is | |
| 3710 // an identity in the URL. The request should be sent as normal, but when | |
| 3711 // it fails the identity from the URL is no longer used. | |
| 3712 TEST_F(HttpNetworkTransactionTest, IgnoreAuthIdentityInURL) { | |
| 3713 HttpRequestInfo request; | |
| 3714 request.method = "GET"; | |
| 3715 request.url = GURL("http://foo:b@r@www.google.com/"); | |
| 3716 request.load_flags = LOAD_NORMAL; | |
| 3717 | |
| 3718 SessionDependencies session_deps; | |
| 3719 scoped_ptr<HttpTransaction> trans( | |
| 3720 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 3721 | |
| 3722 // The password contains an escaped character -- for this test to pass it | |
| 3723 // will need to be unescaped by HttpNetworkTransaction. | |
| 3724 EXPECT_EQ("b%40r", request.url.password()); | |
| 3725 | |
| 3726 MockWrite data_writes1[] = { | |
| 3727 MockWrite("GET / HTTP/1.1\r\n" | |
| 3728 "Host: www.google.com\r\n" | |
| 3729 "Connection: keep-alive\r\n\r\n"), | |
| 3730 }; | |
| 3731 | |
| 3732 MockRead data_reads1[] = { | |
| 3733 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 3734 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 3735 MockRead("Content-Length: 10\r\n\r\n"), | |
| 3736 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 3737 }; | |
| 3738 | |
| 3739 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 3740 data_writes1, arraysize(data_writes1)); | |
| 3741 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 3742 | |
| 3743 TestCompletionCallback callback1; | |
| 3744 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 3745 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3746 rv = callback1.WaitForResult(); | |
| 3747 EXPECT_EQ(OK, rv); | |
| 3748 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 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(SYNCHRONOUS, 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(SYNCHRONOUS, 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.callback(), 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 ASSERT_TRUE(response != NULL); | |
| 3813 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 3814 | |
| 3815 TestCompletionCallback callback2; | |
| 3816 | |
| 3817 rv = trans->RestartWithAuth( | |
| 3818 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 3819 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3820 | |
| 3821 rv = callback2.WaitForResult(); | |
| 3822 EXPECT_EQ(OK, rv); | |
| 3823 | |
| 3824 response = trans->GetResponseInfo(); | |
| 3825 ASSERT_TRUE(response != NULL); | |
| 3826 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 3827 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 3828 } | |
| 3829 | |
| 3830 // ------------------------------------------------------------------------ | |
| 3831 | |
| 3832 // Transaction 2: authenticate (foo2, bar2) on MyRealm2 | |
| 3833 { | |
| 3834 HttpRequestInfo request; | |
| 3835 request.method = "GET"; | |
| 3836 // Note that Transaction 1 was at /x/y/z, so this is in the same | |
| 3837 // protection space as MyRealm1. | |
| 3838 request.url = GURL("http://www.google.com/x/y/a/b"); | |
| 3839 request.load_flags = 0; | |
| 3840 | |
| 3841 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 3842 | |
| 3843 MockWrite data_writes1[] = { | |
| 3844 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" | |
| 3845 "Host: www.google.com\r\n" | |
| 3846 "Connection: keep-alive\r\n" | |
| 3847 // Send preemptive authorization for MyRealm1 | |
| 3848 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 3849 }; | |
| 3850 | |
| 3851 // The server didn't like the preemptive authorization, and | |
| 3852 // challenges us for a different realm (MyRealm2). | |
| 3853 MockRead data_reads1[] = { | |
| 3854 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 3855 MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"), | |
| 3856 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 3857 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 3858 }; | |
| 3859 | |
| 3860 // Resend with authorization for MyRealm2 (username=foo2, password=bar2) | |
| 3861 MockWrite data_writes2[] = { | |
| 3862 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" | |
| 3863 "Host: www.google.com\r\n" | |
| 3864 "Connection: keep-alive\r\n" | |
| 3865 "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), | |
| 3866 }; | |
| 3867 | |
| 3868 // Sever accepts the authorization. | |
| 3869 MockRead data_reads2[] = { | |
| 3870 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 3871 MockRead("Content-Length: 100\r\n\r\n"), | |
| 3872 MockRead(SYNCHRONOUS, OK), | |
| 3873 }; | |
| 3874 | |
| 3875 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 3876 data_writes1, arraysize(data_writes1)); | |
| 3877 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 3878 data_writes2, arraysize(data_writes2)); | |
| 3879 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 3880 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 3881 | |
| 3882 TestCompletionCallback callback1; | |
| 3883 | |
| 3884 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 3885 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3886 | |
| 3887 rv = callback1.WaitForResult(); | |
| 3888 EXPECT_EQ(OK, rv); | |
| 3889 | |
| 3890 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3891 ASSERT_TRUE(response != NULL); | |
| 3892 ASSERT_TRUE(response->auth_challenge.get()); | |
| 3893 EXPECT_FALSE(response->auth_challenge->is_proxy); | |
| 3894 EXPECT_EQ("www.google.com:80", | |
| 3895 response->auth_challenge->challenger.ToString()); | |
| 3896 EXPECT_EQ("MyRealm2", response->auth_challenge->realm); | |
| 3897 EXPECT_EQ("basic", response->auth_challenge->scheme); | |
| 3898 | |
| 3899 TestCompletionCallback callback2; | |
| 3900 | |
| 3901 rv = trans->RestartWithAuth( | |
| 3902 AuthCredentials(kFoo2, kBar2), callback2.callback()); | |
| 3903 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3904 | |
| 3905 rv = callback2.WaitForResult(); | |
| 3906 EXPECT_EQ(OK, rv); | |
| 3907 | |
| 3908 response = trans->GetResponseInfo(); | |
| 3909 ASSERT_TRUE(response != NULL); | |
| 3910 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 3911 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 3912 } | |
| 3913 | |
| 3914 // ------------------------------------------------------------------------ | |
| 3915 | |
| 3916 // Transaction 3: Resend a request in MyRealm's protection space -- | |
| 3917 // succeed with preemptive authorization. | |
| 3918 { | |
| 3919 HttpRequestInfo request; | |
| 3920 request.method = "GET"; | |
| 3921 request.url = GURL("http://www.google.com/x/y/z2"); | |
| 3922 request.load_flags = 0; | |
| 3923 | |
| 3924 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 3925 | |
| 3926 MockWrite data_writes1[] = { | |
| 3927 MockWrite("GET /x/y/z2 HTTP/1.1\r\n" | |
| 3928 "Host: www.google.com\r\n" | |
| 3929 "Connection: keep-alive\r\n" | |
| 3930 // The authorization for MyRealm1 gets sent preemptively | |
| 3931 // (since the url is in the same protection space) | |
| 3932 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 3933 }; | |
| 3934 | |
| 3935 // Sever accepts the preemptive authorization | |
| 3936 MockRead data_reads1[] = { | |
| 3937 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 3938 MockRead("Content-Length: 100\r\n\r\n"), | |
| 3939 MockRead(SYNCHRONOUS, OK), | |
| 3940 }; | |
| 3941 | |
| 3942 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 3943 data_writes1, arraysize(data_writes1)); | |
| 3944 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 3945 | |
| 3946 TestCompletionCallback callback1; | |
| 3947 | |
| 3948 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 3949 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 3950 | |
| 3951 rv = callback1.WaitForResult(); | |
| 3952 EXPECT_EQ(OK, rv); | |
| 3953 | |
| 3954 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 3955 ASSERT_TRUE(response != NULL); | |
| 3956 | |
| 3957 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 3958 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 3959 } | |
| 3960 | |
| 3961 // ------------------------------------------------------------------------ | |
| 3962 | |
| 3963 // Transaction 4: request another URL in MyRealm (however the | |
| 3964 // url is not known to belong to the protection space, so no pre-auth). | |
| 3965 { | |
| 3966 HttpRequestInfo request; | |
| 3967 request.method = "GET"; | |
| 3968 request.url = GURL("http://www.google.com/x/1"); | |
| 3969 request.load_flags = 0; | |
| 3970 | |
| 3971 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 3972 | |
| 3973 MockWrite data_writes1[] = { | |
| 3974 MockWrite("GET /x/1 HTTP/1.1\r\n" | |
| 3975 "Host: www.google.com\r\n" | |
| 3976 "Connection: keep-alive\r\n\r\n"), | |
| 3977 }; | |
| 3978 | |
| 3979 MockRead data_reads1[] = { | |
| 3980 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 3981 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 3982 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 3983 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 3984 }; | |
| 3985 | |
| 3986 // Resend with authorization from MyRealm's cache. | |
| 3987 MockWrite data_writes2[] = { | |
| 3988 MockWrite("GET /x/1 HTTP/1.1\r\n" | |
| 3989 "Host: www.google.com\r\n" | |
| 3990 "Connection: keep-alive\r\n" | |
| 3991 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 3992 }; | |
| 3993 | |
| 3994 // Sever accepts the authorization. | |
| 3995 MockRead data_reads2[] = { | |
| 3996 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 3997 MockRead("Content-Length: 100\r\n\r\n"), | |
| 3998 MockRead(SYNCHRONOUS, OK), | |
| 3999 }; | |
| 4000 | |
| 4001 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 4002 data_writes1, arraysize(data_writes1)); | |
| 4003 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 4004 data_writes2, arraysize(data_writes2)); | |
| 4005 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 4006 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 4007 | |
| 4008 TestCompletionCallback callback1; | |
| 4009 | |
| 4010 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 4011 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4012 | |
| 4013 rv = callback1.WaitForResult(); | |
| 4014 EXPECT_EQ(OK, rv); | |
| 4015 | |
| 4016 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 4017 TestCompletionCallback callback2; | |
| 4018 rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback()); | |
| 4019 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4020 rv = callback2.WaitForResult(); | |
| 4021 EXPECT_EQ(OK, rv); | |
| 4022 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 4023 | |
| 4024 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4025 ASSERT_TRUE(response != NULL); | |
| 4026 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 4027 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 4028 } | |
| 4029 | |
| 4030 // ------------------------------------------------------------------------ | |
| 4031 | |
| 4032 // Transaction 5: request a URL in MyRealm, but the server rejects the | |
| 4033 // cached identity. Should invalidate and re-prompt. | |
| 4034 { | |
| 4035 HttpRequestInfo request; | |
| 4036 request.method = "GET"; | |
| 4037 request.url = GURL("http://www.google.com/p/q/t"); | |
| 4038 request.load_flags = 0; | |
| 4039 | |
| 4040 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 4041 | |
| 4042 MockWrite data_writes1[] = { | |
| 4043 MockWrite("GET /p/q/t HTTP/1.1\r\n" | |
| 4044 "Host: www.google.com\r\n" | |
| 4045 "Connection: keep-alive\r\n\r\n"), | |
| 4046 }; | |
| 4047 | |
| 4048 MockRead data_reads1[] = { | |
| 4049 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 4050 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 4051 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 4052 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 4053 }; | |
| 4054 | |
| 4055 // Resend with authorization from cache for MyRealm. | |
| 4056 MockWrite data_writes2[] = { | |
| 4057 MockWrite("GET /p/q/t HTTP/1.1\r\n" | |
| 4058 "Host: www.google.com\r\n" | |
| 4059 "Connection: keep-alive\r\n" | |
| 4060 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 4061 }; | |
| 4062 | |
| 4063 // Sever rejects the authorization. | |
| 4064 MockRead data_reads2[] = { | |
| 4065 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 4066 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 4067 MockRead("Content-Length: 10000\r\n\r\n"), | |
| 4068 MockRead(SYNCHRONOUS, ERR_FAILED), | |
| 4069 }; | |
| 4070 | |
| 4071 // At this point we should prompt for new credentials for MyRealm. | |
| 4072 // Restart with username=foo3, password=foo4. | |
| 4073 MockWrite data_writes3[] = { | |
| 4074 MockWrite("GET /p/q/t HTTP/1.1\r\n" | |
| 4075 "Host: www.google.com\r\n" | |
| 4076 "Connection: keep-alive\r\n" | |
| 4077 "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"), | |
| 4078 }; | |
| 4079 | |
| 4080 // Sever accepts the authorization. | |
| 4081 MockRead data_reads3[] = { | |
| 4082 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 4083 MockRead("Content-Length: 100\r\n\r\n"), | |
| 4084 MockRead(SYNCHRONOUS, OK), | |
| 4085 }; | |
| 4086 | |
| 4087 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 4088 data_writes1, arraysize(data_writes1)); | |
| 4089 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 4090 data_writes2, arraysize(data_writes2)); | |
| 4091 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
| 4092 data_writes3, arraysize(data_writes3)); | |
| 4093 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 4094 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 4095 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
| 4096 | |
| 4097 TestCompletionCallback callback1; | |
| 4098 | |
| 4099 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 4100 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4101 | |
| 4102 rv = callback1.WaitForResult(); | |
| 4103 EXPECT_EQ(OK, rv); | |
| 4104 | |
| 4105 EXPECT_TRUE(trans->IsReadyToRestartForAuth()); | |
| 4106 TestCompletionCallback callback2; | |
| 4107 rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback()); | |
| 4108 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4109 rv = callback2.WaitForResult(); | |
| 4110 EXPECT_EQ(OK, rv); | |
| 4111 EXPECT_FALSE(trans->IsReadyToRestartForAuth()); | |
| 4112 | |
| 4113 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4114 ASSERT_TRUE(response != NULL); | |
| 4115 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 4116 | |
| 4117 TestCompletionCallback callback3; | |
| 4118 | |
| 4119 rv = trans->RestartWithAuth( | |
| 4120 AuthCredentials(kFoo3, kBar3), callback3.callback()); | |
| 4121 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4122 | |
| 4123 rv = callback3.WaitForResult(); | |
| 4124 EXPECT_EQ(OK, rv); | |
| 4125 | |
| 4126 response = trans->GetResponseInfo(); | |
| 4127 ASSERT_TRUE(response != NULL); | |
| 4128 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 4129 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 4130 } | |
| 4131 } | |
| 4132 | |
| 4133 // Tests that nonce count increments when multiple auth attempts | |
| 4134 // are started with the same nonce. | |
| 4135 TEST_F(HttpNetworkTransactionTest, DigestPreAuthNonceCount) { | |
| 4136 SessionDependencies session_deps; | |
| 4137 HttpAuthHandlerDigest::Factory* digest_factory = | |
| 4138 new HttpAuthHandlerDigest::Factory(); | |
| 4139 HttpAuthHandlerDigest::FixedNonceGenerator* nonce_generator = | |
| 4140 new HttpAuthHandlerDigest::FixedNonceGenerator("0123456789abcdef"); | |
| 4141 digest_factory->set_nonce_generator(nonce_generator); | |
| 4142 session_deps.http_auth_handler_factory.reset(digest_factory); | |
| 4143 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 4144 | |
| 4145 // Transaction 1: authenticate (foo, bar) on MyRealm1 | |
| 4146 { | |
| 4147 HttpRequestInfo request; | |
| 4148 request.method = "GET"; | |
| 4149 request.url = GURL("http://www.google.com/x/y/z"); | |
| 4150 request.load_flags = 0; | |
| 4151 | |
| 4152 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 4153 | |
| 4154 MockWrite data_writes1[] = { | |
| 4155 MockWrite("GET /x/y/z HTTP/1.1\r\n" | |
| 4156 "Host: www.google.com\r\n" | |
| 4157 "Connection: keep-alive\r\n\r\n"), | |
| 4158 }; | |
| 4159 | |
| 4160 MockRead data_reads1[] = { | |
| 4161 MockRead("HTTP/1.0 401 Unauthorized\r\n"), | |
| 4162 MockRead("WWW-Authenticate: Digest realm=\"digestive\", nonce=\"OU812\", " | |
| 4163 "algorithm=MD5, qop=\"auth\"\r\n\r\n"), | |
| 4164 MockRead(SYNCHRONOUS, OK), | |
| 4165 }; | |
| 4166 | |
| 4167 // Resend with authorization (username=foo, password=bar) | |
| 4168 MockWrite data_writes2[] = { | |
| 4169 MockWrite("GET /x/y/z HTTP/1.1\r\n" | |
| 4170 "Host: www.google.com\r\n" | |
| 4171 "Connection: keep-alive\r\n" | |
| 4172 "Authorization: Digest username=\"foo\", realm=\"digestive\", " | |
| 4173 "nonce=\"OU812\", uri=\"/x/y/z\", algorithm=MD5, " | |
| 4174 "response=\"03ffbcd30add722589c1de345d7a927f\", qop=auth, " | |
| 4175 "nc=00000001, cnonce=\"0123456789abcdef\"\r\n\r\n"), | |
| 4176 }; | |
| 4177 | |
| 4178 // Sever accepts the authorization. | |
| 4179 MockRead data_reads2[] = { | |
| 4180 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 4181 MockRead(SYNCHRONOUS, OK), | |
| 4182 }; | |
| 4183 | |
| 4184 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 4185 data_writes1, arraysize(data_writes1)); | |
| 4186 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 4187 data_writes2, arraysize(data_writes2)); | |
| 4188 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 4189 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 4190 | |
| 4191 TestCompletionCallback callback1; | |
| 4192 | |
| 4193 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 4194 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4195 | |
| 4196 rv = callback1.WaitForResult(); | |
| 4197 EXPECT_EQ(OK, rv); | |
| 4198 | |
| 4199 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4200 ASSERT_TRUE(response != NULL); | |
| 4201 EXPECT_TRUE(CheckDigestServerAuth(response->auth_challenge.get())); | |
| 4202 | |
| 4203 TestCompletionCallback callback2; | |
| 4204 | |
| 4205 rv = trans->RestartWithAuth( | |
| 4206 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 4207 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4208 | |
| 4209 rv = callback2.WaitForResult(); | |
| 4210 EXPECT_EQ(OK, rv); | |
| 4211 | |
| 4212 response = trans->GetResponseInfo(); | |
| 4213 ASSERT_TRUE(response != NULL); | |
| 4214 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 4215 } | |
| 4216 | |
| 4217 // ------------------------------------------------------------------------ | |
| 4218 | |
| 4219 // Transaction 2: Request another resource in digestive's protection space. | |
| 4220 // This will preemptively add an Authorization header which should have an | |
| 4221 // "nc" value of 2 (as compared to 1 in the first use. | |
| 4222 { | |
| 4223 HttpRequestInfo request; | |
| 4224 request.method = "GET"; | |
| 4225 // Note that Transaction 1 was at /x/y/z, so this is in the same | |
| 4226 // protection space as digest. | |
| 4227 request.url = GURL("http://www.google.com/x/y/a/b"); | |
| 4228 request.load_flags = 0; | |
| 4229 | |
| 4230 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 4231 | |
| 4232 MockWrite data_writes1[] = { | |
| 4233 MockWrite("GET /x/y/a/b HTTP/1.1\r\n" | |
| 4234 "Host: www.google.com\r\n" | |
| 4235 "Connection: keep-alive\r\n" | |
| 4236 "Authorization: Digest username=\"foo\", realm=\"digestive\", " | |
| 4237 "nonce=\"OU812\", uri=\"/x/y/a/b\", algorithm=MD5, " | |
| 4238 "response=\"d6f9a2c07d1c5df7b89379dca1269b35\", qop=auth, " | |
| 4239 "nc=00000002, cnonce=\"0123456789abcdef\"\r\n\r\n"), | |
| 4240 }; | |
| 4241 | |
| 4242 // Sever accepts the authorization. | |
| 4243 MockRead data_reads1[] = { | |
| 4244 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 4245 MockRead("Content-Length: 100\r\n\r\n"), | |
| 4246 MockRead(SYNCHRONOUS, OK), | |
| 4247 }; | |
| 4248 | |
| 4249 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 4250 data_writes1, arraysize(data_writes1)); | |
| 4251 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 4252 | |
| 4253 TestCompletionCallback callback1; | |
| 4254 | |
| 4255 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 4256 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4257 | |
| 4258 rv = callback1.WaitForResult(); | |
| 4259 EXPECT_EQ(OK, rv); | |
| 4260 | |
| 4261 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4262 ASSERT_TRUE(response != NULL); | |
| 4263 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 4264 } | |
| 4265 } | |
| 4266 | |
| 4267 // Test the ResetStateForRestart() private method. | |
| 4268 TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) { | |
| 4269 // Create a transaction (the dependencies aren't important). | |
| 4270 SessionDependencies session_deps; | |
| 4271 scoped_ptr<HttpNetworkTransaction> trans( | |
| 4272 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 4273 | |
| 4274 // Setup some state (which we expect ResetStateForRestart() will clear). | |
| 4275 trans->read_buf_ = new IOBuffer(15); | |
| 4276 trans->read_buf_len_ = 15; | |
| 4277 trans->request_headers_.SetHeader("Authorization", "NTLM"); | |
| 4278 | |
| 4279 // Setup state in response_ | |
| 4280 HttpResponseInfo* response = &trans->response_; | |
| 4281 response->auth_challenge = new AuthChallengeInfo(); | |
| 4282 response->ssl_info.cert_status = static_cast<CertStatus>(-1); // Nonsensical. | |
| 4283 response->response_time = base::Time::Now(); | |
| 4284 response->was_cached = true; // (Wouldn't ever actually be true...) | |
| 4285 | |
| 4286 { // Setup state for response_.vary_data | |
| 4287 HttpRequestInfo request; | |
| 4288 std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n"); | |
| 4289 std::replace(temp.begin(), temp.end(), '\n', '\0'); | |
| 4290 scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(temp)); | |
| 4291 request.extra_headers.SetHeader("Foo", "1"); | |
| 4292 request.extra_headers.SetHeader("bar", "23"); | |
| 4293 EXPECT_TRUE(response->vary_data.Init(request, *headers)); | |
| 4294 } | |
| 4295 | |
| 4296 // Cause the above state to be reset. | |
| 4297 trans->ResetStateForRestart(); | |
| 4298 | |
| 4299 // Verify that the state that needed to be reset, has been reset. | |
| 4300 EXPECT_TRUE(trans->read_buf_.get() == NULL); | |
| 4301 EXPECT_EQ(0, trans->read_buf_len_); | |
| 4302 EXPECT_TRUE(trans->request_headers_.IsEmpty()); | |
| 4303 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 4304 EXPECT_TRUE(response->headers.get() == NULL); | |
| 4305 EXPECT_FALSE(response->was_cached); | |
| 4306 EXPECT_EQ(0U, response->ssl_info.cert_status); | |
| 4307 EXPECT_FALSE(response->vary_data.is_valid()); | |
| 4308 } | |
| 4309 | |
| 4310 // Test HTTPS connections to a site with a bad certificate | |
| 4311 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificate) { | |
| 4312 HttpRequestInfo request; | |
| 4313 request.method = "GET"; | |
| 4314 request.url = GURL("https://www.google.com/"); | |
| 4315 request.load_flags = 0; | |
| 4316 | |
| 4317 SessionDependencies session_deps; | |
| 4318 scoped_ptr<HttpTransaction> trans( | |
| 4319 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 4320 | |
| 4321 MockWrite data_writes[] = { | |
| 4322 MockWrite("GET / HTTP/1.1\r\n" | |
| 4323 "Host: www.google.com\r\n" | |
| 4324 "Connection: keep-alive\r\n\r\n"), | |
| 4325 }; | |
| 4326 | |
| 4327 MockRead data_reads[] = { | |
| 4328 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 4329 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 4330 MockRead("Content-Length: 100\r\n\r\n"), | |
| 4331 MockRead(SYNCHRONOUS, OK), | |
| 4332 }; | |
| 4333 | |
| 4334 StaticSocketDataProvider ssl_bad_certificate; | |
| 4335 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 4336 data_writes, arraysize(data_writes)); | |
| 4337 SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); | |
| 4338 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 4339 | |
| 4340 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); | |
| 4341 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 4342 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); | |
| 4343 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 4344 | |
| 4345 TestCompletionCallback callback; | |
| 4346 | |
| 4347 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4348 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4349 | |
| 4350 rv = callback.WaitForResult(); | |
| 4351 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); | |
| 4352 | |
| 4353 rv = trans->RestartIgnoringLastError(callback.callback()); | |
| 4354 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4355 | |
| 4356 rv = callback.WaitForResult(); | |
| 4357 EXPECT_EQ(OK, rv); | |
| 4358 | |
| 4359 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4360 | |
| 4361 ASSERT_TRUE(response != NULL); | |
| 4362 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 4363 } | |
| 4364 | |
| 4365 // Test HTTPS connections to a site with a bad certificate, going through a | |
| 4366 // proxy | |
| 4367 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) { | |
| 4368 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 4369 | |
| 4370 HttpRequestInfo request; | |
| 4371 request.method = "GET"; | |
| 4372 request.url = GURL("https://www.google.com/"); | |
| 4373 request.load_flags = 0; | |
| 4374 | |
| 4375 MockWrite proxy_writes[] = { | |
| 4376 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 4377 "Host: www.google.com\r\n" | |
| 4378 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 4379 }; | |
| 4380 | |
| 4381 MockRead proxy_reads[] = { | |
| 4382 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
| 4383 MockRead(SYNCHRONOUS, OK) | |
| 4384 }; | |
| 4385 | |
| 4386 MockWrite data_writes[] = { | |
| 4387 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 4388 "Host: www.google.com\r\n" | |
| 4389 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 4390 MockWrite("GET / HTTP/1.1\r\n" | |
| 4391 "Host: www.google.com\r\n" | |
| 4392 "Connection: keep-alive\r\n\r\n"), | |
| 4393 }; | |
| 4394 | |
| 4395 MockRead data_reads[] = { | |
| 4396 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
| 4397 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 4398 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 4399 MockRead("Content-Length: 100\r\n\r\n"), | |
| 4400 MockRead(SYNCHRONOUS, OK), | |
| 4401 }; | |
| 4402 | |
| 4403 StaticSocketDataProvider ssl_bad_certificate( | |
| 4404 proxy_reads, arraysize(proxy_reads), | |
| 4405 proxy_writes, arraysize(proxy_writes)); | |
| 4406 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 4407 data_writes, arraysize(data_writes)); | |
| 4408 SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); | |
| 4409 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 4410 | |
| 4411 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); | |
| 4412 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 4413 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); | |
| 4414 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 4415 | |
| 4416 TestCompletionCallback callback; | |
| 4417 | |
| 4418 for (int i = 0; i < 2; i++) { | |
| 4419 session_deps.socket_factory.ResetNextMockIndexes(); | |
| 4420 | |
| 4421 scoped_ptr<HttpTransaction> trans( | |
| 4422 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 4423 | |
| 4424 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4425 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4426 | |
| 4427 rv = callback.WaitForResult(); | |
| 4428 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); | |
| 4429 | |
| 4430 rv = trans->RestartIgnoringLastError(callback.callback()); | |
| 4431 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4432 | |
| 4433 rv = callback.WaitForResult(); | |
| 4434 EXPECT_EQ(OK, rv); | |
| 4435 | |
| 4436 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4437 | |
| 4438 ASSERT_TRUE(response != NULL); | |
| 4439 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 4440 } | |
| 4441 } | |
| 4442 | |
| 4443 | |
| 4444 // Test HTTPS connections to a site, going through an HTTPS proxy | |
| 4445 TEST_F(HttpNetworkTransactionTest, HTTPSViaHttpsProxy) { | |
| 4446 SessionDependencies session_deps(ProxyService::CreateFixed( | |
| 4447 "https://proxy:70")); | |
| 4448 | |
| 4449 HttpRequestInfo request; | |
| 4450 request.method = "GET"; | |
| 4451 request.url = GURL("https://www.google.com/"); | |
| 4452 request.load_flags = 0; | |
| 4453 | |
| 4454 MockWrite data_writes[] = { | |
| 4455 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 4456 "Host: www.google.com\r\n" | |
| 4457 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 4458 MockWrite("GET / HTTP/1.1\r\n" | |
| 4459 "Host: www.google.com\r\n" | |
| 4460 "Connection: keep-alive\r\n\r\n"), | |
| 4461 }; | |
| 4462 | |
| 4463 MockRead data_reads[] = { | |
| 4464 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
| 4465 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 4466 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 4467 MockRead("Content-Length: 100\r\n\r\n"), | |
| 4468 MockRead(SYNCHRONOUS, OK), | |
| 4469 }; | |
| 4470 | |
| 4471 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 4472 data_writes, arraysize(data_writes)); | |
| 4473 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
| 4474 SSLSocketDataProvider tunnel_ssl(ASYNC, OK); // SSL through the tunnel | |
| 4475 | |
| 4476 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 4477 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); | |
| 4478 session_deps.socket_factory.AddSSLSocketDataProvider(&tunnel_ssl); | |
| 4479 | |
| 4480 TestCompletionCallback callback; | |
| 4481 | |
| 4482 scoped_ptr<HttpTransaction> trans( | |
| 4483 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 4484 | |
| 4485 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4486 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4487 | |
| 4488 rv = callback.WaitForResult(); | |
| 4489 EXPECT_EQ(OK, rv); | |
| 4490 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4491 | |
| 4492 ASSERT_TRUE(response != NULL); | |
| 4493 | |
| 4494 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 4495 EXPECT_EQ(200, response->headers->response_code()); | |
| 4496 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 4497 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 4498 } | |
| 4499 | |
| 4500 // Test an HTTPS Proxy's ability to redirect a CONNECT request | |
| 4501 TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) { | |
| 4502 SessionDependencies session_deps( | |
| 4503 ProxyService::CreateFixed("https://proxy:70")); | |
| 4504 | |
| 4505 HttpRequestInfo request; | |
| 4506 request.method = "GET"; | |
| 4507 request.url = GURL("https://www.google.com/"); | |
| 4508 request.load_flags = 0; | |
| 4509 | |
| 4510 MockWrite data_writes[] = { | |
| 4511 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 4512 "Host: www.google.com\r\n" | |
| 4513 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 4514 }; | |
| 4515 | |
| 4516 MockRead data_reads[] = { | |
| 4517 MockRead("HTTP/1.1 302 Redirect\r\n"), | |
| 4518 MockRead("Location: http://login.example.com/\r\n"), | |
| 4519 MockRead("Content-Length: 0\r\n\r\n"), | |
| 4520 MockRead(SYNCHRONOUS, OK), | |
| 4521 }; | |
| 4522 | |
| 4523 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 4524 data_writes, arraysize(data_writes)); | |
| 4525 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
| 4526 | |
| 4527 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 4528 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); | |
| 4529 | |
| 4530 TestCompletionCallback callback; | |
| 4531 | |
| 4532 scoped_ptr<HttpTransaction> trans( | |
| 4533 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 4534 | |
| 4535 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4536 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4537 | |
| 4538 rv = callback.WaitForResult(); | |
| 4539 EXPECT_EQ(OK, rv); | |
| 4540 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4541 | |
| 4542 ASSERT_TRUE(response != NULL); | |
| 4543 | |
| 4544 EXPECT_EQ(302, response->headers->response_code()); | |
| 4545 std::string url; | |
| 4546 EXPECT_TRUE(response->headers->IsRedirect(&url)); | |
| 4547 EXPECT_EQ("http://login.example.com/", url); | |
| 4548 } | |
| 4549 | |
| 4550 // Test an HTTPS (SPDY) Proxy's ability to redirect a CONNECT request | |
| 4551 TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) { | |
| 4552 SessionDependencies session_deps( | |
| 4553 ProxyService::CreateFixed("https://proxy:70")); | |
| 4554 | |
| 4555 HttpRequestInfo request; | |
| 4556 request.method = "GET"; | |
| 4557 request.url = GURL("https://www.google.com/"); | |
| 4558 request.load_flags = 0; | |
| 4559 | |
| 4560 scoped_ptr<spdy::SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1)); | |
| 4561 scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyRstStream(1, spdy::CANCEL)); | |
| 4562 MockWrite data_writes[] = { | |
| 4563 CreateMockWrite(*conn.get(), 0, SYNCHRONOUS), | |
| 4564 }; | |
| 4565 | |
| 4566 static const char* const kExtraHeaders[] = { | |
| 4567 "location", | |
| 4568 "http://login.example.com/", | |
| 4569 }; | |
| 4570 scoped_ptr<spdy::SpdyFrame> resp( | |
| 4571 ConstructSpdySynReplyError("302 Redirect", kExtraHeaders, | |
| 4572 arraysize(kExtraHeaders)/2, 1)); | |
| 4573 MockRead data_reads[] = { | |
| 4574 CreateMockRead(*resp.get(), 1, SYNCHRONOUS), | |
| 4575 MockRead(ASYNC, 0, 2), // EOF | |
| 4576 }; | |
| 4577 | |
| 4578 scoped_ptr<DelayedSocketData> data( | |
| 4579 new DelayedSocketData( | |
| 4580 1, // wait for one write to finish before reading. | |
| 4581 data_reads, arraysize(data_reads), | |
| 4582 data_writes, arraysize(data_writes))); | |
| 4583 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
| 4584 proxy_ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 4585 | |
| 4586 session_deps.socket_factory.AddSocketDataProvider(data.get()); | |
| 4587 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); | |
| 4588 | |
| 4589 TestCompletionCallback callback; | |
| 4590 | |
| 4591 scoped_ptr<HttpTransaction> trans( | |
| 4592 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 4593 | |
| 4594 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4595 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4596 | |
| 4597 rv = callback.WaitForResult(); | |
| 4598 EXPECT_EQ(OK, rv); | |
| 4599 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4600 | |
| 4601 ASSERT_TRUE(response != NULL); | |
| 4602 | |
| 4603 EXPECT_EQ(302, response->headers->response_code()); | |
| 4604 std::string url; | |
| 4605 EXPECT_TRUE(response->headers->IsRedirect(&url)); | |
| 4606 EXPECT_EQ("http://login.example.com/", url); | |
| 4607 } | |
| 4608 | |
| 4609 // Test an HTTPS Proxy's ability to provide a response to a CONNECT request | |
| 4610 TEST_F(HttpNetworkTransactionTest, ErrorResponseTofHttpsConnectViaHttpsProxy) { | |
| 4611 SessionDependencies session_deps( | |
| 4612 ProxyService::CreateFixed("https://proxy:70")); | |
| 4613 | |
| 4614 HttpRequestInfo request; | |
| 4615 request.method = "GET"; | |
| 4616 request.url = GURL("https://www.google.com/"); | |
| 4617 request.load_flags = 0; | |
| 4618 | |
| 4619 MockWrite data_writes[] = { | |
| 4620 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 4621 "Host: www.google.com\r\n" | |
| 4622 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 4623 }; | |
| 4624 | |
| 4625 MockRead data_reads[] = { | |
| 4626 MockRead("HTTP/1.1 404 Not Found\r\n"), | |
| 4627 MockRead("Content-Length: 23\r\n\r\n"), | |
| 4628 MockRead("The host does not exist"), | |
| 4629 MockRead(SYNCHRONOUS, OK), | |
| 4630 }; | |
| 4631 | |
| 4632 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 4633 data_writes, arraysize(data_writes)); | |
| 4634 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
| 4635 | |
| 4636 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 4637 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); | |
| 4638 | |
| 4639 TestCompletionCallback callback; | |
| 4640 | |
| 4641 scoped_ptr<HttpTransaction> trans( | |
| 4642 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 4643 | |
| 4644 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4645 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4646 | |
| 4647 rv = callback.WaitForResult(); | |
| 4648 EXPECT_EQ(OK, rv); | |
| 4649 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4650 | |
| 4651 ASSERT_TRUE(response != NULL); | |
| 4652 | |
| 4653 EXPECT_EQ(404, response->headers->response_code()); | |
| 4654 EXPECT_EQ(23, response->headers->GetContentLength()); | |
| 4655 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 4656 EXPECT_FALSE(response->ssl_info.is_valid()); | |
| 4657 | |
| 4658 std::string response_data; | |
| 4659 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 4660 EXPECT_EQ("The host does not exist", response_data); | |
| 4661 } | |
| 4662 | |
| 4663 // Test an HTTPS (SPDY) Proxy's ability to provide a response to a CONNECT | |
| 4664 // request | |
| 4665 TEST_F(HttpNetworkTransactionTest, ErrorResponseTofHttpsConnectViaSpdyProxy) { | |
| 4666 SessionDependencies session_deps( | |
| 4667 ProxyService::CreateFixed("https://proxy:70")); | |
| 4668 | |
| 4669 HttpRequestInfo request; | |
| 4670 request.method = "GET"; | |
| 4671 request.url = GURL("https://www.google.com/"); | |
| 4672 request.load_flags = 0; | |
| 4673 | |
| 4674 scoped_ptr<spdy::SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1)); | |
| 4675 scoped_ptr<spdy::SpdyFrame> goaway(ConstructSpdyRstStream(1, spdy::CANCEL)); | |
| 4676 MockWrite data_writes[] = { | |
| 4677 CreateMockWrite(*conn.get(), 0, SYNCHRONOUS), | |
| 4678 }; | |
| 4679 | |
| 4680 static const char* const kExtraHeaders[] = { | |
| 4681 "location", | |
| 4682 "http://login.example.com/", | |
| 4683 }; | |
| 4684 scoped_ptr<spdy::SpdyFrame> resp( | |
| 4685 ConstructSpdySynReplyError("404 Not Found", kExtraHeaders, | |
| 4686 arraysize(kExtraHeaders)/2, 1)); | |
| 4687 scoped_ptr<spdy::SpdyFrame> body( | |
| 4688 ConstructSpdyBodyFrame(1, "The host does not exist", 23, true)); | |
| 4689 MockRead data_reads[] = { | |
| 4690 CreateMockRead(*resp.get(), 1, SYNCHRONOUS), | |
| 4691 CreateMockRead(*body.get(), 2, SYNCHRONOUS), | |
| 4692 MockRead(ASYNC, 0, 3), // EOF | |
| 4693 }; | |
| 4694 | |
| 4695 scoped_ptr<DelayedSocketData> data( | |
| 4696 new DelayedSocketData( | |
| 4697 1, // wait for one write to finish before reading. | |
| 4698 data_reads, arraysize(data_reads), | |
| 4699 data_writes, arraysize(data_writes))); | |
| 4700 SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy | |
| 4701 proxy_ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 4702 | |
| 4703 session_deps.socket_factory.AddSocketDataProvider(data.get()); | |
| 4704 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); | |
| 4705 | |
| 4706 TestCompletionCallback callback; | |
| 4707 | |
| 4708 scoped_ptr<HttpTransaction> trans( | |
| 4709 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 4710 | |
| 4711 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4712 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4713 | |
| 4714 rv = callback.WaitForResult(); | |
| 4715 EXPECT_EQ(OK, rv); | |
| 4716 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4717 | |
| 4718 ASSERT_TRUE(response != NULL); | |
| 4719 | |
| 4720 EXPECT_EQ(404, response->headers->response_code()); | |
| 4721 EXPECT_FALSE(response->ssl_info.is_valid()); | |
| 4722 | |
| 4723 std::string response_data; | |
| 4724 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 4725 EXPECT_EQ("The host does not exist", response_data); | |
| 4726 } | |
| 4727 | |
| 4728 // Test the request-challenge-retry sequence for basic auth, through | |
| 4729 // a SPDY proxy over a single SPDY session. | |
| 4730 TEST_F(HttpNetworkTransactionTest, BasicAuthSpdyProxy) { | |
| 4731 HttpRequestInfo request; | |
| 4732 request.method = "GET"; | |
| 4733 request.url = GURL("https://www.google.com/"); | |
| 4734 // when the no authentication data flag is set. | |
| 4735 request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; | |
| 4736 | |
| 4737 // Configure against https proxy server "myproxy:70". | |
| 4738 SessionDependencies session_deps( | |
| 4739 ProxyService::CreateFixed("https://myproxy:70")); | |
| 4740 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 4741 session_deps.net_log = log.bound().net_log(); | |
| 4742 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 4743 | |
| 4744 // Since we have proxy, should try to establish tunnel. | |
| 4745 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyConnect(NULL, 0, 1)); | |
| 4746 scoped_ptr<spdy::SpdyFrame> rst(ConstructSpdyRstStream(1, spdy::CANCEL)); | |
| 4747 | |
| 4748 // After calling trans->RestartWithAuth(), this is the request we should | |
| 4749 // be issuing -- the final header line contains the credentials. | |
| 4750 const char* const kAuthCredentials[] = { | |
| 4751 "proxy-authorization", "Basic Zm9vOmJhcg==", | |
| 4752 }; | |
| 4753 scoped_ptr<spdy::SpdyFrame> connect2( | |
| 4754 ConstructSpdyConnect(kAuthCredentials, arraysize(kAuthCredentials)/2, 3)); | |
| 4755 // fetch https://www.google.com/ via HTTP | |
| 4756 const char get[] = "GET / HTTP/1.1\r\n" | |
| 4757 "Host: www.google.com\r\n" | |
| 4758 "Connection: keep-alive\r\n\r\n"; | |
| 4759 scoped_ptr<spdy::SpdyFrame> wrapped_get( | |
| 4760 ConstructSpdyBodyFrame(3, get, strlen(get), false)); | |
| 4761 | |
| 4762 MockWrite spdy_writes[] = { | |
| 4763 CreateMockWrite(*req, 0, ASYNC), | |
| 4764 CreateMockWrite(*rst, 2, ASYNC), | |
| 4765 CreateMockWrite(*connect2, 3), | |
| 4766 CreateMockWrite(*wrapped_get, 5) | |
| 4767 }; | |
| 4768 | |
| 4769 // The proxy responds to the connect with a 407, using a persistent | |
| 4770 // connection. | |
| 4771 const char* const kAuthChallenge[] = { | |
| 4772 "status", "407 Proxy Authentication Required", | |
| 4773 "version", "HTTP/1.1", | |
| 4774 "proxy-authenticate", "Basic realm=\"MyRealm1\"", | |
| 4775 }; | |
| 4776 | |
| 4777 scoped_ptr<spdy::SpdyFrame> conn_auth_resp( | |
| 4778 ConstructSpdyControlFrame(NULL, | |
| 4779 0, | |
| 4780 false, | |
| 4781 1, | |
| 4782 LOWEST, | |
| 4783 spdy::SYN_REPLY, | |
| 4784 spdy::CONTROL_FLAG_NONE, | |
| 4785 kAuthChallenge, | |
| 4786 arraysize(kAuthChallenge))); | |
| 4787 | |
| 4788 scoped_ptr<spdy::SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 4789 const char resp[] = "HTTP/1.1 200 OK\r\n" | |
| 4790 "Content-Length: 5\r\n\r\n"; | |
| 4791 | |
| 4792 scoped_ptr<spdy::SpdyFrame> wrapped_get_resp( | |
| 4793 ConstructSpdyBodyFrame(3, resp, strlen(resp), false)); | |
| 4794 scoped_ptr<spdy::SpdyFrame> wrapped_body( | |
| 4795 ConstructSpdyBodyFrame(3, "hello", 5, false)); | |
| 4796 MockRead spdy_reads[] = { | |
| 4797 CreateMockRead(*conn_auth_resp, 1, ASYNC), | |
| 4798 CreateMockRead(*conn_resp, 4, ASYNC), | |
| 4799 CreateMockRead(*wrapped_get_resp, 5, ASYNC), | |
| 4800 CreateMockRead(*wrapped_body, 6, ASYNC), | |
| 4801 MockRead(SYNCHRONOUS, ERR_IO_PENDING), | |
| 4802 }; | |
| 4803 | |
| 4804 scoped_ptr<OrderedSocketData> spdy_data( | |
| 4805 new OrderedSocketData( | |
| 4806 spdy_reads, arraysize(spdy_reads), | |
| 4807 spdy_writes, arraysize(spdy_writes))); | |
| 4808 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 4809 // Negotiate SPDY to the proxy | |
| 4810 SSLSocketDataProvider proxy(ASYNC, OK); | |
| 4811 proxy.SetNextProto(SSLClientSocket::kProtoSPDY2); | |
| 4812 session_deps.socket_factory.AddSSLSocketDataProvider(&proxy); | |
| 4813 // Vanilla SSL to the server | |
| 4814 SSLSocketDataProvider server(ASYNC, OK); | |
| 4815 session_deps.socket_factory.AddSSLSocketDataProvider(&server); | |
| 4816 | |
| 4817 TestCompletionCallback callback1; | |
| 4818 | |
| 4819 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 4820 | |
| 4821 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 4822 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4823 | |
| 4824 rv = callback1.WaitForResult(); | |
| 4825 EXPECT_EQ(OK, rv); | |
| 4826 net::CapturingNetLog::EntryList entries; | |
| 4827 log.GetEntries(&entries); | |
| 4828 size_t pos = ExpectLogContainsSomewhere( | |
| 4829 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 4830 NetLog::PHASE_NONE); | |
| 4831 ExpectLogContainsSomewhere( | |
| 4832 entries, pos, | |
| 4833 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 4834 NetLog::PHASE_NONE); | |
| 4835 | |
| 4836 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4837 ASSERT_TRUE(response != NULL); | |
| 4838 ASSERT_FALSE(response->headers == NULL); | |
| 4839 EXPECT_EQ(407, response->headers->response_code()); | |
| 4840 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 4841 EXPECT_TRUE(response->auth_challenge.get() != NULL); | |
| 4842 EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); | |
| 4843 | |
| 4844 TestCompletionCallback callback2; | |
| 4845 | |
| 4846 rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), | |
| 4847 callback2.callback()); | |
| 4848 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4849 | |
| 4850 rv = callback2.WaitForResult(); | |
| 4851 EXPECT_EQ(OK, rv); | |
| 4852 | |
| 4853 response = trans->GetResponseInfo(); | |
| 4854 ASSERT_TRUE(response != NULL); | |
| 4855 | |
| 4856 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 4857 EXPECT_EQ(200, response->headers->response_code()); | |
| 4858 EXPECT_EQ(5, response->headers->GetContentLength()); | |
| 4859 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 4860 | |
| 4861 // The password prompt info should not be set. | |
| 4862 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 4863 | |
| 4864 trans.reset(); | |
| 4865 session->CloseAllConnections(); | |
| 4866 } | |
| 4867 | |
| 4868 // Test HTTPS connections to a site with a bad certificate, going through an | |
| 4869 // HTTPS proxy | |
| 4870 TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaHttpsProxy) { | |
| 4871 SessionDependencies session_deps(ProxyService::CreateFixed( | |
| 4872 "https://proxy:70")); | |
| 4873 | |
| 4874 HttpRequestInfo request; | |
| 4875 request.method = "GET"; | |
| 4876 request.url = GURL("https://www.google.com/"); | |
| 4877 request.load_flags = 0; | |
| 4878 | |
| 4879 // Attempt to fetch the URL from a server with a bad cert | |
| 4880 MockWrite bad_cert_writes[] = { | |
| 4881 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 4882 "Host: www.google.com\r\n" | |
| 4883 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 4884 }; | |
| 4885 | |
| 4886 MockRead bad_cert_reads[] = { | |
| 4887 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
| 4888 MockRead(SYNCHRONOUS, OK) | |
| 4889 }; | |
| 4890 | |
| 4891 // Attempt to fetch the URL with a good cert | |
| 4892 MockWrite good_data_writes[] = { | |
| 4893 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 4894 "Host: www.google.com\r\n" | |
| 4895 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 4896 MockWrite("GET / HTTP/1.1\r\n" | |
| 4897 "Host: www.google.com\r\n" | |
| 4898 "Connection: keep-alive\r\n\r\n"), | |
| 4899 }; | |
| 4900 | |
| 4901 MockRead good_cert_reads[] = { | |
| 4902 MockRead("HTTP/1.0 200 Connected\r\n\r\n"), | |
| 4903 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 4904 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 4905 MockRead("Content-Length: 100\r\n\r\n"), | |
| 4906 MockRead(SYNCHRONOUS, OK), | |
| 4907 }; | |
| 4908 | |
| 4909 StaticSocketDataProvider ssl_bad_certificate( | |
| 4910 bad_cert_reads, arraysize(bad_cert_reads), | |
| 4911 bad_cert_writes, arraysize(bad_cert_writes)); | |
| 4912 StaticSocketDataProvider data(good_cert_reads, arraysize(good_cert_reads), | |
| 4913 good_data_writes, arraysize(good_data_writes)); | |
| 4914 SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); | |
| 4915 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 4916 | |
| 4917 // SSL to the proxy, then CONNECT request, then SSL with bad certificate | |
| 4918 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 4919 session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); | |
| 4920 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); | |
| 4921 | |
| 4922 // SSL to the proxy, then CONNECT request, then valid SSL certificate | |
| 4923 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 4924 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 4925 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 4926 | |
| 4927 TestCompletionCallback callback; | |
| 4928 | |
| 4929 scoped_ptr<HttpTransaction> trans( | |
| 4930 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 4931 | |
| 4932 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4933 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4934 | |
| 4935 rv = callback.WaitForResult(); | |
| 4936 EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); | |
| 4937 | |
| 4938 rv = trans->RestartIgnoringLastError(callback.callback()); | |
| 4939 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4940 | |
| 4941 rv = callback.WaitForResult(); | |
| 4942 EXPECT_EQ(OK, rv); | |
| 4943 | |
| 4944 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 4945 | |
| 4946 ASSERT_TRUE(response != NULL); | |
| 4947 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 4948 } | |
| 4949 | |
| 4950 TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgent) { | |
| 4951 HttpRequestInfo request; | |
| 4952 request.method = "GET"; | |
| 4953 request.url = GURL("http://www.google.com/"); | |
| 4954 request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, | |
| 4955 "Chromium Ultra Awesome X Edition"); | |
| 4956 | |
| 4957 SessionDependencies session_deps; | |
| 4958 scoped_ptr<HttpTransaction> trans( | |
| 4959 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 4960 | |
| 4961 MockWrite data_writes[] = { | |
| 4962 MockWrite("GET / HTTP/1.1\r\n" | |
| 4963 "Host: www.google.com\r\n" | |
| 4964 "Connection: keep-alive\r\n" | |
| 4965 "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"), | |
| 4966 }; | |
| 4967 | |
| 4968 // Lastly, the server responds with the actual content. | |
| 4969 MockRead data_reads[] = { | |
| 4970 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 4971 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 4972 MockRead("Content-Length: 100\r\n\r\n"), | |
| 4973 MockRead(SYNCHRONOUS, OK), | |
| 4974 }; | |
| 4975 | |
| 4976 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 4977 data_writes, arraysize(data_writes)); | |
| 4978 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 4979 | |
| 4980 TestCompletionCallback callback; | |
| 4981 | |
| 4982 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 4983 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 4984 | |
| 4985 rv = callback.WaitForResult(); | |
| 4986 EXPECT_EQ(OK, rv); | |
| 4987 } | |
| 4988 | |
| 4989 TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgentOverTunnel) { | |
| 4990 HttpRequestInfo request; | |
| 4991 request.method = "GET"; | |
| 4992 request.url = GURL("https://www.google.com/"); | |
| 4993 request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, | |
| 4994 "Chromium Ultra Awesome X Edition"); | |
| 4995 | |
| 4996 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 4997 scoped_ptr<HttpTransaction> trans( | |
| 4998 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 4999 | |
| 5000 MockWrite data_writes[] = { | |
| 5001 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 5002 "Host: www.google.com\r\n" | |
| 5003 "Proxy-Connection: keep-alive\r\n" | |
| 5004 "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"), | |
| 5005 }; | |
| 5006 MockRead data_reads[] = { | |
| 5007 // Return an error, so the transaction stops here (this test isn't | |
| 5008 // interested in the rest). | |
| 5009 MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), | |
| 5010 MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 5011 MockRead("Proxy-Connection: close\r\n\r\n"), | |
| 5012 }; | |
| 5013 | |
| 5014 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5015 data_writes, arraysize(data_writes)); | |
| 5016 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5017 | |
| 5018 TestCompletionCallback callback; | |
| 5019 | |
| 5020 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5021 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5022 | |
| 5023 rv = callback.WaitForResult(); | |
| 5024 EXPECT_EQ(OK, rv); | |
| 5025 } | |
| 5026 | |
| 5027 TEST_F(HttpNetworkTransactionTest, BuildRequest_Referer) { | |
| 5028 HttpRequestInfo request; | |
| 5029 request.method = "GET"; | |
| 5030 request.url = GURL("http://www.google.com/"); | |
| 5031 request.load_flags = 0; | |
| 5032 request.extra_headers.SetHeader(HttpRequestHeaders::kReferer, | |
| 5033 "http://the.previous.site.com/"); | |
| 5034 | |
| 5035 SessionDependencies session_deps; | |
| 5036 scoped_ptr<HttpTransaction> trans( | |
| 5037 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5038 | |
| 5039 MockWrite data_writes[] = { | |
| 5040 MockWrite("GET / HTTP/1.1\r\n" | |
| 5041 "Host: www.google.com\r\n" | |
| 5042 "Connection: keep-alive\r\n" | |
| 5043 "Referer: http://the.previous.site.com/\r\n\r\n"), | |
| 5044 }; | |
| 5045 | |
| 5046 // Lastly, the server responds with the actual content. | |
| 5047 MockRead data_reads[] = { | |
| 5048 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5049 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 5050 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5051 MockRead(SYNCHRONOUS, OK), | |
| 5052 }; | |
| 5053 | |
| 5054 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5055 data_writes, arraysize(data_writes)); | |
| 5056 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5057 | |
| 5058 TestCompletionCallback callback; | |
| 5059 | |
| 5060 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5061 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5062 | |
| 5063 rv = callback.WaitForResult(); | |
| 5064 EXPECT_EQ(OK, rv); | |
| 5065 } | |
| 5066 | |
| 5067 TEST_F(HttpNetworkTransactionTest, BuildRequest_PostContentLengthZero) { | |
| 5068 HttpRequestInfo request; | |
| 5069 request.method = "POST"; | |
| 5070 request.url = GURL("http://www.google.com/"); | |
| 5071 | |
| 5072 SessionDependencies session_deps; | |
| 5073 scoped_ptr<HttpTransaction> trans( | |
| 5074 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5075 | |
| 5076 MockWrite data_writes[] = { | |
| 5077 MockWrite("POST / HTTP/1.1\r\n" | |
| 5078 "Host: www.google.com\r\n" | |
| 5079 "Connection: keep-alive\r\n" | |
| 5080 "Content-Length: 0\r\n\r\n"), | |
| 5081 }; | |
| 5082 | |
| 5083 // Lastly, the server responds with the actual content. | |
| 5084 MockRead data_reads[] = { | |
| 5085 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5086 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 5087 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5088 MockRead(SYNCHRONOUS, OK), | |
| 5089 }; | |
| 5090 | |
| 5091 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5092 data_writes, arraysize(data_writes)); | |
| 5093 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5094 | |
| 5095 TestCompletionCallback callback; | |
| 5096 | |
| 5097 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5098 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5099 | |
| 5100 rv = callback.WaitForResult(); | |
| 5101 EXPECT_EQ(OK, rv); | |
| 5102 } | |
| 5103 | |
| 5104 TEST_F(HttpNetworkTransactionTest, BuildRequest_PutContentLengthZero) { | |
| 5105 HttpRequestInfo request; | |
| 5106 request.method = "PUT"; | |
| 5107 request.url = GURL("http://www.google.com/"); | |
| 5108 | |
| 5109 SessionDependencies session_deps; | |
| 5110 scoped_ptr<HttpTransaction> trans( | |
| 5111 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5112 | |
| 5113 MockWrite data_writes[] = { | |
| 5114 MockWrite("PUT / HTTP/1.1\r\n" | |
| 5115 "Host: www.google.com\r\n" | |
| 5116 "Connection: keep-alive\r\n" | |
| 5117 "Content-Length: 0\r\n\r\n"), | |
| 5118 }; | |
| 5119 | |
| 5120 // Lastly, the server responds with the actual content. | |
| 5121 MockRead data_reads[] = { | |
| 5122 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5123 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 5124 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5125 MockRead(SYNCHRONOUS, OK), | |
| 5126 }; | |
| 5127 | |
| 5128 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5129 data_writes, arraysize(data_writes)); | |
| 5130 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5131 | |
| 5132 TestCompletionCallback callback; | |
| 5133 | |
| 5134 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5135 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5136 | |
| 5137 rv = callback.WaitForResult(); | |
| 5138 EXPECT_EQ(OK, rv); | |
| 5139 } | |
| 5140 | |
| 5141 TEST_F(HttpNetworkTransactionTest, BuildRequest_HeadContentLengthZero) { | |
| 5142 HttpRequestInfo request; | |
| 5143 request.method = "HEAD"; | |
| 5144 request.url = GURL("http://www.google.com/"); | |
| 5145 | |
| 5146 SessionDependencies session_deps; | |
| 5147 scoped_ptr<HttpTransaction> trans( | |
| 5148 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5149 | |
| 5150 MockWrite data_writes[] = { | |
| 5151 MockWrite("HEAD / HTTP/1.1\r\n" | |
| 5152 "Host: www.google.com\r\n" | |
| 5153 "Connection: keep-alive\r\n" | |
| 5154 "Content-Length: 0\r\n\r\n"), | |
| 5155 }; | |
| 5156 | |
| 5157 // Lastly, the server responds with the actual content. | |
| 5158 MockRead data_reads[] = { | |
| 5159 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5160 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 5161 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5162 MockRead(SYNCHRONOUS, OK), | |
| 5163 }; | |
| 5164 | |
| 5165 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5166 data_writes, arraysize(data_writes)); | |
| 5167 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5168 | |
| 5169 TestCompletionCallback callback; | |
| 5170 | |
| 5171 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5172 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5173 | |
| 5174 rv = callback.WaitForResult(); | |
| 5175 EXPECT_EQ(OK, rv); | |
| 5176 } | |
| 5177 | |
| 5178 TEST_F(HttpNetworkTransactionTest, BuildRequest_CacheControlNoCache) { | |
| 5179 HttpRequestInfo request; | |
| 5180 request.method = "GET"; | |
| 5181 request.url = GURL("http://www.google.com/"); | |
| 5182 request.load_flags = LOAD_BYPASS_CACHE; | |
| 5183 | |
| 5184 SessionDependencies session_deps; | |
| 5185 scoped_ptr<HttpTransaction> trans( | |
| 5186 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5187 | |
| 5188 MockWrite data_writes[] = { | |
| 5189 MockWrite("GET / HTTP/1.1\r\n" | |
| 5190 "Host: www.google.com\r\n" | |
| 5191 "Connection: keep-alive\r\n" | |
| 5192 "Pragma: no-cache\r\n" | |
| 5193 "Cache-Control: no-cache\r\n\r\n"), | |
| 5194 }; | |
| 5195 | |
| 5196 // Lastly, the server responds with the actual content. | |
| 5197 MockRead data_reads[] = { | |
| 5198 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5199 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 5200 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5201 MockRead(SYNCHRONOUS, OK), | |
| 5202 }; | |
| 5203 | |
| 5204 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5205 data_writes, arraysize(data_writes)); | |
| 5206 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5207 | |
| 5208 TestCompletionCallback callback; | |
| 5209 | |
| 5210 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5211 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5212 | |
| 5213 rv = callback.WaitForResult(); | |
| 5214 EXPECT_EQ(OK, rv); | |
| 5215 } | |
| 5216 | |
| 5217 TEST_F(HttpNetworkTransactionTest, | |
| 5218 BuildRequest_CacheControlValidateCache) { | |
| 5219 HttpRequestInfo request; | |
| 5220 request.method = "GET"; | |
| 5221 request.url = GURL("http://www.google.com/"); | |
| 5222 request.load_flags = LOAD_VALIDATE_CACHE; | |
| 5223 | |
| 5224 SessionDependencies session_deps; | |
| 5225 scoped_ptr<HttpTransaction> trans( | |
| 5226 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5227 | |
| 5228 MockWrite data_writes[] = { | |
| 5229 MockWrite("GET / HTTP/1.1\r\n" | |
| 5230 "Host: www.google.com\r\n" | |
| 5231 "Connection: keep-alive\r\n" | |
| 5232 "Cache-Control: max-age=0\r\n\r\n"), | |
| 5233 }; | |
| 5234 | |
| 5235 // Lastly, the server responds with the actual content. | |
| 5236 MockRead data_reads[] = { | |
| 5237 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5238 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 5239 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5240 MockRead(SYNCHRONOUS, OK), | |
| 5241 }; | |
| 5242 | |
| 5243 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5244 data_writes, arraysize(data_writes)); | |
| 5245 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5246 | |
| 5247 TestCompletionCallback callback; | |
| 5248 | |
| 5249 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5250 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5251 | |
| 5252 rv = callback.WaitForResult(); | |
| 5253 EXPECT_EQ(OK, rv); | |
| 5254 } | |
| 5255 | |
| 5256 TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) { | |
| 5257 HttpRequestInfo request; | |
| 5258 request.method = "GET"; | |
| 5259 request.url = GURL("http://www.google.com/"); | |
| 5260 request.extra_headers.SetHeader("FooHeader", "Bar"); | |
| 5261 | |
| 5262 SessionDependencies session_deps; | |
| 5263 scoped_ptr<HttpTransaction> trans( | |
| 5264 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5265 | |
| 5266 MockWrite data_writes[] = { | |
| 5267 MockWrite("GET / HTTP/1.1\r\n" | |
| 5268 "Host: www.google.com\r\n" | |
| 5269 "Connection: keep-alive\r\n" | |
| 5270 "FooHeader: Bar\r\n\r\n"), | |
| 5271 }; | |
| 5272 | |
| 5273 // Lastly, the server responds with the actual content. | |
| 5274 MockRead data_reads[] = { | |
| 5275 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5276 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 5277 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5278 MockRead(SYNCHRONOUS, OK), | |
| 5279 }; | |
| 5280 | |
| 5281 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5282 data_writes, arraysize(data_writes)); | |
| 5283 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5284 | |
| 5285 TestCompletionCallback callback; | |
| 5286 | |
| 5287 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5288 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5289 | |
| 5290 rv = callback.WaitForResult(); | |
| 5291 EXPECT_EQ(OK, rv); | |
| 5292 } | |
| 5293 | |
| 5294 TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeadersStripped) { | |
| 5295 HttpRequestInfo request; | |
| 5296 request.method = "GET"; | |
| 5297 request.url = GURL("http://www.google.com/"); | |
| 5298 request.extra_headers.SetHeader("referer", "www.foo.com"); | |
| 5299 request.extra_headers.SetHeader("hEllo", "Kitty"); | |
| 5300 request.extra_headers.SetHeader("FoO", "bar"); | |
| 5301 | |
| 5302 SessionDependencies session_deps; | |
| 5303 scoped_ptr<HttpTransaction> trans( | |
| 5304 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5305 | |
| 5306 MockWrite data_writes[] = { | |
| 5307 MockWrite("GET / HTTP/1.1\r\n" | |
| 5308 "Host: www.google.com\r\n" | |
| 5309 "Connection: keep-alive\r\n" | |
| 5310 "referer: www.foo.com\r\n" | |
| 5311 "hEllo: Kitty\r\n" | |
| 5312 "FoO: bar\r\n\r\n"), | |
| 5313 }; | |
| 5314 | |
| 5315 // Lastly, the server responds with the actual content. | |
| 5316 MockRead data_reads[] = { | |
| 5317 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5318 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 5319 MockRead("Content-Length: 100\r\n\r\n"), | |
| 5320 MockRead(SYNCHRONOUS, OK), | |
| 5321 }; | |
| 5322 | |
| 5323 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5324 data_writes, arraysize(data_writes)); | |
| 5325 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5326 | |
| 5327 TestCompletionCallback callback; | |
| 5328 | |
| 5329 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5330 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5331 | |
| 5332 rv = callback.WaitForResult(); | |
| 5333 EXPECT_EQ(OK, rv); | |
| 5334 } | |
| 5335 | |
| 5336 // http://crbug.com/112682 | |
| 5337 #if defined(OS_MACOSX) | |
| 5338 #define MAYBE_SOCKS4_HTTP_GET DISABLED_SOCKS4_HTTP_GET | |
| 5339 #else | |
| 5340 #define MAYBE_SOCKS4_HTTP_GET SOCKS4_HTTP_GET | |
| 5341 #endif | |
| 5342 | |
| 5343 TEST_F(HttpNetworkTransactionTest, MAYBE_SOCKS4_HTTP_GET) { | |
| 5344 HttpRequestInfo request; | |
| 5345 request.method = "GET"; | |
| 5346 request.url = GURL("http://www.google.com/"); | |
| 5347 request.load_flags = 0; | |
| 5348 | |
| 5349 SessionDependencies session_deps( | |
| 5350 ProxyService::CreateFixed("socks4://myproxy:1080")); | |
| 5351 | |
| 5352 scoped_ptr<HttpTransaction> trans( | |
| 5353 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5354 | |
| 5355 char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 }; | |
| 5356 char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; | |
| 5357 | |
| 5358 MockWrite data_writes[] = { | |
| 5359 MockWrite(ASYNC, write_buffer, arraysize(write_buffer)), | |
| 5360 MockWrite("GET / HTTP/1.1\r\n" | |
| 5361 "Host: www.google.com\r\n" | |
| 5362 "Connection: keep-alive\r\n\r\n") | |
| 5363 }; | |
| 5364 | |
| 5365 MockRead data_reads[] = { | |
| 5366 MockRead(ASYNC, read_buffer, arraysize(read_buffer)), | |
| 5367 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5368 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
| 5369 MockRead("Payload"), | |
| 5370 MockRead(SYNCHRONOUS, OK) | |
| 5371 }; | |
| 5372 | |
| 5373 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5374 data_writes, arraysize(data_writes)); | |
| 5375 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5376 | |
| 5377 TestCompletionCallback callback; | |
| 5378 | |
| 5379 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5380 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5381 | |
| 5382 rv = callback.WaitForResult(); | |
| 5383 EXPECT_EQ(OK, rv); | |
| 5384 | |
| 5385 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5386 ASSERT_TRUE(response != NULL); | |
| 5387 | |
| 5388 std::string response_text; | |
| 5389 rv = ReadTransaction(trans.get(), &response_text); | |
| 5390 EXPECT_EQ(OK, rv); | |
| 5391 EXPECT_EQ("Payload", response_text); | |
| 5392 } | |
| 5393 | |
| 5394 // http://crbug.com/112682 | |
| 5395 #if defined(OS_MACOSX) | |
| 5396 #define MAYBE_SOCKS4_SSL_GET DISABLED_SOCKS4_SSL_GET | |
| 5397 #else | |
| 5398 #define MAYBE_SOCKS4_SSL_GET SOCKS4_SSL_GET | |
| 5399 #endif | |
| 5400 | |
| 5401 TEST_F(HttpNetworkTransactionTest, MAYBE_SOCKS4_SSL_GET) { | |
| 5402 HttpRequestInfo request; | |
| 5403 request.method = "GET"; | |
| 5404 request.url = GURL("https://www.google.com/"); | |
| 5405 request.load_flags = 0; | |
| 5406 | |
| 5407 SessionDependencies session_deps( | |
| 5408 ProxyService::CreateFixed("socks4://myproxy:1080")); | |
| 5409 | |
| 5410 scoped_ptr<HttpTransaction> trans( | |
| 5411 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5412 | |
| 5413 unsigned char write_buffer[] = { 0x04, 0x01, 0x01, 0xBB, 127, 0, 0, 1, 0 }; | |
| 5414 unsigned char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; | |
| 5415 | |
| 5416 MockWrite data_writes[] = { | |
| 5417 MockWrite(ASYNC, reinterpret_cast<char*>(write_buffer), | |
| 5418 arraysize(write_buffer)), | |
| 5419 MockWrite("GET / HTTP/1.1\r\n" | |
| 5420 "Host: www.google.com\r\n" | |
| 5421 "Connection: keep-alive\r\n\r\n") | |
| 5422 }; | |
| 5423 | |
| 5424 MockRead data_reads[] = { | |
| 5425 MockWrite(ASYNC, reinterpret_cast<char*>(read_buffer), | |
| 5426 arraysize(read_buffer)), | |
| 5427 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5428 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
| 5429 MockRead("Payload"), | |
| 5430 MockRead(SYNCHRONOUS, OK) | |
| 5431 }; | |
| 5432 | |
| 5433 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5434 data_writes, arraysize(data_writes)); | |
| 5435 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5436 | |
| 5437 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 5438 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 5439 | |
| 5440 TestCompletionCallback callback; | |
| 5441 | |
| 5442 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5443 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5444 | |
| 5445 rv = callback.WaitForResult(); | |
| 5446 EXPECT_EQ(OK, rv); | |
| 5447 | |
| 5448 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5449 ASSERT_TRUE(response != NULL); | |
| 5450 | |
| 5451 std::string response_text; | |
| 5452 rv = ReadTransaction(trans.get(), &response_text); | |
| 5453 EXPECT_EQ(OK, rv); | |
| 5454 EXPECT_EQ("Payload", response_text); | |
| 5455 } | |
| 5456 | |
| 5457 TEST_F(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) { | |
| 5458 HttpRequestInfo request; | |
| 5459 request.method = "GET"; | |
| 5460 request.url = GURL("http://www.google.com/"); | |
| 5461 request.load_flags = 0; | |
| 5462 | |
| 5463 SessionDependencies session_deps( | |
| 5464 ProxyService::CreateFixed("socks5://myproxy:1080")); | |
| 5465 | |
| 5466 scoped_ptr<HttpTransaction> trans( | |
| 5467 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5468 | |
| 5469 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; | |
| 5470 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 }; | |
| 5471 const char kSOCKS5OkRequest[] = { | |
| 5472 0x05, // Version | |
| 5473 0x01, // Command (CONNECT) | |
| 5474 0x00, // Reserved. | |
| 5475 0x03, // Address type (DOMAINNAME). | |
| 5476 0x0E, // Length of domain (14) | |
| 5477 // Domain string: | |
| 5478 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', | |
| 5479 0x00, 0x50, // 16-bit port (80) | |
| 5480 }; | |
| 5481 const char kSOCKS5OkResponse[] = | |
| 5482 { 0x05, 0x00, 0x00, 0x01, 127, 0, 0, 1, 0x00, 0x50 }; | |
| 5483 | |
| 5484 MockWrite data_writes[] = { | |
| 5485 MockWrite(ASYNC, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)), | |
| 5486 MockWrite(ASYNC, kSOCKS5OkRequest, arraysize(kSOCKS5OkRequest)), | |
| 5487 MockWrite("GET / HTTP/1.1\r\n" | |
| 5488 "Host: www.google.com\r\n" | |
| 5489 "Connection: keep-alive\r\n\r\n") | |
| 5490 }; | |
| 5491 | |
| 5492 MockRead data_reads[] = { | |
| 5493 MockWrite(ASYNC, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), | |
| 5494 MockWrite(ASYNC, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)), | |
| 5495 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5496 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
| 5497 MockRead("Payload"), | |
| 5498 MockRead(SYNCHRONOUS, OK) | |
| 5499 }; | |
| 5500 | |
| 5501 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5502 data_writes, arraysize(data_writes)); | |
| 5503 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5504 | |
| 5505 TestCompletionCallback callback; | |
| 5506 | |
| 5507 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5508 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5509 | |
| 5510 rv = callback.WaitForResult(); | |
| 5511 EXPECT_EQ(OK, rv); | |
| 5512 | |
| 5513 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5514 ASSERT_TRUE(response != NULL); | |
| 5515 | |
| 5516 std::string response_text; | |
| 5517 rv = ReadTransaction(trans.get(), &response_text); | |
| 5518 EXPECT_EQ(OK, rv); | |
| 5519 EXPECT_EQ("Payload", response_text); | |
| 5520 } | |
| 5521 | |
| 5522 TEST_F(HttpNetworkTransactionTest, SOCKS5_SSL_GET) { | |
| 5523 HttpRequestInfo request; | |
| 5524 request.method = "GET"; | |
| 5525 request.url = GURL("https://www.google.com/"); | |
| 5526 request.load_flags = 0; | |
| 5527 | |
| 5528 SessionDependencies session_deps( | |
| 5529 ProxyService::CreateFixed("socks5://myproxy:1080")); | |
| 5530 | |
| 5531 scoped_ptr<HttpTransaction> trans( | |
| 5532 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5533 | |
| 5534 const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; | |
| 5535 const char kSOCKS5GreetResponse[] = { 0x05, 0x00 }; | |
| 5536 const unsigned char kSOCKS5OkRequest[] = { | |
| 5537 0x05, // Version | |
| 5538 0x01, // Command (CONNECT) | |
| 5539 0x00, // Reserved. | |
| 5540 0x03, // Address type (DOMAINNAME). | |
| 5541 0x0E, // Length of domain (14) | |
| 5542 // Domain string: | |
| 5543 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', | |
| 5544 0x01, 0xBB, // 16-bit port (443) | |
| 5545 }; | |
| 5546 | |
| 5547 const char kSOCKS5OkResponse[] = | |
| 5548 { 0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0x00, 0x00 }; | |
| 5549 | |
| 5550 MockWrite data_writes[] = { | |
| 5551 MockWrite(ASYNC, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)), | |
| 5552 MockWrite(ASYNC, reinterpret_cast<const char*>(kSOCKS5OkRequest), | |
| 5553 arraysize(kSOCKS5OkRequest)), | |
| 5554 MockWrite("GET / HTTP/1.1\r\n" | |
| 5555 "Host: www.google.com\r\n" | |
| 5556 "Connection: keep-alive\r\n\r\n") | |
| 5557 }; | |
| 5558 | |
| 5559 MockRead data_reads[] = { | |
| 5560 MockWrite(ASYNC, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), | |
| 5561 MockWrite(ASYNC, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)), | |
| 5562 MockRead("HTTP/1.0 200 OK\r\n"), | |
| 5563 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), | |
| 5564 MockRead("Payload"), | |
| 5565 MockRead(SYNCHRONOUS, OK) | |
| 5566 }; | |
| 5567 | |
| 5568 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 5569 data_writes, arraysize(data_writes)); | |
| 5570 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5571 | |
| 5572 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 5573 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 5574 | |
| 5575 TestCompletionCallback callback; | |
| 5576 | |
| 5577 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5578 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5579 | |
| 5580 rv = callback.WaitForResult(); | |
| 5581 EXPECT_EQ(OK, rv); | |
| 5582 | |
| 5583 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5584 ASSERT_TRUE(response != NULL); | |
| 5585 | |
| 5586 std::string response_text; | |
| 5587 rv = ReadTransaction(trans.get(), &response_text); | |
| 5588 EXPECT_EQ(OK, rv); | |
| 5589 EXPECT_EQ("Payload", response_text); | |
| 5590 } | |
| 5591 | |
| 5592 // Tests that for connection endpoints the group names are correctly set. | |
| 5593 | |
| 5594 struct GroupNameTest { | |
| 5595 std::string proxy_server; | |
| 5596 std::string url; | |
| 5597 std::string expected_group_name; | |
| 5598 bool ssl; | |
| 5599 }; | |
| 5600 | |
| 5601 scoped_refptr<HttpNetworkSession> SetupSessionForGroupNameTests( | |
| 5602 SessionDependencies* session_deps) { | |
| 5603 scoped_refptr<HttpNetworkSession> session(CreateSession(session_deps)); | |
| 5604 | |
| 5605 HttpServerProperties* http_server_properties = | |
| 5606 session->http_server_properties(); | |
| 5607 http_server_properties->SetAlternateProtocol( | |
| 5608 HostPortPair("host.with.alternate", 80), 443, | |
| 5609 NPN_SPDY_21); | |
| 5610 | |
| 5611 return session; | |
| 5612 } | |
| 5613 | |
| 5614 int GroupNameTransactionHelper( | |
| 5615 const std::string& url, | |
| 5616 const scoped_refptr<HttpNetworkSession>& session) { | |
| 5617 HttpRequestInfo request; | |
| 5618 request.method = "GET"; | |
| 5619 request.url = GURL(url); | |
| 5620 request.load_flags = 0; | |
| 5621 | |
| 5622 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 5623 | |
| 5624 TestCompletionCallback callback; | |
| 5625 | |
| 5626 // We do not complete this request, the dtor will clean the transaction up. | |
| 5627 return trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5628 } | |
| 5629 | |
| 5630 TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) { | |
| 5631 const GroupNameTest tests[] = { | |
| 5632 { | |
| 5633 "", // unused | |
| 5634 "http://www.google.com/direct", | |
| 5635 "www.google.com:80", | |
| 5636 false, | |
| 5637 }, | |
| 5638 { | |
| 5639 "", // unused | |
| 5640 "http://[2001:1418:13:1::25]/direct", | |
| 5641 "[2001:1418:13:1::25]:80", | |
| 5642 false, | |
| 5643 }, | |
| 5644 | |
| 5645 // SSL Tests | |
| 5646 { | |
| 5647 "", // unused | |
| 5648 "https://www.google.com/direct_ssl", | |
| 5649 "ssl/www.google.com:443", | |
| 5650 true, | |
| 5651 }, | |
| 5652 { | |
| 5653 "", // unused | |
| 5654 "https://[2001:1418:13:1::25]/direct", | |
| 5655 "ssl/[2001:1418:13:1::25]:443", | |
| 5656 true, | |
| 5657 }, | |
| 5658 { | |
| 5659 "", // unused | |
| 5660 "http://host.with.alternate/direct", | |
| 5661 "ssl/host.with.alternate:443", | |
| 5662 true, | |
| 5663 }, | |
| 5664 }; | |
| 5665 | |
| 5666 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 5667 | |
| 5668 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { | |
| 5669 SessionDependencies session_deps( | |
| 5670 ProxyService::CreateFixed(tests[i].proxy_server)); | |
| 5671 scoped_refptr<HttpNetworkSession> session( | |
| 5672 SetupSessionForGroupNameTests(&session_deps)); | |
| 5673 | |
| 5674 HttpNetworkSessionPeer peer(session); | |
| 5675 CaptureGroupNameTransportSocketPool* transport_conn_pool = | |
| 5676 new CaptureGroupNameTransportSocketPool(NULL, NULL); | |
| 5677 CaptureGroupNameSSLSocketPool* ssl_conn_pool = | |
| 5678 new CaptureGroupNameSSLSocketPool(NULL, NULL); | |
| 5679 MockClientSocketPoolManager* mock_pool_manager = | |
| 5680 new MockClientSocketPoolManager; | |
| 5681 mock_pool_manager->SetTransportSocketPool(transport_conn_pool); | |
| 5682 mock_pool_manager->SetSSLSocketPool(ssl_conn_pool); | |
| 5683 peer.SetClientSocketPoolManager(mock_pool_manager); | |
| 5684 | |
| 5685 EXPECT_EQ(ERR_IO_PENDING, | |
| 5686 GroupNameTransactionHelper(tests[i].url, session)); | |
| 5687 if (tests[i].ssl) | |
| 5688 EXPECT_EQ(tests[i].expected_group_name, | |
| 5689 ssl_conn_pool->last_group_name_received()); | |
| 5690 else | |
| 5691 EXPECT_EQ(tests[i].expected_group_name, | |
| 5692 transport_conn_pool->last_group_name_received()); | |
| 5693 } | |
| 5694 | |
| 5695 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 5696 } | |
| 5697 | |
| 5698 TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) { | |
| 5699 const GroupNameTest tests[] = { | |
| 5700 { | |
| 5701 "http_proxy", | |
| 5702 "http://www.google.com/http_proxy_normal", | |
| 5703 "www.google.com:80", | |
| 5704 false, | |
| 5705 }, | |
| 5706 | |
| 5707 // SSL Tests | |
| 5708 { | |
| 5709 "http_proxy", | |
| 5710 "https://www.google.com/http_connect_ssl", | |
| 5711 "ssl/www.google.com:443", | |
| 5712 true, | |
| 5713 }, | |
| 5714 | |
| 5715 { | |
| 5716 "http_proxy", | |
| 5717 "http://host.with.alternate/direct", | |
| 5718 "ssl/host.with.alternate:443", | |
| 5719 true, | |
| 5720 }, | |
| 5721 }; | |
| 5722 | |
| 5723 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 5724 | |
| 5725 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { | |
| 5726 SessionDependencies session_deps( | |
| 5727 ProxyService::CreateFixed(tests[i].proxy_server)); | |
| 5728 scoped_refptr<HttpNetworkSession> session( | |
| 5729 SetupSessionForGroupNameTests(&session_deps)); | |
| 5730 | |
| 5731 HttpNetworkSessionPeer peer(session); | |
| 5732 | |
| 5733 HostPortPair proxy_host("http_proxy", 80); | |
| 5734 CaptureGroupNameHttpProxySocketPool* http_proxy_pool = | |
| 5735 new CaptureGroupNameHttpProxySocketPool(NULL, NULL); | |
| 5736 CaptureGroupNameSSLSocketPool* ssl_conn_pool = | |
| 5737 new CaptureGroupNameSSLSocketPool(NULL, NULL); | |
| 5738 | |
| 5739 MockClientSocketPoolManager* mock_pool_manager = | |
| 5740 new MockClientSocketPoolManager; | |
| 5741 mock_pool_manager->SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool); | |
| 5742 mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); | |
| 5743 peer.SetClientSocketPoolManager(mock_pool_manager); | |
| 5744 | |
| 5745 EXPECT_EQ(ERR_IO_PENDING, | |
| 5746 GroupNameTransactionHelper(tests[i].url, session)); | |
| 5747 if (tests[i].ssl) | |
| 5748 EXPECT_EQ(tests[i].expected_group_name, | |
| 5749 ssl_conn_pool->last_group_name_received()); | |
| 5750 else | |
| 5751 EXPECT_EQ(tests[i].expected_group_name, | |
| 5752 http_proxy_pool->last_group_name_received()); | |
| 5753 } | |
| 5754 | |
| 5755 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 5756 } | |
| 5757 | |
| 5758 TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) { | |
| 5759 const GroupNameTest tests[] = { | |
| 5760 { | |
| 5761 "socks4://socks_proxy:1080", | |
| 5762 "http://www.google.com/socks4_direct", | |
| 5763 "socks4/www.google.com:80", | |
| 5764 false, | |
| 5765 }, | |
| 5766 { | |
| 5767 "socks5://socks_proxy:1080", | |
| 5768 "http://www.google.com/socks5_direct", | |
| 5769 "socks5/www.google.com:80", | |
| 5770 false, | |
| 5771 }, | |
| 5772 | |
| 5773 // SSL Tests | |
| 5774 { | |
| 5775 "socks4://socks_proxy:1080", | |
| 5776 "https://www.google.com/socks4_ssl", | |
| 5777 "socks4/ssl/www.google.com:443", | |
| 5778 true, | |
| 5779 }, | |
| 5780 { | |
| 5781 "socks5://socks_proxy:1080", | |
| 5782 "https://www.google.com/socks5_ssl", | |
| 5783 "socks5/ssl/www.google.com:443", | |
| 5784 true, | |
| 5785 }, | |
| 5786 | |
| 5787 { | |
| 5788 "socks4://socks_proxy:1080", | |
| 5789 "http://host.with.alternate/direct", | |
| 5790 "socks4/ssl/host.with.alternate:443", | |
| 5791 true, | |
| 5792 }, | |
| 5793 }; | |
| 5794 | |
| 5795 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 5796 | |
| 5797 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { | |
| 5798 SessionDependencies session_deps( | |
| 5799 ProxyService::CreateFixed(tests[i].proxy_server)); | |
| 5800 scoped_refptr<HttpNetworkSession> session( | |
| 5801 SetupSessionForGroupNameTests(&session_deps)); | |
| 5802 | |
| 5803 HttpNetworkSessionPeer peer(session); | |
| 5804 | |
| 5805 HostPortPair proxy_host("socks_proxy", 1080); | |
| 5806 CaptureGroupNameSOCKSSocketPool* socks_conn_pool = | |
| 5807 new CaptureGroupNameSOCKSSocketPool(NULL, NULL); | |
| 5808 CaptureGroupNameSSLSocketPool* ssl_conn_pool = | |
| 5809 new CaptureGroupNameSSLSocketPool(NULL, NULL); | |
| 5810 | |
| 5811 MockClientSocketPoolManager* mock_pool_manager = | |
| 5812 new MockClientSocketPoolManager; | |
| 5813 mock_pool_manager->SetSocketPoolForSOCKSProxy(proxy_host, socks_conn_pool); | |
| 5814 mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); | |
| 5815 peer.SetClientSocketPoolManager(mock_pool_manager); | |
| 5816 | |
| 5817 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 5818 | |
| 5819 EXPECT_EQ(ERR_IO_PENDING, | |
| 5820 GroupNameTransactionHelper(tests[i].url, session)); | |
| 5821 if (tests[i].ssl) | |
| 5822 EXPECT_EQ(tests[i].expected_group_name, | |
| 5823 ssl_conn_pool->last_group_name_received()); | |
| 5824 else | |
| 5825 EXPECT_EQ(tests[i].expected_group_name, | |
| 5826 socks_conn_pool->last_group_name_received()); | |
| 5827 } | |
| 5828 | |
| 5829 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 5830 } | |
| 5831 | |
| 5832 TEST_F(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) { | |
| 5833 HttpRequestInfo request; | |
| 5834 request.method = "GET"; | |
| 5835 request.url = GURL("http://www.google.com/"); | |
| 5836 | |
| 5837 SessionDependencies session_deps( | |
| 5838 ProxyService::CreateFixed("myproxy:70;foobar:80")); | |
| 5839 | |
| 5840 // This simulates failure resolving all hostnames; that means we will fail | |
| 5841 // connecting to both proxies (myproxy:70 and foobar:80). | |
| 5842 session_deps.host_resolver->rules()->AddSimulatedFailure("*"); | |
| 5843 | |
| 5844 scoped_ptr<HttpTransaction> trans( | |
| 5845 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5846 | |
| 5847 TestCompletionCallback callback; | |
| 5848 | |
| 5849 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5850 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5851 | |
| 5852 rv = callback.WaitForResult(); | |
| 5853 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv); | |
| 5854 } | |
| 5855 | |
| 5856 // Base test to make sure that when the load flags for a request specify to | |
| 5857 // bypass the cache, the DNS cache is not used. | |
| 5858 void BypassHostCacheOnRefreshHelper(int load_flags) { | |
| 5859 // Issue a request, asking to bypass the cache(s). | |
| 5860 HttpRequestInfo request; | |
| 5861 request.method = "GET"; | |
| 5862 request.load_flags = load_flags; | |
| 5863 request.url = GURL("http://www.google.com/"); | |
| 5864 | |
| 5865 SessionDependencies session_deps; | |
| 5866 | |
| 5867 // Select a host resolver that does caching. | |
| 5868 session_deps.host_resolver.reset(new MockCachingHostResolver); | |
| 5869 | |
| 5870 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction( | |
| 5871 CreateSession(&session_deps))); | |
| 5872 | |
| 5873 // Warm up the host cache so it has an entry for "www.google.com". | |
| 5874 AddressList addrlist; | |
| 5875 TestCompletionCallback callback; | |
| 5876 int rv = session_deps.host_resolver->Resolve( | |
| 5877 HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist, | |
| 5878 callback.callback(), NULL, BoundNetLog()); | |
| 5879 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5880 rv = callback.WaitForResult(); | |
| 5881 EXPECT_EQ(OK, rv); | |
| 5882 | |
| 5883 // Verify that it was added to host cache, by doing a subsequent async lookup | |
| 5884 // and confirming it completes synchronously. | |
| 5885 rv = session_deps.host_resolver->Resolve( | |
| 5886 HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist, | |
| 5887 callback.callback(), NULL, BoundNetLog()); | |
| 5888 ASSERT_EQ(OK, rv); | |
| 5889 | |
| 5890 // Inject a failure the next time that "www.google.com" is resolved. This way | |
| 5891 // we can tell if the next lookup hit the cache, or the "network". | |
| 5892 // (cache --> success, "network" --> failure). | |
| 5893 session_deps.host_resolver->rules()->AddSimulatedFailure("www.google.com"); | |
| 5894 | |
| 5895 // Connect up a mock socket which will fail with ERR_UNEXPECTED during the | |
| 5896 // first read -- this won't be reached as the host resolution will fail first. | |
| 5897 MockRead data_reads[] = { MockRead(SYNCHRONOUS, ERR_UNEXPECTED) }; | |
| 5898 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 5899 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5900 | |
| 5901 // Run the request. | |
| 5902 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5903 ASSERT_EQ(ERR_IO_PENDING, rv); | |
| 5904 rv = callback.WaitForResult(); | |
| 5905 | |
| 5906 // If we bypassed the cache, we would have gotten a failure while resolving | |
| 5907 // "www.google.com". | |
| 5908 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv); | |
| 5909 } | |
| 5910 | |
| 5911 // There are multiple load flags that should trigger the host cache bypass. | |
| 5912 // Test each in isolation: | |
| 5913 TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh1) { | |
| 5914 BypassHostCacheOnRefreshHelper(LOAD_BYPASS_CACHE); | |
| 5915 } | |
| 5916 | |
| 5917 TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh2) { | |
| 5918 BypassHostCacheOnRefreshHelper(LOAD_VALIDATE_CACHE); | |
| 5919 } | |
| 5920 | |
| 5921 TEST_F(HttpNetworkTransactionTest, BypassHostCacheOnRefresh3) { | |
| 5922 BypassHostCacheOnRefreshHelper(LOAD_DISABLE_CACHE); | |
| 5923 } | |
| 5924 | |
| 5925 // Make sure we can handle an error when writing the request. | |
| 5926 TEST_F(HttpNetworkTransactionTest, RequestWriteError) { | |
| 5927 SessionDependencies session_deps; | |
| 5928 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 5929 | |
| 5930 HttpRequestInfo request; | |
| 5931 request.method = "GET"; | |
| 5932 request.url = GURL("http://www.foo.com/"); | |
| 5933 request.load_flags = 0; | |
| 5934 | |
| 5935 MockWrite write_failure[] = { | |
| 5936 MockWrite(ASYNC, ERR_CONNECTION_RESET), | |
| 5937 }; | |
| 5938 StaticSocketDataProvider data(NULL, 0, | |
| 5939 write_failure, arraysize(write_failure)); | |
| 5940 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5941 | |
| 5942 TestCompletionCallback callback; | |
| 5943 | |
| 5944 scoped_ptr<HttpTransaction> trans( | |
| 5945 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5946 | |
| 5947 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5948 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5949 | |
| 5950 rv = callback.WaitForResult(); | |
| 5951 EXPECT_EQ(ERR_CONNECTION_RESET, rv); | |
| 5952 } | |
| 5953 | |
| 5954 // Check that a connection closed after the start of the headers finishes ok. | |
| 5955 TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) { | |
| 5956 SessionDependencies session_deps; | |
| 5957 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 5958 | |
| 5959 HttpRequestInfo request; | |
| 5960 request.method = "GET"; | |
| 5961 request.url = GURL("http://www.foo.com/"); | |
| 5962 request.load_flags = 0; | |
| 5963 | |
| 5964 MockRead data_reads[] = { | |
| 5965 MockRead("HTTP/1."), | |
| 5966 MockRead(SYNCHRONOUS, OK), | |
| 5967 }; | |
| 5968 | |
| 5969 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 5970 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 5971 | |
| 5972 TestCompletionCallback callback; | |
| 5973 | |
| 5974 scoped_ptr<HttpTransaction> trans( | |
| 5975 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 5976 | |
| 5977 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 5978 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 5979 | |
| 5980 rv = callback.WaitForResult(); | |
| 5981 EXPECT_EQ(OK, rv); | |
| 5982 | |
| 5983 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 5984 ASSERT_TRUE(response != NULL); | |
| 5985 | |
| 5986 EXPECT_TRUE(response->headers != NULL); | |
| 5987 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
| 5988 | |
| 5989 std::string response_data; | |
| 5990 rv = ReadTransaction(trans.get(), &response_data); | |
| 5991 EXPECT_EQ(OK, rv); | |
| 5992 EXPECT_EQ("", response_data); | |
| 5993 } | |
| 5994 | |
| 5995 // Make sure that a dropped connection while draining the body for auth | |
| 5996 // restart does the right thing. | |
| 5997 TEST_F(HttpNetworkTransactionTest, DrainResetOK) { | |
| 5998 SessionDependencies session_deps; | |
| 5999 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 6000 | |
| 6001 HttpRequestInfo request; | |
| 6002 request.method = "GET"; | |
| 6003 request.url = GURL("http://www.google.com/"); | |
| 6004 request.load_flags = 0; | |
| 6005 | |
| 6006 MockWrite data_writes1[] = { | |
| 6007 MockWrite("GET / HTTP/1.1\r\n" | |
| 6008 "Host: www.google.com\r\n" | |
| 6009 "Connection: keep-alive\r\n\r\n"), | |
| 6010 }; | |
| 6011 | |
| 6012 MockRead data_reads1[] = { | |
| 6013 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
| 6014 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 6015 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 6016 MockRead("Content-Length: 14\r\n\r\n"), | |
| 6017 MockRead("Unauth"), | |
| 6018 MockRead(ASYNC, ERR_CONNECTION_RESET), | |
| 6019 }; | |
| 6020 | |
| 6021 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 6022 data_writes1, arraysize(data_writes1)); | |
| 6023 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 6024 | |
| 6025 // After calling trans->RestartWithAuth(), this is the request we should | |
| 6026 // be issuing -- the final header line contains the credentials. | |
| 6027 MockWrite data_writes2[] = { | |
| 6028 MockWrite("GET / HTTP/1.1\r\n" | |
| 6029 "Host: www.google.com\r\n" | |
| 6030 "Connection: keep-alive\r\n" | |
| 6031 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 6032 }; | |
| 6033 | |
| 6034 // Lastly, the server responds with the actual content. | |
| 6035 MockRead data_reads2[] = { | |
| 6036 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 6037 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 6038 MockRead("Content-Length: 100\r\n\r\n"), | |
| 6039 MockRead(SYNCHRONOUS, OK), | |
| 6040 }; | |
| 6041 | |
| 6042 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 6043 data_writes2, arraysize(data_writes2)); | |
| 6044 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 6045 | |
| 6046 TestCompletionCallback callback1; | |
| 6047 | |
| 6048 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 6049 | |
| 6050 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 6051 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6052 | |
| 6053 rv = callback1.WaitForResult(); | |
| 6054 EXPECT_EQ(OK, rv); | |
| 6055 | |
| 6056 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6057 ASSERT_TRUE(response != NULL); | |
| 6058 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 6059 | |
| 6060 TestCompletionCallback callback2; | |
| 6061 | |
| 6062 rv = trans->RestartWithAuth( | |
| 6063 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 6064 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6065 | |
| 6066 rv = callback2.WaitForResult(); | |
| 6067 EXPECT_EQ(OK, rv); | |
| 6068 | |
| 6069 response = trans->GetResponseInfo(); | |
| 6070 ASSERT_TRUE(response != NULL); | |
| 6071 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 6072 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 6073 } | |
| 6074 | |
| 6075 // Test HTTPS connections going through a proxy that sends extra data. | |
| 6076 TEST_F(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) { | |
| 6077 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 6078 | |
| 6079 HttpRequestInfo request; | |
| 6080 request.method = "GET"; | |
| 6081 request.url = GURL("https://www.google.com/"); | |
| 6082 request.load_flags = 0; | |
| 6083 | |
| 6084 MockRead proxy_reads[] = { | |
| 6085 MockRead("HTTP/1.0 200 Connected\r\n\r\nExtra data"), | |
| 6086 MockRead(SYNCHRONOUS, OK) | |
| 6087 }; | |
| 6088 | |
| 6089 StaticSocketDataProvider data(proxy_reads, arraysize(proxy_reads), NULL, 0); | |
| 6090 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 6091 | |
| 6092 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 6093 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 6094 | |
| 6095 TestCompletionCallback callback; | |
| 6096 | |
| 6097 session_deps.socket_factory.ResetNextMockIndexes(); | |
| 6098 | |
| 6099 scoped_ptr<HttpTransaction> trans( | |
| 6100 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 6101 | |
| 6102 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6103 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6104 | |
| 6105 rv = callback.WaitForResult(); | |
| 6106 EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); | |
| 6107 } | |
| 6108 | |
| 6109 TEST_F(HttpNetworkTransactionTest, LargeContentLengthThenClose) { | |
| 6110 HttpRequestInfo request; | |
| 6111 request.method = "GET"; | |
| 6112 request.url = GURL("http://www.google.com/"); | |
| 6113 request.load_flags = 0; | |
| 6114 | |
| 6115 SessionDependencies session_deps; | |
| 6116 scoped_ptr<HttpTransaction> trans( | |
| 6117 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 6118 | |
| 6119 MockRead data_reads[] = { | |
| 6120 MockRead("HTTP/1.0 200 OK\r\nContent-Length:6719476739\r\n\r\n"), | |
| 6121 MockRead(SYNCHRONOUS, OK), | |
| 6122 }; | |
| 6123 | |
| 6124 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 6125 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 6126 | |
| 6127 TestCompletionCallback callback; | |
| 6128 | |
| 6129 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6130 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6131 | |
| 6132 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 6133 | |
| 6134 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6135 ASSERT_TRUE(response != NULL); | |
| 6136 | |
| 6137 EXPECT_TRUE(response->headers != NULL); | |
| 6138 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
| 6139 | |
| 6140 std::string response_data; | |
| 6141 rv = ReadTransaction(trans.get(), &response_data); | |
| 6142 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv); | |
| 6143 } | |
| 6144 | |
| 6145 TEST_F(HttpNetworkTransactionTest, UploadFileSmallerThanLength) { | |
| 6146 HttpRequestInfo request; | |
| 6147 request.method = "POST"; | |
| 6148 request.url = GURL("http://www.google.com/upload"); | |
| 6149 request.upload_data = new UploadData; | |
| 6150 request.load_flags = 0; | |
| 6151 | |
| 6152 SessionDependencies session_deps; | |
| 6153 scoped_ptr<HttpTransaction> trans( | |
| 6154 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 6155 | |
| 6156 FilePath temp_file_path; | |
| 6157 ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file_path)); | |
| 6158 const uint64 kFakeSize = 100000; // file is actually blank | |
| 6159 | |
| 6160 std::vector<UploadData::Element> elements; | |
| 6161 UploadData::Element element; | |
| 6162 element.SetToFilePath(temp_file_path); | |
| 6163 element.SetContentLength(kFakeSize); | |
| 6164 elements.push_back(element); | |
| 6165 request.upload_data->SetElements(elements); | |
| 6166 EXPECT_EQ(kFakeSize, request.upload_data->GetContentLengthSync()); | |
| 6167 | |
| 6168 MockRead data_reads[] = { | |
| 6169 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
| 6170 MockRead("hello world"), | |
| 6171 MockRead(SYNCHRONOUS, OK), | |
| 6172 }; | |
| 6173 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 6174 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 6175 | |
| 6176 TestCompletionCallback callback; | |
| 6177 | |
| 6178 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6179 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6180 | |
| 6181 rv = callback.WaitForResult(); | |
| 6182 EXPECT_EQ(OK, rv); | |
| 6183 | |
| 6184 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6185 ASSERT_TRUE(response != NULL); | |
| 6186 | |
| 6187 EXPECT_TRUE(response->headers != NULL); | |
| 6188 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
| 6189 | |
| 6190 std::string response_data; | |
| 6191 rv = ReadTransaction(trans.get(), &response_data); | |
| 6192 EXPECT_EQ(OK, rv); | |
| 6193 EXPECT_EQ("hello world", response_data); | |
| 6194 | |
| 6195 file_util::Delete(temp_file_path, false); | |
| 6196 } | |
| 6197 | |
| 6198 TEST_F(HttpNetworkTransactionTest, UploadUnreadableFile) { | |
| 6199 HttpRequestInfo request; | |
| 6200 request.method = "POST"; | |
| 6201 request.url = GURL("http://www.google.com/upload"); | |
| 6202 request.upload_data = new UploadData; | |
| 6203 request.load_flags = 0; | |
| 6204 | |
| 6205 // If we try to upload an unreadable file, the network stack should report | |
| 6206 // the file size as zero and upload zero bytes for that file. | |
| 6207 SessionDependencies session_deps; | |
| 6208 scoped_ptr<HttpTransaction> trans( | |
| 6209 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 6210 | |
| 6211 FilePath temp_file; | |
| 6212 ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file)); | |
| 6213 std::string temp_file_content("Unreadable file."); | |
| 6214 ASSERT_TRUE(file_util::WriteFile(temp_file, temp_file_content.c_str(), | |
| 6215 temp_file_content.length())); | |
| 6216 ASSERT_TRUE(file_util::MakeFileUnreadable(temp_file)); | |
| 6217 | |
| 6218 std::vector<UploadData::Element> elements; | |
| 6219 UploadData::Element element; | |
| 6220 element.SetToFilePath(temp_file); | |
| 6221 elements.push_back(element); | |
| 6222 request.upload_data->SetElements(elements); | |
| 6223 | |
| 6224 MockRead data_reads[] = { | |
| 6225 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
| 6226 MockRead(SYNCHRONOUS, OK), | |
| 6227 }; | |
| 6228 MockWrite data_writes[] = { | |
| 6229 MockWrite("POST /upload HTTP/1.1\r\n" | |
| 6230 "Host: www.google.com\r\n" | |
| 6231 "Connection: keep-alive\r\n" | |
| 6232 "Content-Length: 0\r\n\r\n"), | |
| 6233 MockWrite(SYNCHRONOUS, OK), | |
| 6234 }; | |
| 6235 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 6236 arraysize(data_writes)); | |
| 6237 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 6238 | |
| 6239 TestCompletionCallback callback; | |
| 6240 | |
| 6241 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6242 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6243 | |
| 6244 rv = callback.WaitForResult(); | |
| 6245 EXPECT_EQ(OK, rv); | |
| 6246 | |
| 6247 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6248 ASSERT_TRUE(response != NULL); | |
| 6249 EXPECT_TRUE(response->headers != NULL); | |
| 6250 EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); | |
| 6251 | |
| 6252 file_util::Delete(temp_file, false); | |
| 6253 } | |
| 6254 | |
| 6255 TEST_F(HttpNetworkTransactionTest, UnreadableUploadFileAfterAuthRestart) { | |
| 6256 HttpRequestInfo request; | |
| 6257 request.method = "POST"; | |
| 6258 request.url = GURL("http://www.google.com/upload"); | |
| 6259 request.upload_data = new UploadData; | |
| 6260 request.load_flags = 0; | |
| 6261 | |
| 6262 SessionDependencies session_deps; | |
| 6263 scoped_ptr<HttpTransaction> trans( | |
| 6264 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 6265 | |
| 6266 FilePath temp_file; | |
| 6267 ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file)); | |
| 6268 std::string temp_file_contents("Unreadable file."); | |
| 6269 std::string unreadable_contents(temp_file_contents.length(), '\0'); | |
| 6270 ASSERT_TRUE(file_util::WriteFile(temp_file, temp_file_contents.c_str(), | |
| 6271 temp_file_contents.length())); | |
| 6272 | |
| 6273 std::vector<UploadData::Element> elements; | |
| 6274 UploadData::Element element; | |
| 6275 element.SetToFilePath(temp_file); | |
| 6276 elements.push_back(element); | |
| 6277 request.upload_data->SetElements(elements); | |
| 6278 | |
| 6279 MockRead data_reads[] = { | |
| 6280 MockRead("HTTP/1.1 401 Unauthorized\r\n"), | |
| 6281 MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), | |
| 6282 MockRead("Content-Length: 0\r\n\r\n"), // No response body. | |
| 6283 | |
| 6284 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 6285 MockRead("Content-Length: 0\r\n\r\n"), | |
| 6286 MockRead(SYNCHRONOUS, OK), | |
| 6287 }; | |
| 6288 MockWrite data_writes[] = { | |
| 6289 MockWrite("POST /upload HTTP/1.1\r\n" | |
| 6290 "Host: www.google.com\r\n" | |
| 6291 "Connection: keep-alive\r\n" | |
| 6292 "Content-Length: 16\r\n\r\n"), | |
| 6293 MockWrite(SYNCHRONOUS, temp_file_contents.c_str()), | |
| 6294 | |
| 6295 MockWrite("POST /upload HTTP/1.1\r\n" | |
| 6296 "Host: www.google.com\r\n" | |
| 6297 "Connection: keep-alive\r\n" | |
| 6298 "Content-Length: 16\r\n" | |
| 6299 "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), | |
| 6300 MockWrite(SYNCHRONOUS, unreadable_contents.c_str(), | |
| 6301 temp_file_contents.length()), | |
| 6302 MockWrite(SYNCHRONOUS, OK), | |
| 6303 }; | |
| 6304 StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, | |
| 6305 arraysize(data_writes)); | |
| 6306 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 6307 | |
| 6308 TestCompletionCallback callback1; | |
| 6309 | |
| 6310 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 6311 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6312 | |
| 6313 rv = callback1.WaitForResult(); | |
| 6314 EXPECT_EQ(OK, rv); | |
| 6315 | |
| 6316 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6317 ASSERT_TRUE(response != NULL); | |
| 6318 ASSERT_TRUE(response->headers != NULL); | |
| 6319 EXPECT_EQ("HTTP/1.1 401 Unauthorized", response->headers->GetStatusLine()); | |
| 6320 EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); | |
| 6321 | |
| 6322 // Now make the file unreadable and try again. | |
| 6323 ASSERT_TRUE(file_util::MakeFileUnreadable(temp_file)); | |
| 6324 | |
| 6325 TestCompletionCallback callback2; | |
| 6326 | |
| 6327 rv = trans->RestartWithAuth( | |
| 6328 AuthCredentials(kFoo, kBar), callback2.callback()); | |
| 6329 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6330 | |
| 6331 rv = callback2.WaitForResult(); | |
| 6332 EXPECT_EQ(OK, rv); | |
| 6333 | |
| 6334 response = trans->GetResponseInfo(); | |
| 6335 ASSERT_TRUE(response != NULL); | |
| 6336 EXPECT_TRUE(response->headers != NULL); | |
| 6337 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 6338 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 6339 | |
| 6340 file_util::Delete(temp_file, false); | |
| 6341 } | |
| 6342 | |
| 6343 // Tests that changes to Auth realms are treated like auth rejections. | |
| 6344 TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) { | |
| 6345 SessionDependencies session_deps; | |
| 6346 | |
| 6347 HttpRequestInfo request; | |
| 6348 request.method = "GET"; | |
| 6349 request.url = GURL("http://www.google.com/"); | |
| 6350 request.load_flags = 0; | |
| 6351 | |
| 6352 // First transaction will request a resource and receive a Basic challenge | |
| 6353 // with realm="first_realm". | |
| 6354 MockWrite data_writes1[] = { | |
| 6355 MockWrite("GET / HTTP/1.1\r\n" | |
| 6356 "Host: www.google.com\r\n" | |
| 6357 "Connection: keep-alive\r\n" | |
| 6358 "\r\n"), | |
| 6359 }; | |
| 6360 MockRead data_reads1[] = { | |
| 6361 MockRead("HTTP/1.1 401 Unauthorized\r\n" | |
| 6362 "WWW-Authenticate: Basic realm=\"first_realm\"\r\n" | |
| 6363 "\r\n"), | |
| 6364 }; | |
| 6365 | |
| 6366 // After calling trans->RestartWithAuth(), provide an Authentication header | |
| 6367 // for first_realm. The server will reject and provide a challenge with | |
| 6368 // second_realm. | |
| 6369 MockWrite data_writes2[] = { | |
| 6370 MockWrite("GET / HTTP/1.1\r\n" | |
| 6371 "Host: www.google.com\r\n" | |
| 6372 "Connection: keep-alive\r\n" | |
| 6373 "Authorization: Basic Zmlyc3Q6YmF6\r\n" | |
| 6374 "\r\n"), | |
| 6375 }; | |
| 6376 MockRead data_reads2[] = { | |
| 6377 MockRead("HTTP/1.1 401 Unauthorized\r\n" | |
| 6378 "WWW-Authenticate: Basic realm=\"second_realm\"\r\n" | |
| 6379 "\r\n"), | |
| 6380 }; | |
| 6381 | |
| 6382 // This again fails, and goes back to first_realm. Make sure that the | |
| 6383 // entry is removed from cache. | |
| 6384 MockWrite data_writes3[] = { | |
| 6385 MockWrite("GET / HTTP/1.1\r\n" | |
| 6386 "Host: www.google.com\r\n" | |
| 6387 "Connection: keep-alive\r\n" | |
| 6388 "Authorization: Basic c2Vjb25kOmZvdQ==\r\n" | |
| 6389 "\r\n"), | |
| 6390 }; | |
| 6391 MockRead data_reads3[] = { | |
| 6392 MockRead("HTTP/1.1 401 Unauthorized\r\n" | |
| 6393 "WWW-Authenticate: Basic realm=\"first_realm\"\r\n" | |
| 6394 "\r\n"), | |
| 6395 }; | |
| 6396 | |
| 6397 // Try one last time (with the correct password) and get the resource. | |
| 6398 MockWrite data_writes4[] = { | |
| 6399 MockWrite("GET / HTTP/1.1\r\n" | |
| 6400 "Host: www.google.com\r\n" | |
| 6401 "Connection: keep-alive\r\n" | |
| 6402 "Authorization: Basic Zmlyc3Q6YmFy\r\n" | |
| 6403 "\r\n"), | |
| 6404 }; | |
| 6405 MockRead data_reads4[] = { | |
| 6406 MockRead("HTTP/1.1 200 OK\r\n" | |
| 6407 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 6408 "Content-Length: 5\r\n" | |
| 6409 "\r\n" | |
| 6410 "hello"), | |
| 6411 }; | |
| 6412 | |
| 6413 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 6414 data_writes1, arraysize(data_writes1)); | |
| 6415 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 6416 data_writes2, arraysize(data_writes2)); | |
| 6417 StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), | |
| 6418 data_writes3, arraysize(data_writes3)); | |
| 6419 StaticSocketDataProvider data4(data_reads4, arraysize(data_reads4), | |
| 6420 data_writes4, arraysize(data_writes4)); | |
| 6421 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 6422 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 6423 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
| 6424 session_deps.socket_factory.AddSocketDataProvider(&data4); | |
| 6425 | |
| 6426 TestCompletionCallback callback1; | |
| 6427 | |
| 6428 scoped_ptr<HttpTransaction> trans( | |
| 6429 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 6430 | |
| 6431 // Issue the first request with Authorize headers. There should be a | |
| 6432 // password prompt for first_realm waiting to be filled in after the | |
| 6433 // transaction completes. | |
| 6434 int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); | |
| 6435 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6436 rv = callback1.WaitForResult(); | |
| 6437 EXPECT_EQ(OK, rv); | |
| 6438 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6439 ASSERT_TRUE(response != NULL); | |
| 6440 const AuthChallengeInfo* challenge = response->auth_challenge.get(); | |
| 6441 ASSERT_FALSE(challenge == NULL); | |
| 6442 EXPECT_FALSE(challenge->is_proxy); | |
| 6443 EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); | |
| 6444 EXPECT_EQ("first_realm", challenge->realm); | |
| 6445 EXPECT_EQ("basic", challenge->scheme); | |
| 6446 | |
| 6447 // Issue the second request with an incorrect password. There should be a | |
| 6448 // password prompt for second_realm waiting to be filled in after the | |
| 6449 // transaction completes. | |
| 6450 TestCompletionCallback callback2; | |
| 6451 rv = trans->RestartWithAuth( | |
| 6452 AuthCredentials(kFirst, kBaz), callback2.callback()); | |
| 6453 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6454 rv = callback2.WaitForResult(); | |
| 6455 EXPECT_EQ(OK, rv); | |
| 6456 response = trans->GetResponseInfo(); | |
| 6457 ASSERT_TRUE(response != NULL); | |
| 6458 challenge = response->auth_challenge.get(); | |
| 6459 ASSERT_FALSE(challenge == NULL); | |
| 6460 EXPECT_FALSE(challenge->is_proxy); | |
| 6461 EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); | |
| 6462 EXPECT_EQ("second_realm", challenge->realm); | |
| 6463 EXPECT_EQ("basic", challenge->scheme); | |
| 6464 | |
| 6465 // Issue the third request with another incorrect password. There should be | |
| 6466 // a password prompt for first_realm waiting to be filled in. If the password | |
| 6467 // prompt is not present, it indicates that the HttpAuthCacheEntry for | |
| 6468 // first_realm was not correctly removed. | |
| 6469 TestCompletionCallback callback3; | |
| 6470 rv = trans->RestartWithAuth( | |
| 6471 AuthCredentials(kSecond, kFou), callback3.callback()); | |
| 6472 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6473 rv = callback3.WaitForResult(); | |
| 6474 EXPECT_EQ(OK, rv); | |
| 6475 response = trans->GetResponseInfo(); | |
| 6476 ASSERT_TRUE(response != NULL); | |
| 6477 challenge = response->auth_challenge.get(); | |
| 6478 ASSERT_FALSE(challenge == NULL); | |
| 6479 EXPECT_FALSE(challenge->is_proxy); | |
| 6480 EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); | |
| 6481 EXPECT_EQ("first_realm", challenge->realm); | |
| 6482 EXPECT_EQ("basic", challenge->scheme); | |
| 6483 | |
| 6484 // Issue the fourth request with the correct password and username. | |
| 6485 TestCompletionCallback callback4; | |
| 6486 rv = trans->RestartWithAuth( | |
| 6487 AuthCredentials(kFirst, kBar), callback4.callback()); | |
| 6488 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6489 rv = callback4.WaitForResult(); | |
| 6490 EXPECT_EQ(OK, rv); | |
| 6491 response = trans->GetResponseInfo(); | |
| 6492 ASSERT_TRUE(response != NULL); | |
| 6493 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 6494 } | |
| 6495 | |
| 6496 TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) { | |
| 6497 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 6498 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
| 6499 | |
| 6500 SessionDependencies session_deps; | |
| 6501 | |
| 6502 MockRead data_reads[] = { | |
| 6503 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 6504 MockRead(kAlternateProtocolHttpHeader), | |
| 6505 MockRead("hello world"), | |
| 6506 MockRead(SYNCHRONOUS, OK), | |
| 6507 }; | |
| 6508 | |
| 6509 HttpRequestInfo request; | |
| 6510 request.method = "GET"; | |
| 6511 request.url = GURL("http://www.google.com/"); | |
| 6512 request.load_flags = 0; | |
| 6513 | |
| 6514 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 6515 | |
| 6516 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 6517 | |
| 6518 TestCompletionCallback callback; | |
| 6519 | |
| 6520 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 6521 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 6522 | |
| 6523 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6524 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6525 | |
| 6526 HostPortPair http_host_port_pair("www.google.com", 80); | |
| 6527 const HttpServerProperties& http_server_properties = | |
| 6528 *session->http_server_properties(); | |
| 6529 EXPECT_FALSE( | |
| 6530 http_server_properties.HasAlternateProtocol(http_host_port_pair)); | |
| 6531 | |
| 6532 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 6533 | |
| 6534 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6535 ASSERT_TRUE(response != NULL); | |
| 6536 ASSERT_TRUE(response->headers != NULL); | |
| 6537 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 6538 EXPECT_FALSE(response->was_fetched_via_spdy); | |
| 6539 EXPECT_FALSE(response->was_npn_negotiated); | |
| 6540 | |
| 6541 std::string response_data; | |
| 6542 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 6543 EXPECT_EQ("hello world", response_data); | |
| 6544 | |
| 6545 ASSERT_TRUE(http_server_properties.HasAlternateProtocol(http_host_port_pair)); | |
| 6546 const PortAlternateProtocolPair alternate = | |
| 6547 http_server_properties.GetAlternateProtocol(http_host_port_pair); | |
| 6548 PortAlternateProtocolPair expected_alternate; | |
| 6549 expected_alternate.port = 443; | |
| 6550 expected_alternate.protocol = NPN_SPDY_21; | |
| 6551 EXPECT_TRUE(expected_alternate.Equals(alternate)); | |
| 6552 | |
| 6553 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 6554 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
| 6555 } | |
| 6556 | |
| 6557 TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocolAndFallback) { | |
| 6558 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 6559 SessionDependencies session_deps; | |
| 6560 | |
| 6561 HttpRequestInfo request; | |
| 6562 request.method = "GET"; | |
| 6563 request.url = GURL("http://www.google.com/"); | |
| 6564 request.load_flags = 0; | |
| 6565 | |
| 6566 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 6567 StaticSocketDataProvider first_data; | |
| 6568 first_data.set_connect_data(mock_connect); | |
| 6569 session_deps.socket_factory.AddSocketDataProvider(&first_data); | |
| 6570 | |
| 6571 MockRead data_reads[] = { | |
| 6572 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 6573 MockRead("hello world"), | |
| 6574 MockRead(ASYNC, OK), | |
| 6575 }; | |
| 6576 StaticSocketDataProvider second_data( | |
| 6577 data_reads, arraysize(data_reads), NULL, 0); | |
| 6578 session_deps.socket_factory.AddSocketDataProvider(&second_data); | |
| 6579 | |
| 6580 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 6581 | |
| 6582 HttpServerProperties* http_server_properties = | |
| 6583 session->http_server_properties(); | |
| 6584 // Port must be < 1024, or the header will be ignored (since initial port was | |
| 6585 // port 80 (another restricted port). | |
| 6586 http_server_properties->SetAlternateProtocol( | |
| 6587 HostPortPair::FromURL(request.url), | |
| 6588 666 /* port is ignored by MockConnect anyway */, | |
| 6589 NPN_SPDY_21); | |
| 6590 | |
| 6591 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 6592 TestCompletionCallback callback; | |
| 6593 | |
| 6594 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6595 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6596 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 6597 | |
| 6598 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6599 ASSERT_TRUE(response != NULL); | |
| 6600 ASSERT_TRUE(response->headers != NULL); | |
| 6601 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 6602 | |
| 6603 std::string response_data; | |
| 6604 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 6605 EXPECT_EQ("hello world", response_data); | |
| 6606 | |
| 6607 ASSERT_TRUE(http_server_properties->HasAlternateProtocol( | |
| 6608 HostPortPair::FromURL(request.url))); | |
| 6609 const PortAlternateProtocolPair alternate = | |
| 6610 http_server_properties->GetAlternateProtocol( | |
| 6611 HostPortPair::FromURL(request.url)); | |
| 6612 EXPECT_EQ(ALTERNATE_PROTOCOL_BROKEN, alternate.protocol); | |
| 6613 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 6614 } | |
| 6615 | |
| 6616 TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortRestrictedBlocked) { | |
| 6617 // Ensure that we're not allowed to redirect traffic via an alternate | |
| 6618 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
| 6619 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
| 6620 // other cases. | |
| 6621 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 6622 SessionDependencies session_deps; | |
| 6623 | |
| 6624 HttpRequestInfo restricted_port_request; | |
| 6625 restricted_port_request.method = "GET"; | |
| 6626 restricted_port_request.url = GURL("http://www.google.com:1023/"); | |
| 6627 restricted_port_request.load_flags = 0; | |
| 6628 | |
| 6629 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 6630 StaticSocketDataProvider first_data; | |
| 6631 first_data.set_connect_data(mock_connect); | |
| 6632 session_deps.socket_factory.AddSocketDataProvider(&first_data); | |
| 6633 | |
| 6634 MockRead data_reads[] = { | |
| 6635 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 6636 MockRead("hello world"), | |
| 6637 MockRead(ASYNC, OK), | |
| 6638 }; | |
| 6639 StaticSocketDataProvider second_data( | |
| 6640 data_reads, arraysize(data_reads), NULL, 0); | |
| 6641 session_deps.socket_factory.AddSocketDataProvider(&second_data); | |
| 6642 | |
| 6643 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 6644 | |
| 6645 HttpServerProperties* http_server_properties = | |
| 6646 session->http_server_properties(); | |
| 6647 const int kUnrestrictedAlternatePort = 1024; | |
| 6648 http_server_properties->SetAlternateProtocol( | |
| 6649 HostPortPair::FromURL(restricted_port_request.url), | |
| 6650 kUnrestrictedAlternatePort, | |
| 6651 NPN_SPDY_21); | |
| 6652 | |
| 6653 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 6654 TestCompletionCallback callback; | |
| 6655 | |
| 6656 int rv = trans->Start( | |
| 6657 &restricted_port_request, callback.callback(), BoundNetLog()); | |
| 6658 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6659 // Invalid change to unrestricted port should fail. | |
| 6660 EXPECT_EQ(ERR_CONNECTION_REFUSED, callback.WaitForResult()); | |
| 6661 | |
| 6662 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 6663 } | |
| 6664 | |
| 6665 TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortRestrictedAllowed) { | |
| 6666 // Ensure that we're not allowed to redirect traffic via an alternate | |
| 6667 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
| 6668 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
| 6669 // other cases. | |
| 6670 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 6671 SessionDependencies session_deps; | |
| 6672 | |
| 6673 HttpRequestInfo restricted_port_request; | |
| 6674 restricted_port_request.method = "GET"; | |
| 6675 restricted_port_request.url = GURL("http://www.google.com:1023/"); | |
| 6676 restricted_port_request.load_flags = 0; | |
| 6677 | |
| 6678 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 6679 StaticSocketDataProvider first_data; | |
| 6680 first_data.set_connect_data(mock_connect); | |
| 6681 session_deps.socket_factory.AddSocketDataProvider(&first_data); | |
| 6682 | |
| 6683 MockRead data_reads[] = { | |
| 6684 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 6685 MockRead("hello world"), | |
| 6686 MockRead(ASYNC, OK), | |
| 6687 }; | |
| 6688 StaticSocketDataProvider second_data( | |
| 6689 data_reads, arraysize(data_reads), NULL, 0); | |
| 6690 session_deps.socket_factory.AddSocketDataProvider(&second_data); | |
| 6691 | |
| 6692 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 6693 | |
| 6694 HttpServerProperties* http_server_properties = | |
| 6695 session->http_server_properties(); | |
| 6696 const int kRestrictedAlternatePort = 80; | |
| 6697 http_server_properties->SetAlternateProtocol( | |
| 6698 HostPortPair::FromURL(restricted_port_request.url), | |
| 6699 kRestrictedAlternatePort, | |
| 6700 NPN_SPDY_21); | |
| 6701 | |
| 6702 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 6703 TestCompletionCallback callback; | |
| 6704 | |
| 6705 int rv = trans->Start( | |
| 6706 &restricted_port_request, callback.callback(), BoundNetLog()); | |
| 6707 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6708 // Valid change to restricted port should pass. | |
| 6709 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 6710 | |
| 6711 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 6712 } | |
| 6713 | |
| 6714 TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortUnrestrictedAllowed1) { | |
| 6715 // Ensure that we're not allowed to redirect traffic via an alternate | |
| 6716 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
| 6717 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
| 6718 // other cases. | |
| 6719 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 6720 SessionDependencies session_deps; | |
| 6721 | |
| 6722 HttpRequestInfo unrestricted_port_request; | |
| 6723 unrestricted_port_request.method = "GET"; | |
| 6724 unrestricted_port_request.url = GURL("http://www.google.com:1024/"); | |
| 6725 unrestricted_port_request.load_flags = 0; | |
| 6726 | |
| 6727 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 6728 StaticSocketDataProvider first_data; | |
| 6729 first_data.set_connect_data(mock_connect); | |
| 6730 session_deps.socket_factory.AddSocketDataProvider(&first_data); | |
| 6731 | |
| 6732 MockRead data_reads[] = { | |
| 6733 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 6734 MockRead("hello world"), | |
| 6735 MockRead(ASYNC, OK), | |
| 6736 }; | |
| 6737 StaticSocketDataProvider second_data( | |
| 6738 data_reads, arraysize(data_reads), NULL, 0); | |
| 6739 session_deps.socket_factory.AddSocketDataProvider(&second_data); | |
| 6740 | |
| 6741 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 6742 | |
| 6743 HttpServerProperties* http_server_properties = | |
| 6744 session->http_server_properties(); | |
| 6745 const int kRestrictedAlternatePort = 80; | |
| 6746 http_server_properties->SetAlternateProtocol( | |
| 6747 HostPortPair::FromURL(unrestricted_port_request.url), | |
| 6748 kRestrictedAlternatePort, | |
| 6749 NPN_SPDY_21); | |
| 6750 | |
| 6751 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 6752 TestCompletionCallback callback; | |
| 6753 | |
| 6754 int rv = trans->Start( | |
| 6755 &unrestricted_port_request, callback.callback(), BoundNetLog()); | |
| 6756 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6757 // Valid change to restricted port should pass. | |
| 6758 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 6759 | |
| 6760 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 6761 } | |
| 6762 | |
| 6763 TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortUnrestrictedAllowed2) { | |
| 6764 // Ensure that we're not allowed to redirect traffic via an alternate | |
| 6765 // protocol to an unrestricted (port >= 1024) when the original traffic was | |
| 6766 // on a restricted port (port < 1024). Ensure that we can redirect in all | |
| 6767 // other cases. | |
| 6768 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 6769 SessionDependencies session_deps; | |
| 6770 | |
| 6771 HttpRequestInfo unrestricted_port_request; | |
| 6772 unrestricted_port_request.method = "GET"; | |
| 6773 unrestricted_port_request.url = GURL("http://www.google.com:1024/"); | |
| 6774 unrestricted_port_request.load_flags = 0; | |
| 6775 | |
| 6776 MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); | |
| 6777 StaticSocketDataProvider first_data; | |
| 6778 first_data.set_connect_data(mock_connect); | |
| 6779 session_deps.socket_factory.AddSocketDataProvider(&first_data); | |
| 6780 | |
| 6781 MockRead data_reads[] = { | |
| 6782 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 6783 MockRead("hello world"), | |
| 6784 MockRead(ASYNC, OK), | |
| 6785 }; | |
| 6786 StaticSocketDataProvider second_data( | |
| 6787 data_reads, arraysize(data_reads), NULL, 0); | |
| 6788 session_deps.socket_factory.AddSocketDataProvider(&second_data); | |
| 6789 | |
| 6790 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 6791 | |
| 6792 HttpServerProperties* http_server_properties = | |
| 6793 session->http_server_properties(); | |
| 6794 const int kUnrestrictedAlternatePort = 1024; | |
| 6795 http_server_properties->SetAlternateProtocol( | |
| 6796 HostPortPair::FromURL(unrestricted_port_request.url), | |
| 6797 kUnrestrictedAlternatePort, | |
| 6798 NPN_SPDY_21); | |
| 6799 | |
| 6800 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 6801 TestCompletionCallback callback; | |
| 6802 | |
| 6803 int rv = trans->Start( | |
| 6804 &unrestricted_port_request, callback.callback(), BoundNetLog()); | |
| 6805 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6806 // Valid change to an unrestricted port should pass. | |
| 6807 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 6808 | |
| 6809 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 6810 } | |
| 6811 | |
| 6812 TEST_F(HttpNetworkTransactionTest, AlternateProtocolUnsafeBlocked) { | |
| 6813 // Ensure that we're not allowed to redirect traffic via an alternate | |
| 6814 // protocol to an unsafe port, and that we resume the second | |
| 6815 // HttpStreamFactoryImpl::Job once the alternate protocol request fails. | |
| 6816 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 6817 SessionDependencies session_deps; | |
| 6818 | |
| 6819 HttpRequestInfo request; | |
| 6820 request.method = "GET"; | |
| 6821 request.url = GURL("http://www.google.com/"); | |
| 6822 request.load_flags = 0; | |
| 6823 | |
| 6824 // The alternate protocol request will error out before we attempt to connect, | |
| 6825 // so only the standard HTTP request will try to connect. | |
| 6826 MockRead data_reads[] = { | |
| 6827 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
| 6828 MockRead("hello world"), | |
| 6829 MockRead(ASYNC, OK), | |
| 6830 }; | |
| 6831 StaticSocketDataProvider data( | |
| 6832 data_reads, arraysize(data_reads), NULL, 0); | |
| 6833 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 6834 | |
| 6835 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 6836 | |
| 6837 HttpServerProperties* http_server_properties = | |
| 6838 session->http_server_properties(); | |
| 6839 const int kUnsafePort = 7; | |
| 6840 http_server_properties->SetAlternateProtocol( | |
| 6841 HostPortPair::FromURL(request.url), | |
| 6842 kUnsafePort, | |
| 6843 NPN_SPDY_2); | |
| 6844 | |
| 6845 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 6846 TestCompletionCallback callback; | |
| 6847 | |
| 6848 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6849 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6850 // The HTTP request should succeed. | |
| 6851 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 6852 | |
| 6853 // Disable alternate protocol before the asserts. | |
| 6854 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 6855 | |
| 6856 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6857 ASSERT_TRUE(response != NULL); | |
| 6858 ASSERT_TRUE(response->headers != NULL); | |
| 6859 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 6860 | |
| 6861 std::string response_data; | |
| 6862 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 6863 EXPECT_EQ("hello world", response_data); | |
| 6864 } | |
| 6865 | |
| 6866 TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) { | |
| 6867 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 6868 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
| 6869 SessionDependencies session_deps; | |
| 6870 | |
| 6871 HttpRequestInfo request; | |
| 6872 request.method = "GET"; | |
| 6873 request.url = GURL("http://www.google.com/"); | |
| 6874 request.load_flags = 0; | |
| 6875 | |
| 6876 MockRead data_reads[] = { | |
| 6877 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 6878 MockRead(kAlternateProtocolHttpHeader), | |
| 6879 MockRead("hello world"), | |
| 6880 MockRead(ASYNC, OK), | |
| 6881 }; | |
| 6882 | |
| 6883 StaticSocketDataProvider first_transaction( | |
| 6884 data_reads, arraysize(data_reads), NULL, 0); | |
| 6885 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
| 6886 | |
| 6887 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 6888 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 6889 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 6890 | |
| 6891 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
| 6892 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
| 6893 | |
| 6894 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 6895 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
| 6896 MockRead spdy_reads[] = { | |
| 6897 CreateMockRead(*resp), | |
| 6898 CreateMockRead(*data), | |
| 6899 MockRead(ASYNC, 0, 0), | |
| 6900 }; | |
| 6901 | |
| 6902 scoped_ptr<DelayedSocketData> spdy_data( | |
| 6903 new DelayedSocketData( | |
| 6904 1, // wait for one write to finish before reading. | |
| 6905 spdy_reads, arraysize(spdy_reads), | |
| 6906 spdy_writes, arraysize(spdy_writes))); | |
| 6907 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 6908 | |
| 6909 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
| 6910 StaticSocketDataProvider hanging_non_alternate_protocol_socket( | |
| 6911 NULL, 0, NULL, 0); | |
| 6912 hanging_non_alternate_protocol_socket.set_connect_data( | |
| 6913 never_finishing_connect); | |
| 6914 session_deps.socket_factory.AddSocketDataProvider( | |
| 6915 &hanging_non_alternate_protocol_socket); | |
| 6916 | |
| 6917 TestCompletionCallback callback; | |
| 6918 | |
| 6919 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 6920 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
| 6921 | |
| 6922 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6923 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6924 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 6925 | |
| 6926 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 6927 ASSERT_TRUE(response != NULL); | |
| 6928 ASSERT_TRUE(response->headers != NULL); | |
| 6929 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 6930 | |
| 6931 std::string response_data; | |
| 6932 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 6933 EXPECT_EQ("hello world", response_data); | |
| 6934 | |
| 6935 trans.reset(new HttpNetworkTransaction(session)); | |
| 6936 | |
| 6937 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 6938 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 6939 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 6940 | |
| 6941 response = trans->GetResponseInfo(); | |
| 6942 ASSERT_TRUE(response != NULL); | |
| 6943 ASSERT_TRUE(response->headers != NULL); | |
| 6944 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 6945 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 6946 EXPECT_TRUE(response->was_npn_negotiated); | |
| 6947 | |
| 6948 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 6949 EXPECT_EQ("hello!", response_data); | |
| 6950 | |
| 6951 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
| 6952 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 6953 } | |
| 6954 | |
| 6955 TEST_F(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) { | |
| 6956 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 6957 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
| 6958 SessionDependencies session_deps; | |
| 6959 | |
| 6960 HttpRequestInfo request; | |
| 6961 request.method = "GET"; | |
| 6962 request.url = GURL("http://www.google.com/"); | |
| 6963 request.load_flags = 0; | |
| 6964 | |
| 6965 MockRead data_reads[] = { | |
| 6966 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 6967 MockRead(kAlternateProtocolHttpHeader), | |
| 6968 MockRead("hello world"), | |
| 6969 MockRead(ASYNC, OK), | |
| 6970 }; | |
| 6971 | |
| 6972 StaticSocketDataProvider first_transaction( | |
| 6973 data_reads, arraysize(data_reads), NULL, 0); | |
| 6974 // Socket 1 is the HTTP transaction with the Alternate-Protocol header. | |
| 6975 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
| 6976 | |
| 6977 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
| 6978 StaticSocketDataProvider hanging_socket( | |
| 6979 NULL, 0, NULL, 0); | |
| 6980 hanging_socket.set_connect_data(never_finishing_connect); | |
| 6981 // Socket 2 and 3 are the hanging Alternate-Protocol and | |
| 6982 // non-Alternate-Protocol jobs from the 2nd transaction. | |
| 6983 session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); | |
| 6984 session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); | |
| 6985 | |
| 6986 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 6987 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 6988 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 6989 | |
| 6990 scoped_ptr<spdy::SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
| 6991 scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); | |
| 6992 MockWrite spdy_writes[] = { | |
| 6993 CreateMockWrite(*req1), | |
| 6994 CreateMockWrite(*req2), | |
| 6995 }; | |
| 6996 scoped_ptr<spdy::SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 6997 scoped_ptr<spdy::SpdyFrame> data1(ConstructSpdyBodyFrame(1, true)); | |
| 6998 scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 6999 scoped_ptr<spdy::SpdyFrame> data2(ConstructSpdyBodyFrame(3, true)); | |
| 7000 MockRead spdy_reads[] = { | |
| 7001 CreateMockRead(*resp1), | |
| 7002 CreateMockRead(*data1), | |
| 7003 CreateMockRead(*resp2), | |
| 7004 CreateMockRead(*data2), | |
| 7005 MockRead(ASYNC, 0, 0), | |
| 7006 }; | |
| 7007 | |
| 7008 scoped_ptr<DelayedSocketData> spdy_data( | |
| 7009 new DelayedSocketData( | |
| 7010 2, // wait for writes to finish before reading. | |
| 7011 spdy_reads, arraysize(spdy_reads), | |
| 7012 spdy_writes, arraysize(spdy_writes))); | |
| 7013 // Socket 4 is the successful Alternate-Protocol for transaction 3. | |
| 7014 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 7015 | |
| 7016 // Socket 5 is the unsuccessful non-Alternate-Protocol for transaction 3. | |
| 7017 session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); | |
| 7018 | |
| 7019 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 7020 TestCompletionCallback callback1; | |
| 7021 HttpNetworkTransaction trans1(session); | |
| 7022 | |
| 7023 int rv = trans1.Start(&request, callback1.callback(), BoundNetLog()); | |
| 7024 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7025 EXPECT_EQ(OK, callback1.WaitForResult()); | |
| 7026 | |
| 7027 const HttpResponseInfo* response = trans1.GetResponseInfo(); | |
| 7028 ASSERT_TRUE(response != NULL); | |
| 7029 ASSERT_TRUE(response->headers != NULL); | |
| 7030 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 7031 | |
| 7032 std::string response_data; | |
| 7033 ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); | |
| 7034 EXPECT_EQ("hello world", response_data); | |
| 7035 | |
| 7036 TestCompletionCallback callback2; | |
| 7037 HttpNetworkTransaction trans2(session); | |
| 7038 rv = trans2.Start(&request, callback2.callback(), BoundNetLog()); | |
| 7039 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7040 | |
| 7041 TestCompletionCallback callback3; | |
| 7042 HttpNetworkTransaction trans3(session); | |
| 7043 rv = trans3.Start(&request, callback3.callback(), BoundNetLog()); | |
| 7044 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7045 | |
| 7046 EXPECT_EQ(OK, callback2.WaitForResult()); | |
| 7047 EXPECT_EQ(OK, callback3.WaitForResult()); | |
| 7048 | |
| 7049 response = trans2.GetResponseInfo(); | |
| 7050 ASSERT_TRUE(response != NULL); | |
| 7051 ASSERT_TRUE(response->headers != NULL); | |
| 7052 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 7053 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 7054 EXPECT_TRUE(response->was_npn_negotiated); | |
| 7055 ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); | |
| 7056 EXPECT_EQ("hello!", response_data); | |
| 7057 | |
| 7058 response = trans3.GetResponseInfo(); | |
| 7059 ASSERT_TRUE(response != NULL); | |
| 7060 ASSERT_TRUE(response->headers != NULL); | |
| 7061 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 7062 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 7063 EXPECT_TRUE(response->was_npn_negotiated); | |
| 7064 ASSERT_EQ(OK, ReadTransaction(&trans3, &response_data)); | |
| 7065 EXPECT_EQ("hello!", response_data); | |
| 7066 | |
| 7067 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
| 7068 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 7069 } | |
| 7070 | |
| 7071 TEST_F(HttpNetworkTransactionTest, StallAlternateProtocolForNpnSpdy) { | |
| 7072 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 7073 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
| 7074 SessionDependencies session_deps; | |
| 7075 | |
| 7076 HttpRequestInfo request; | |
| 7077 request.method = "GET"; | |
| 7078 request.url = GURL("http://www.google.com/"); | |
| 7079 request.load_flags = 0; | |
| 7080 | |
| 7081 MockRead data_reads[] = { | |
| 7082 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 7083 MockRead(kAlternateProtocolHttpHeader), | |
| 7084 MockRead("hello world"), | |
| 7085 MockRead(ASYNC, OK), | |
| 7086 }; | |
| 7087 | |
| 7088 StaticSocketDataProvider first_transaction( | |
| 7089 data_reads, arraysize(data_reads), NULL, 0); | |
| 7090 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
| 7091 | |
| 7092 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 7093 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 7094 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 7095 | |
| 7096 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
| 7097 StaticSocketDataProvider hanging_alternate_protocol_socket( | |
| 7098 NULL, 0, NULL, 0); | |
| 7099 hanging_alternate_protocol_socket.set_connect_data( | |
| 7100 never_finishing_connect); | |
| 7101 session_deps.socket_factory.AddSocketDataProvider( | |
| 7102 &hanging_alternate_protocol_socket); | |
| 7103 | |
| 7104 // 2nd request is just a copy of the first one, over HTTP again. | |
| 7105 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
| 7106 | |
| 7107 TestCompletionCallback callback; | |
| 7108 | |
| 7109 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 7110 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
| 7111 | |
| 7112 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7113 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7114 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 7115 | |
| 7116 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 7117 ASSERT_TRUE(response != NULL); | |
| 7118 ASSERT_TRUE(response->headers != NULL); | |
| 7119 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 7120 | |
| 7121 std::string response_data; | |
| 7122 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 7123 EXPECT_EQ("hello world", response_data); | |
| 7124 | |
| 7125 trans.reset(new HttpNetworkTransaction(session)); | |
| 7126 | |
| 7127 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7128 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7129 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 7130 | |
| 7131 response = trans->GetResponseInfo(); | |
| 7132 ASSERT_TRUE(response != NULL); | |
| 7133 ASSERT_TRUE(response->headers != NULL); | |
| 7134 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 7135 EXPECT_FALSE(response->was_fetched_via_spdy); | |
| 7136 EXPECT_FALSE(response->was_npn_negotiated); | |
| 7137 | |
| 7138 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 7139 EXPECT_EQ("hello world", response_data); | |
| 7140 | |
| 7141 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
| 7142 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 7143 } | |
| 7144 | |
| 7145 class CapturingProxyResolver : public ProxyResolver { | |
| 7146 public: | |
| 7147 CapturingProxyResolver() : ProxyResolver(false /* expects_pac_bytes */) {} | |
| 7148 virtual ~CapturingProxyResolver() {} | |
| 7149 | |
| 7150 virtual int GetProxyForURL(const GURL& url, | |
| 7151 ProxyInfo* results, | |
| 7152 const CompletionCallback& callback, | |
| 7153 RequestHandle* request, | |
| 7154 const BoundNetLog& net_log) { | |
| 7155 ProxyServer proxy_server(ProxyServer::SCHEME_HTTP, | |
| 7156 HostPortPair("myproxy", 80)); | |
| 7157 results->UseProxyServer(proxy_server); | |
| 7158 resolved_.push_back(url); | |
| 7159 return OK; | |
| 7160 } | |
| 7161 | |
| 7162 virtual void CancelRequest(RequestHandle request) { | |
| 7163 NOTREACHED(); | |
| 7164 } | |
| 7165 | |
| 7166 virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE { | |
| 7167 NOTREACHED(); | |
| 7168 return LOAD_STATE_IDLE; | |
| 7169 } | |
| 7170 | |
| 7171 virtual LoadState GetLoadStateThreadSafe( | |
| 7172 RequestHandle request) const OVERRIDE { | |
| 7173 NOTREACHED(); | |
| 7174 return LOAD_STATE_IDLE; | |
| 7175 } | |
| 7176 | |
| 7177 virtual void CancelSetPacScript() { | |
| 7178 NOTREACHED(); | |
| 7179 } | |
| 7180 | |
| 7181 virtual int SetPacScript(const scoped_refptr<ProxyResolverScriptData>&, | |
| 7182 const CompletionCallback& /*callback*/) { | |
| 7183 return OK; | |
| 7184 } | |
| 7185 | |
| 7186 const std::vector<GURL>& resolved() const { return resolved_; } | |
| 7187 | |
| 7188 private: | |
| 7189 std::vector<GURL> resolved_; | |
| 7190 | |
| 7191 DISALLOW_COPY_AND_ASSIGN(CapturingProxyResolver); | |
| 7192 }; | |
| 7193 | |
| 7194 TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForTunneledNpnSpdy) { | |
| 7195 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 7196 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
| 7197 | |
| 7198 ProxyConfig proxy_config; | |
| 7199 proxy_config.set_auto_detect(true); | |
| 7200 proxy_config.set_pac_url(GURL("http://fooproxyurl")); | |
| 7201 | |
| 7202 CapturingProxyResolver* capturing_proxy_resolver = | |
| 7203 new CapturingProxyResolver(); | |
| 7204 SessionDependencies session_deps(new ProxyService( | |
| 7205 new ProxyConfigServiceFixed(proxy_config), capturing_proxy_resolver, | |
| 7206 NULL)); | |
| 7207 | |
| 7208 HttpRequestInfo request; | |
| 7209 request.method = "GET"; | |
| 7210 request.url = GURL("http://www.google.com/"); | |
| 7211 request.load_flags = 0; | |
| 7212 | |
| 7213 MockRead data_reads[] = { | |
| 7214 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 7215 MockRead(kAlternateProtocolHttpHeader), | |
| 7216 MockRead("hello world"), | |
| 7217 MockRead(ASYNC, OK), | |
| 7218 }; | |
| 7219 | |
| 7220 StaticSocketDataProvider first_transaction( | |
| 7221 data_reads, arraysize(data_reads), NULL, 0); | |
| 7222 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
| 7223 | |
| 7224 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 7225 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 7226 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 7227 | |
| 7228 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
| 7229 MockWrite spdy_writes[] = { | |
| 7230 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 7231 "Host: www.google.com\r\n" | |
| 7232 "Proxy-Connection: keep-alive\r\n\r\n"), // 0 | |
| 7233 CreateMockWrite(*req) // 3 | |
| 7234 }; | |
| 7235 | |
| 7236 const char kCONNECTResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; | |
| 7237 | |
| 7238 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 7239 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
| 7240 MockRead spdy_reads[] = { | |
| 7241 MockRead(ASYNC, kCONNECTResponse, arraysize(kCONNECTResponse) - 1, 1), // 1 | |
| 7242 CreateMockRead(*resp.get(), 4), // 2, 4 | |
| 7243 CreateMockRead(*data.get(), 4), // 5 | |
| 7244 MockRead(ASYNC, 0, 0, 4), // 6 | |
| 7245 }; | |
| 7246 | |
| 7247 scoped_ptr<OrderedSocketData> spdy_data( | |
| 7248 new OrderedSocketData( | |
| 7249 spdy_reads, arraysize(spdy_reads), | |
| 7250 spdy_writes, arraysize(spdy_writes))); | |
| 7251 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 7252 | |
| 7253 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
| 7254 StaticSocketDataProvider hanging_non_alternate_protocol_socket( | |
| 7255 NULL, 0, NULL, 0); | |
| 7256 hanging_non_alternate_protocol_socket.set_connect_data( | |
| 7257 never_finishing_connect); | |
| 7258 session_deps.socket_factory.AddSocketDataProvider( | |
| 7259 &hanging_non_alternate_protocol_socket); | |
| 7260 | |
| 7261 TestCompletionCallback callback; | |
| 7262 | |
| 7263 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 7264 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
| 7265 | |
| 7266 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7267 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7268 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 7269 | |
| 7270 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 7271 ASSERT_TRUE(response != NULL); | |
| 7272 ASSERT_TRUE(response->headers != NULL); | |
| 7273 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 7274 EXPECT_FALSE(response->was_fetched_via_spdy); | |
| 7275 EXPECT_FALSE(response->was_npn_negotiated); | |
| 7276 | |
| 7277 std::string response_data; | |
| 7278 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 7279 EXPECT_EQ("hello world", response_data); | |
| 7280 | |
| 7281 trans.reset(new HttpNetworkTransaction(session)); | |
| 7282 | |
| 7283 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7284 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7285 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 7286 | |
| 7287 response = trans->GetResponseInfo(); | |
| 7288 ASSERT_TRUE(response != NULL); | |
| 7289 ASSERT_TRUE(response->headers != NULL); | |
| 7290 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 7291 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 7292 EXPECT_TRUE(response->was_npn_negotiated); | |
| 7293 | |
| 7294 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 7295 EXPECT_EQ("hello!", response_data); | |
| 7296 ASSERT_EQ(3u, capturing_proxy_resolver->resolved().size()); | |
| 7297 EXPECT_EQ("http://www.google.com/", | |
| 7298 capturing_proxy_resolver->resolved()[0].spec()); | |
| 7299 EXPECT_EQ("https://www.google.com/", | |
| 7300 capturing_proxy_resolver->resolved()[1].spec()); | |
| 7301 | |
| 7302 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
| 7303 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 7304 } | |
| 7305 | |
| 7306 TEST_F(HttpNetworkTransactionTest, | |
| 7307 UseAlternateProtocolForNpnSpdyWithExistingSpdySession) { | |
| 7308 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 7309 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
| 7310 SessionDependencies session_deps; | |
| 7311 | |
| 7312 HttpRequestInfo request; | |
| 7313 request.method = "GET"; | |
| 7314 request.url = GURL("http://www.google.com/"); | |
| 7315 request.load_flags = 0; | |
| 7316 | |
| 7317 MockRead data_reads[] = { | |
| 7318 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 7319 MockRead(kAlternateProtocolHttpHeader), | |
| 7320 MockRead("hello world"), | |
| 7321 MockRead(ASYNC, OK), | |
| 7322 }; | |
| 7323 | |
| 7324 StaticSocketDataProvider first_transaction( | |
| 7325 data_reads, arraysize(data_reads), NULL, 0); | |
| 7326 session_deps.socket_factory.AddSocketDataProvider(&first_transaction); | |
| 7327 | |
| 7328 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 7329 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 7330 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 7331 // Make sure we use ssl for spdy here. | |
| 7332 SpdySession::SetSSLMode(true); | |
| 7333 | |
| 7334 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
| 7335 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
| 7336 | |
| 7337 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 7338 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
| 7339 MockRead spdy_reads[] = { | |
| 7340 CreateMockRead(*resp), | |
| 7341 CreateMockRead(*data), | |
| 7342 MockRead(ASYNC, 0, 0), | |
| 7343 }; | |
| 7344 | |
| 7345 scoped_ptr<DelayedSocketData> spdy_data( | |
| 7346 new DelayedSocketData( | |
| 7347 1, // wait for one write to finish before reading. | |
| 7348 spdy_reads, arraysize(spdy_reads), | |
| 7349 spdy_writes, arraysize(spdy_writes))); | |
| 7350 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 7351 | |
| 7352 TestCompletionCallback callback; | |
| 7353 | |
| 7354 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 7355 | |
| 7356 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
| 7357 | |
| 7358 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7359 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7360 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 7361 | |
| 7362 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 7363 ASSERT_TRUE(response != NULL); | |
| 7364 ASSERT_TRUE(response->headers != NULL); | |
| 7365 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 7366 | |
| 7367 std::string response_data; | |
| 7368 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 7369 EXPECT_EQ("hello world", response_data); | |
| 7370 | |
| 7371 // Set up an initial SpdySession in the pool to reuse. | |
| 7372 HostPortPair host_port_pair("www.google.com", 443); | |
| 7373 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); | |
| 7374 scoped_refptr<SpdySession> spdy_session = | |
| 7375 session->spdy_session_pool()->Get(pair, BoundNetLog()); | |
| 7376 scoped_refptr<TransportSocketParams> transport_params( | |
| 7377 new TransportSocketParams(host_port_pair, MEDIUM, false, false)); | |
| 7378 | |
| 7379 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 7380 EXPECT_EQ(ERR_IO_PENDING, | |
| 7381 connection->Init(host_port_pair.ToString(), | |
| 7382 transport_params, | |
| 7383 LOWEST, | |
| 7384 callback.callback(), | |
| 7385 session->GetTransportSocketPool(), | |
| 7386 BoundNetLog())); | |
| 7387 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 7388 | |
| 7389 SSLConfig ssl_config; | |
| 7390 session->ssl_config_service()->GetSSLConfig(&ssl_config); | |
| 7391 scoped_ptr<ClientSocketHandle> ssl_connection(new ClientSocketHandle); | |
| 7392 SSLClientSocketContext context; | |
| 7393 context.cert_verifier = session_deps.cert_verifier.get(); | |
| 7394 ssl_connection->set_socket(session_deps.socket_factory.CreateSSLClientSocket( | |
| 7395 connection.release(), HostPortPair("" , 443), ssl_config, | |
| 7396 NULL /* ssl_host_info */, context)); | |
| 7397 EXPECT_EQ(ERR_IO_PENDING, | |
| 7398 ssl_connection->socket()->Connect(callback.callback())); | |
| 7399 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 7400 | |
| 7401 EXPECT_EQ(OK, spdy_session->InitializeWithSocket(ssl_connection.release(), | |
| 7402 true, OK)); | |
| 7403 | |
| 7404 trans.reset(new HttpNetworkTransaction(session)); | |
| 7405 | |
| 7406 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7407 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7408 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 7409 | |
| 7410 response = trans->GetResponseInfo(); | |
| 7411 ASSERT_TRUE(response != NULL); | |
| 7412 ASSERT_TRUE(response->headers != NULL); | |
| 7413 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 7414 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 7415 EXPECT_TRUE(response->was_npn_negotiated); | |
| 7416 | |
| 7417 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 7418 EXPECT_EQ("hello!", response_data); | |
| 7419 | |
| 7420 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
| 7421 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 7422 } | |
| 7423 | |
| 7424 // GenerateAuthToken is a mighty big test. | |
| 7425 // It tests all permutation of GenerateAuthToken behavior: | |
| 7426 // - Synchronous and Asynchronous completion. | |
| 7427 // - OK or error on completion. | |
| 7428 // - Direct connection, non-authenticating proxy, and authenticating proxy. | |
| 7429 // - HTTP or HTTPS backend (to include proxy tunneling). | |
| 7430 // - Non-authenticating and authenticating backend. | |
| 7431 // | |
| 7432 // In all, there are 44 reasonable permuations (for example, if there are | |
| 7433 // problems generating an auth token for an authenticating proxy, we don't | |
| 7434 // need to test all permutations of the backend server). | |
| 7435 // | |
| 7436 // The test proceeds by going over each of the configuration cases, and | |
| 7437 // potentially running up to three rounds in each of the tests. The TestConfig | |
| 7438 // specifies both the configuration for the test as well as the expectations | |
| 7439 // for the results. | |
| 7440 TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) { | |
| 7441 static const char kServer[] = "http://www.example.com"; | |
| 7442 static const char kSecureServer[] = "https://www.example.com"; | |
| 7443 static const char kProxy[] = "myproxy:70"; | |
| 7444 const int kAuthErr = ERR_INVALID_AUTH_CREDENTIALS; | |
| 7445 | |
| 7446 enum AuthTiming { | |
| 7447 AUTH_NONE, | |
| 7448 AUTH_SYNC, | |
| 7449 AUTH_ASYNC, | |
| 7450 }; | |
| 7451 | |
| 7452 const MockWrite kGet( | |
| 7453 "GET / HTTP/1.1\r\n" | |
| 7454 "Host: www.example.com\r\n" | |
| 7455 "Connection: keep-alive\r\n\r\n"); | |
| 7456 const MockWrite kGetProxy( | |
| 7457 "GET http://www.example.com/ HTTP/1.1\r\n" | |
| 7458 "Host: www.example.com\r\n" | |
| 7459 "Proxy-Connection: keep-alive\r\n\r\n"); | |
| 7460 const MockWrite kGetAuth( | |
| 7461 "GET / HTTP/1.1\r\n" | |
| 7462 "Host: www.example.com\r\n" | |
| 7463 "Connection: keep-alive\r\n" | |
| 7464 "Authorization: auth_token\r\n\r\n"); | |
| 7465 const MockWrite kGetProxyAuth( | |
| 7466 "GET http://www.example.com/ HTTP/1.1\r\n" | |
| 7467 "Host: www.example.com\r\n" | |
| 7468 "Proxy-Connection: keep-alive\r\n" | |
| 7469 "Proxy-Authorization: auth_token\r\n\r\n"); | |
| 7470 const MockWrite kGetAuthThroughProxy( | |
| 7471 "GET http://www.example.com/ HTTP/1.1\r\n" | |
| 7472 "Host: www.example.com\r\n" | |
| 7473 "Proxy-Connection: keep-alive\r\n" | |
| 7474 "Authorization: auth_token\r\n\r\n"); | |
| 7475 const MockWrite kGetAuthWithProxyAuth( | |
| 7476 "GET http://www.example.com/ HTTP/1.1\r\n" | |
| 7477 "Host: www.example.com\r\n" | |
| 7478 "Proxy-Connection: keep-alive\r\n" | |
| 7479 "Proxy-Authorization: auth_token\r\n" | |
| 7480 "Authorization: auth_token\r\n\r\n"); | |
| 7481 const MockWrite kConnect( | |
| 7482 "CONNECT www.example.com:443 HTTP/1.1\r\n" | |
| 7483 "Host: www.example.com\r\n" | |
| 7484 "Proxy-Connection: keep-alive\r\n\r\n"); | |
| 7485 const MockWrite kConnectProxyAuth( | |
| 7486 "CONNECT www.example.com:443 HTTP/1.1\r\n" | |
| 7487 "Host: www.example.com\r\n" | |
| 7488 "Proxy-Connection: keep-alive\r\n" | |
| 7489 "Proxy-Authorization: auth_token\r\n\r\n"); | |
| 7490 | |
| 7491 const MockRead kSuccess( | |
| 7492 "HTTP/1.1 200 OK\r\n" | |
| 7493 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 7494 "Content-Length: 3\r\n\r\n" | |
| 7495 "Yes"); | |
| 7496 const MockRead kFailure( | |
| 7497 "Should not be called."); | |
| 7498 const MockRead kServerChallenge( | |
| 7499 "HTTP/1.1 401 Unauthorized\r\n" | |
| 7500 "WWW-Authenticate: Mock realm=server\r\n" | |
| 7501 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 7502 "Content-Length: 14\r\n\r\n" | |
| 7503 "Unauthorized\r\n"); | |
| 7504 const MockRead kProxyChallenge( | |
| 7505 "HTTP/1.1 407 Unauthorized\r\n" | |
| 7506 "Proxy-Authenticate: Mock realm=proxy\r\n" | |
| 7507 "Proxy-Connection: close\r\n" | |
| 7508 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 7509 "Content-Length: 14\r\n\r\n" | |
| 7510 "Unauthorized\r\n"); | |
| 7511 const MockRead kProxyConnected( | |
| 7512 "HTTP/1.1 200 Connection Established\r\n\r\n"); | |
| 7513 | |
| 7514 // NOTE(cbentzel): I wanted TestReadWriteRound to be a simple struct with | |
| 7515 // no constructors, but the C++ compiler on Windows warns about | |
| 7516 // unspecified data in compound literals. So, moved to using constructors, | |
| 7517 // and TestRound's created with the default constructor should not be used. | |
| 7518 struct TestRound { | |
| 7519 TestRound() | |
| 7520 : expected_rv(ERR_UNEXPECTED), | |
| 7521 extra_write(NULL), | |
| 7522 extra_read(NULL) { | |
| 7523 } | |
| 7524 TestRound(const MockWrite& write_arg, const MockRead& read_arg, | |
| 7525 int expected_rv_arg) | |
| 7526 : write(write_arg), | |
| 7527 read(read_arg), | |
| 7528 expected_rv(expected_rv_arg), | |
| 7529 extra_write(NULL), | |
| 7530 extra_read(NULL) { | |
| 7531 } | |
| 7532 TestRound(const MockWrite& write_arg, const MockRead& read_arg, | |
| 7533 int expected_rv_arg, const MockWrite* extra_write_arg, | |
| 7534 const MockWrite* extra_read_arg) | |
| 7535 : write(write_arg), | |
| 7536 read(read_arg), | |
| 7537 expected_rv(expected_rv_arg), | |
| 7538 extra_write(extra_write_arg), | |
| 7539 extra_read(extra_read_arg) { | |
| 7540 } | |
| 7541 MockWrite write; | |
| 7542 MockRead read; | |
| 7543 int expected_rv; | |
| 7544 const MockWrite* extra_write; | |
| 7545 const MockRead* extra_read; | |
| 7546 }; | |
| 7547 | |
| 7548 static const int kNoSSL = 500; | |
| 7549 | |
| 7550 struct TestConfig { | |
| 7551 const char* proxy_url; | |
| 7552 AuthTiming proxy_auth_timing; | |
| 7553 int proxy_auth_rv; | |
| 7554 const char* server_url; | |
| 7555 AuthTiming server_auth_timing; | |
| 7556 int server_auth_rv; | |
| 7557 int num_auth_rounds; | |
| 7558 int first_ssl_round; | |
| 7559 TestRound rounds[3]; | |
| 7560 } test_configs[] = { | |
| 7561 // Non-authenticating HTTP server with a direct connection. | |
| 7562 { NULL, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL, | |
| 7563 { TestRound(kGet, kSuccess, OK)}}, | |
| 7564 // Authenticating HTTP server with a direct connection. | |
| 7565 { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL, | |
| 7566 { TestRound(kGet, kServerChallenge, OK), | |
| 7567 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 7568 { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL, | |
| 7569 { TestRound(kGet, kServerChallenge, OK), | |
| 7570 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 7571 { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL, | |
| 7572 { TestRound(kGet, kServerChallenge, OK), | |
| 7573 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 7574 { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL, | |
| 7575 { TestRound(kGet, kServerChallenge, OK), | |
| 7576 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 7577 // Non-authenticating HTTP server through a non-authenticating proxy. | |
| 7578 { kProxy, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL, | |
| 7579 { TestRound(kGetProxy, kSuccess, OK)}}, | |
| 7580 // Authenticating HTTP server through a non-authenticating proxy. | |
| 7581 { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL, | |
| 7582 { TestRound(kGetProxy, kServerChallenge, OK), | |
| 7583 TestRound(kGetAuthThroughProxy, kSuccess, OK)}}, | |
| 7584 { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL, | |
| 7585 { TestRound(kGetProxy, kServerChallenge, OK), | |
| 7586 TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}}, | |
| 7587 { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL, | |
| 7588 { TestRound(kGetProxy, kServerChallenge, OK), | |
| 7589 TestRound(kGetAuthThroughProxy, kSuccess, OK)}}, | |
| 7590 { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL, | |
| 7591 { TestRound(kGetProxy, kServerChallenge, OK), | |
| 7592 TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}}, | |
| 7593 // Non-authenticating HTTP server through an authenticating proxy. | |
| 7594 { kProxy, AUTH_SYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 7595 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7596 TestRound(kGetProxyAuth, kSuccess, OK)}}, | |
| 7597 { kProxy, AUTH_SYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 7598 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7599 TestRound(kGetProxyAuth, kFailure, kAuthErr)}}, | |
| 7600 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 7601 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7602 TestRound(kGetProxyAuth, kSuccess, OK)}}, | |
| 7603 { kProxy, AUTH_ASYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 7604 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7605 TestRound(kGetProxyAuth, kFailure, kAuthErr)}}, | |
| 7606 // Authenticating HTTP server through an authenticating proxy. | |
| 7607 { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL, | |
| 7608 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7609 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 7610 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
| 7611 { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL, | |
| 7612 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7613 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 7614 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
| 7615 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL, | |
| 7616 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7617 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 7618 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
| 7619 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL, | |
| 7620 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7621 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 7622 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
| 7623 { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL, | |
| 7624 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7625 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 7626 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
| 7627 { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL, | |
| 7628 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7629 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 7630 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
| 7631 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL, | |
| 7632 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7633 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 7634 TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, | |
| 7635 { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL, | |
| 7636 { TestRound(kGetProxy, kProxyChallenge, OK), | |
| 7637 TestRound(kGetProxyAuth, kServerChallenge, OK), | |
| 7638 TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, | |
| 7639 // Non-authenticating HTTPS server with a direct connection. | |
| 7640 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0, | |
| 7641 { TestRound(kGet, kSuccess, OK)}}, | |
| 7642 // Authenticating HTTPS server with a direct connection. | |
| 7643 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0, | |
| 7644 { TestRound(kGet, kServerChallenge, OK), | |
| 7645 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 7646 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0, | |
| 7647 { TestRound(kGet, kServerChallenge, OK), | |
| 7648 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 7649 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0, | |
| 7650 { TestRound(kGet, kServerChallenge, OK), | |
| 7651 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 7652 { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0, | |
| 7653 { TestRound(kGet, kServerChallenge, OK), | |
| 7654 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 7655 // Non-authenticating HTTPS server with a non-authenticating proxy. | |
| 7656 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0, | |
| 7657 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}}, | |
| 7658 // Authenticating HTTPS server through a non-authenticating proxy. | |
| 7659 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0, | |
| 7660 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
| 7661 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 7662 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0, | |
| 7663 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
| 7664 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 7665 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0, | |
| 7666 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
| 7667 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 7668 { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0, | |
| 7669 { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), | |
| 7670 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 7671 // Non-Authenticating HTTPS server through an authenticating proxy. | |
| 7672 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1, | |
| 7673 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7674 TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}}, | |
| 7675 { kProxy, AUTH_SYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 7676 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7677 TestRound(kConnectProxyAuth, kFailure, kAuthErr)}}, | |
| 7678 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1, | |
| 7679 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7680 TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}}, | |
| 7681 { kProxy, AUTH_ASYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL, | |
| 7682 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7683 TestRound(kConnectProxyAuth, kFailure, kAuthErr)}}, | |
| 7684 // Authenticating HTTPS server through an authenticating proxy. | |
| 7685 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1, | |
| 7686 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7687 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 7688 &kGet, &kServerChallenge), | |
| 7689 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 7690 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1, | |
| 7691 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7692 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 7693 &kGet, &kServerChallenge), | |
| 7694 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 7695 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1, | |
| 7696 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7697 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 7698 &kGet, &kServerChallenge), | |
| 7699 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 7700 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1, | |
| 7701 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7702 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 7703 &kGet, &kServerChallenge), | |
| 7704 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 7705 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1, | |
| 7706 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7707 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 7708 &kGet, &kServerChallenge), | |
| 7709 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 7710 { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1, | |
| 7711 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7712 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 7713 &kGet, &kServerChallenge), | |
| 7714 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 7715 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1, | |
| 7716 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7717 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 7718 &kGet, &kServerChallenge), | |
| 7719 TestRound(kGetAuth, kSuccess, OK)}}, | |
| 7720 { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1, | |
| 7721 { TestRound(kConnect, kProxyChallenge, OK), | |
| 7722 TestRound(kConnectProxyAuth, kProxyConnected, OK, | |
| 7723 &kGet, &kServerChallenge), | |
| 7724 TestRound(kGetAuth, kFailure, kAuthErr)}}, | |
| 7725 }; | |
| 7726 | |
| 7727 SessionDependencies session_deps; | |
| 7728 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_configs); ++i) { | |
| 7729 HttpAuthHandlerMock::Factory* auth_factory( | |
| 7730 new HttpAuthHandlerMock::Factory()); | |
| 7731 session_deps.http_auth_handler_factory.reset(auth_factory); | |
| 7732 const TestConfig& test_config = test_configs[i]; | |
| 7733 | |
| 7734 // Set up authentication handlers as necessary. | |
| 7735 if (test_config.proxy_auth_timing != AUTH_NONE) { | |
| 7736 for (int n = 0; n < 2; n++) { | |
| 7737 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); | |
| 7738 std::string auth_challenge = "Mock realm=proxy"; | |
| 7739 GURL origin(test_config.proxy_url); | |
| 7740 HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(), | |
| 7741 auth_challenge.end()); | |
| 7742 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_PROXY, | |
| 7743 origin, BoundNetLog()); | |
| 7744 auth_handler->SetGenerateExpectation( | |
| 7745 test_config.proxy_auth_timing == AUTH_ASYNC, | |
| 7746 test_config.proxy_auth_rv); | |
| 7747 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); | |
| 7748 } | |
| 7749 } | |
| 7750 if (test_config.server_auth_timing != AUTH_NONE) { | |
| 7751 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); | |
| 7752 std::string auth_challenge = "Mock realm=server"; | |
| 7753 GURL origin(test_config.server_url); | |
| 7754 HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(), | |
| 7755 auth_challenge.end()); | |
| 7756 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER, | |
| 7757 origin, BoundNetLog()); | |
| 7758 auth_handler->SetGenerateExpectation( | |
| 7759 test_config.server_auth_timing == AUTH_ASYNC, | |
| 7760 test_config.server_auth_rv); | |
| 7761 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER); | |
| 7762 } | |
| 7763 if (test_config.proxy_url) { | |
| 7764 session_deps.proxy_service.reset( | |
| 7765 ProxyService::CreateFixed(test_config.proxy_url)); | |
| 7766 } else { | |
| 7767 session_deps.proxy_service.reset(ProxyService::CreateDirect()); | |
| 7768 } | |
| 7769 | |
| 7770 HttpRequestInfo request; | |
| 7771 request.method = "GET"; | |
| 7772 request.url = GURL(test_config.server_url); | |
| 7773 request.load_flags = 0; | |
| 7774 | |
| 7775 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 7776 HttpNetworkTransaction trans(CreateSession(&session_deps)); | |
| 7777 | |
| 7778 for (int round = 0; round < test_config.num_auth_rounds; ++round) { | |
| 7779 const TestRound& read_write_round = test_config.rounds[round]; | |
| 7780 | |
| 7781 // Set up expected reads and writes. | |
| 7782 MockRead reads[2]; | |
| 7783 reads[0] = read_write_round.read; | |
| 7784 size_t length_reads = 1; | |
| 7785 if (read_write_round.extra_read) { | |
| 7786 reads[1] = *read_write_round.extra_read; | |
| 7787 length_reads = 2; | |
| 7788 } | |
| 7789 | |
| 7790 MockWrite writes[2]; | |
| 7791 writes[0] = read_write_round.write; | |
| 7792 size_t length_writes = 1; | |
| 7793 if (read_write_round.extra_write) { | |
| 7794 writes[1] = *read_write_round.extra_write; | |
| 7795 length_writes = 2; | |
| 7796 } | |
| 7797 StaticSocketDataProvider data_provider( | |
| 7798 reads, length_reads, writes, length_writes); | |
| 7799 session_deps.socket_factory.AddSocketDataProvider(&data_provider); | |
| 7800 | |
| 7801 // Add an SSL sequence if necessary. | |
| 7802 SSLSocketDataProvider ssl_socket_data_provider(SYNCHRONOUS, OK); | |
| 7803 if (round >= test_config.first_ssl_round) | |
| 7804 session_deps.socket_factory.AddSSLSocketDataProvider( | |
| 7805 &ssl_socket_data_provider); | |
| 7806 | |
| 7807 // Start or restart the transaction. | |
| 7808 TestCompletionCallback callback; | |
| 7809 int rv; | |
| 7810 if (round == 0) { | |
| 7811 rv = trans.Start(&request, callback.callback(), BoundNetLog()); | |
| 7812 } else { | |
| 7813 rv = trans.RestartWithAuth( | |
| 7814 AuthCredentials(kFoo, kBar), callback.callback()); | |
| 7815 } | |
| 7816 if (rv == ERR_IO_PENDING) | |
| 7817 rv = callback.WaitForResult(); | |
| 7818 | |
| 7819 // Compare results with expected data. | |
| 7820 EXPECT_EQ(read_write_round.expected_rv, rv); | |
| 7821 const HttpResponseInfo* response = trans.GetResponseInfo(); | |
| 7822 if (read_write_round.expected_rv == OK) { | |
| 7823 ASSERT_TRUE(response != NULL); | |
| 7824 } else { | |
| 7825 EXPECT_TRUE(response == NULL); | |
| 7826 EXPECT_EQ(round + 1, test_config.num_auth_rounds); | |
| 7827 continue; | |
| 7828 } | |
| 7829 if (round + 1 < test_config.num_auth_rounds) { | |
| 7830 EXPECT_FALSE(response->auth_challenge.get() == NULL); | |
| 7831 } else { | |
| 7832 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 7833 } | |
| 7834 } | |
| 7835 } | |
| 7836 } | |
| 7837 | |
| 7838 TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) { | |
| 7839 // Do multi-round authentication and make sure it works correctly. | |
| 7840 SessionDependencies session_deps; | |
| 7841 HttpAuthHandlerMock::Factory* auth_factory( | |
| 7842 new HttpAuthHandlerMock::Factory()); | |
| 7843 session_deps.http_auth_handler_factory.reset(auth_factory); | |
| 7844 session_deps.proxy_service.reset(ProxyService::CreateDirect()); | |
| 7845 session_deps.host_resolver->rules()->AddRule("www.example.com", "10.0.0.1"); | |
| 7846 session_deps.host_resolver->set_synchronous_mode(true); | |
| 7847 | |
| 7848 HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); | |
| 7849 auth_handler->set_connection_based(true); | |
| 7850 std::string auth_challenge = "Mock realm=server"; | |
| 7851 GURL origin("http://www.example.com"); | |
| 7852 HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(), | |
| 7853 auth_challenge.end()); | |
| 7854 auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER, | |
| 7855 origin, BoundNetLog()); | |
| 7856 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER); | |
| 7857 | |
| 7858 int rv = OK; | |
| 7859 const HttpResponseInfo* response = NULL; | |
| 7860 HttpRequestInfo request; | |
| 7861 request.method = "GET"; | |
| 7862 request.url = origin; | |
| 7863 request.load_flags = 0; | |
| 7864 | |
| 7865 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 7866 | |
| 7867 // Use a TCP Socket Pool with only one connection per group. This is used | |
| 7868 // to validate that the TCP socket is not released to the pool between | |
| 7869 // each round of multi-round authentication. | |
| 7870 HttpNetworkSessionPeer session_peer(session); | |
| 7871 ClientSocketPoolHistograms transport_pool_histograms("SmallTCP"); | |
| 7872 TransportClientSocketPool* transport_pool = new TransportClientSocketPool( | |
| 7873 50, // Max sockets for pool | |
| 7874 1, // Max sockets per group | |
| 7875 &transport_pool_histograms, | |
| 7876 session_deps.host_resolver.get(), | |
| 7877 &session_deps.socket_factory, | |
| 7878 session_deps.net_log); | |
| 7879 MockClientSocketPoolManager* mock_pool_manager = | |
| 7880 new MockClientSocketPoolManager; | |
| 7881 mock_pool_manager->SetTransportSocketPool(transport_pool); | |
| 7882 session_peer.SetClientSocketPoolManager(mock_pool_manager); | |
| 7883 | |
| 7884 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 7885 TestCompletionCallback callback; | |
| 7886 | |
| 7887 const MockWrite kGet( | |
| 7888 "GET / HTTP/1.1\r\n" | |
| 7889 "Host: www.example.com\r\n" | |
| 7890 "Connection: keep-alive\r\n\r\n"); | |
| 7891 const MockWrite kGetAuth( | |
| 7892 "GET / HTTP/1.1\r\n" | |
| 7893 "Host: www.example.com\r\n" | |
| 7894 "Connection: keep-alive\r\n" | |
| 7895 "Authorization: auth_token\r\n\r\n"); | |
| 7896 | |
| 7897 const MockRead kServerChallenge( | |
| 7898 "HTTP/1.1 401 Unauthorized\r\n" | |
| 7899 "WWW-Authenticate: Mock realm=server\r\n" | |
| 7900 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 7901 "Content-Length: 14\r\n\r\n" | |
| 7902 "Unauthorized\r\n"); | |
| 7903 const MockRead kSuccess( | |
| 7904 "HTTP/1.1 200 OK\r\n" | |
| 7905 "Content-Type: text/html; charset=iso-8859-1\r\n" | |
| 7906 "Content-Length: 3\r\n\r\n" | |
| 7907 "Yes"); | |
| 7908 | |
| 7909 MockWrite writes[] = { | |
| 7910 // First round | |
| 7911 kGet, | |
| 7912 // Second round | |
| 7913 kGetAuth, | |
| 7914 // Third round | |
| 7915 kGetAuth, | |
| 7916 // Fourth round | |
| 7917 kGetAuth, | |
| 7918 // Competing request | |
| 7919 kGet, | |
| 7920 }; | |
| 7921 MockRead reads[] = { | |
| 7922 // First round | |
| 7923 kServerChallenge, | |
| 7924 // Second round | |
| 7925 kServerChallenge, | |
| 7926 // Third round | |
| 7927 kServerChallenge, | |
| 7928 // Fourth round | |
| 7929 kSuccess, | |
| 7930 // Competing response | |
| 7931 kSuccess, | |
| 7932 }; | |
| 7933 StaticSocketDataProvider data_provider(reads, arraysize(reads), | |
| 7934 writes, arraysize(writes)); | |
| 7935 session_deps.socket_factory.AddSocketDataProvider(&data_provider); | |
| 7936 | |
| 7937 const char* const kSocketGroup = "www.example.com:80"; | |
| 7938 | |
| 7939 // First round of authentication. | |
| 7940 auth_handler->SetGenerateExpectation(false, OK); | |
| 7941 rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 7942 if (rv == ERR_IO_PENDING) | |
| 7943 rv = callback.WaitForResult(); | |
| 7944 EXPECT_EQ(OK, rv); | |
| 7945 response = trans->GetResponseInfo(); | |
| 7946 ASSERT_TRUE(response != NULL); | |
| 7947 EXPECT_FALSE(response->auth_challenge.get() == NULL); | |
| 7948 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 7949 | |
| 7950 // In between rounds, another request comes in for the same domain. | |
| 7951 // It should not be able to grab the TCP socket that trans has already | |
| 7952 // claimed. | |
| 7953 scoped_ptr<HttpTransaction> trans_compete( | |
| 7954 new HttpNetworkTransaction(session)); | |
| 7955 TestCompletionCallback callback_compete; | |
| 7956 rv = trans_compete->Start( | |
| 7957 &request, callback_compete.callback(), BoundNetLog()); | |
| 7958 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 7959 // callback_compete.WaitForResult at this point would stall forever, | |
| 7960 // since the HttpNetworkTransaction does not release the request back to | |
| 7961 // the pool until after authentication completes. | |
| 7962 | |
| 7963 // Second round of authentication. | |
| 7964 auth_handler->SetGenerateExpectation(false, OK); | |
| 7965 rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback()); | |
| 7966 if (rv == ERR_IO_PENDING) | |
| 7967 rv = callback.WaitForResult(); | |
| 7968 EXPECT_EQ(OK, rv); | |
| 7969 response = trans->GetResponseInfo(); | |
| 7970 ASSERT_TRUE(response != NULL); | |
| 7971 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 7972 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 7973 | |
| 7974 // Third round of authentication. | |
| 7975 auth_handler->SetGenerateExpectation(false, OK); | |
| 7976 rv = trans->RestartWithAuth(AuthCredentials(), callback.callback()); | |
| 7977 if (rv == ERR_IO_PENDING) | |
| 7978 rv = callback.WaitForResult(); | |
| 7979 EXPECT_EQ(OK, rv); | |
| 7980 response = trans->GetResponseInfo(); | |
| 7981 ASSERT_TRUE(response != NULL); | |
| 7982 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 7983 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 7984 | |
| 7985 // Fourth round of authentication, which completes successfully. | |
| 7986 auth_handler->SetGenerateExpectation(false, OK); | |
| 7987 rv = trans->RestartWithAuth(AuthCredentials(), callback.callback()); | |
| 7988 if (rv == ERR_IO_PENDING) | |
| 7989 rv = callback.WaitForResult(); | |
| 7990 EXPECT_EQ(OK, rv); | |
| 7991 response = trans->GetResponseInfo(); | |
| 7992 ASSERT_TRUE(response != NULL); | |
| 7993 EXPECT_TRUE(response->auth_challenge.get() == NULL); | |
| 7994 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 7995 | |
| 7996 // Read the body since the fourth round was successful. This will also | |
| 7997 // release the socket back to the pool. | |
| 7998 scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(50)); | |
| 7999 rv = trans->Read(io_buf, io_buf->size(), callback.callback()); | |
| 8000 if (rv == ERR_IO_PENDING) | |
| 8001 rv = callback.WaitForResult(); | |
| 8002 EXPECT_EQ(3, rv); | |
| 8003 rv = trans->Read(io_buf, io_buf->size(), callback.callback()); | |
| 8004 EXPECT_EQ(0, rv); | |
| 8005 // There are still 0 idle sockets, since the trans_compete transaction | |
| 8006 // will be handed it immediately after trans releases it to the group. | |
| 8007 EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 8008 | |
| 8009 // The competing request can now finish. Wait for the headers and then | |
| 8010 // read the body. | |
| 8011 rv = callback_compete.WaitForResult(); | |
| 8012 EXPECT_EQ(OK, rv); | |
| 8013 rv = trans_compete->Read(io_buf, io_buf->size(), callback.callback()); | |
| 8014 if (rv == ERR_IO_PENDING) | |
| 8015 rv = callback.WaitForResult(); | |
| 8016 EXPECT_EQ(3, rv); | |
| 8017 rv = trans_compete->Read(io_buf, io_buf->size(), callback.callback()); | |
| 8018 EXPECT_EQ(0, rv); | |
| 8019 | |
| 8020 // Finally, the socket is released to the group. | |
| 8021 EXPECT_EQ(1, transport_pool->IdleSocketCountInGroup(kSocketGroup)); | |
| 8022 } | |
| 8023 | |
| 8024 class TLSDecompressionFailureSocketDataProvider : public SocketDataProvider { | |
| 8025 public: | |
| 8026 explicit TLSDecompressionFailureSocketDataProvider(bool fail_all) | |
| 8027 : fail_all_(fail_all) { | |
| 8028 } | |
| 8029 | |
| 8030 virtual MockRead GetNextRead() { | |
| 8031 if (fail_all_) | |
| 8032 return MockRead(SYNCHRONOUS, ERR_SSL_DECOMPRESSION_FAILURE_ALERT); | |
| 8033 | |
| 8034 return MockRead(SYNCHRONOUS, | |
| 8035 "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nok.\r\n"); | |
| 8036 } | |
| 8037 | |
| 8038 virtual MockWriteResult OnWrite(const std::string& data) { | |
| 8039 return MockWriteResult(SYNCHRONOUS /* async */, data.size()); | |
| 8040 } | |
| 8041 | |
| 8042 void Reset() { | |
| 8043 } | |
| 8044 | |
| 8045 private: | |
| 8046 const bool fail_all_; | |
| 8047 }; | |
| 8048 | |
| 8049 // Test that we restart a connection when we see a decompression failure from | |
| 8050 // the peer during the handshake. (In the real world we'll restart with SSLv3 | |
| 8051 // and we won't offer DEFLATE in that case.) | |
| 8052 TEST_F(HttpNetworkTransactionTest, RestartAfterTLSDecompressionFailure) { | |
| 8053 HttpRequestInfo request; | |
| 8054 request.method = "GET"; | |
| 8055 request.url = GURL("https://tlsdecompressionfailure.example.com/"); | |
| 8056 request.load_flags = 0; | |
| 8057 | |
| 8058 SessionDependencies session_deps; | |
| 8059 TLSDecompressionFailureSocketDataProvider socket_data_provider1( | |
| 8060 false /* fail all reads */); | |
| 8061 TLSDecompressionFailureSocketDataProvider socket_data_provider2(false); | |
| 8062 SSLSocketDataProvider ssl_socket_data_provider1( | |
| 8063 SYNCHRONOUS, ERR_SSL_DECOMPRESSION_FAILURE_ALERT); | |
| 8064 SSLSocketDataProvider ssl_socket_data_provider2(SYNCHRONOUS, OK); | |
| 8065 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider1); | |
| 8066 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider2); | |
| 8067 session_deps.socket_factory.AddSSLSocketDataProvider( | |
| 8068 &ssl_socket_data_provider1); | |
| 8069 session_deps.socket_factory.AddSSLSocketDataProvider( | |
| 8070 &ssl_socket_data_provider2); | |
| 8071 | |
| 8072 // Work around http://crbug.com/37454 | |
| 8073 StaticSocketDataProvider bug37454_connection; | |
| 8074 bug37454_connection.set_connect_data(MockConnect(ASYNC, ERR_UNEXPECTED)); | |
| 8075 session_deps.socket_factory.AddSocketDataProvider(&bug37454_connection); | |
| 8076 | |
| 8077 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8078 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 8079 TestCompletionCallback callback; | |
| 8080 | |
| 8081 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8082 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8083 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8084 | |
| 8085 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8086 ASSERT_TRUE(response != NULL); | |
| 8087 ASSERT_TRUE(response->headers != NULL); | |
| 8088 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 8089 | |
| 8090 std::string response_data; | |
| 8091 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 8092 EXPECT_EQ("ok.", response_data); | |
| 8093 } | |
| 8094 | |
| 8095 // Test that we restart a connection if we get a decompression failure from the | |
| 8096 // peer while reading the first bytes from the connection. This occurs when the | |
| 8097 // peer cannot handle DEFLATE but we're using False Start, so we don't notice | |
| 8098 // in the handshake. | |
| 8099 TEST_F(HttpNetworkTransactionTest, | |
| 8100 RestartAfterTLSDecompressionFailureWithFalseStart) { | |
| 8101 HttpRequestInfo request; | |
| 8102 request.method = "GET"; | |
| 8103 request.url = GURL("https://tlsdecompressionfailure2.example.com/"); | |
| 8104 request.load_flags = 0; | |
| 8105 | |
| 8106 SessionDependencies session_deps; | |
| 8107 TLSDecompressionFailureSocketDataProvider socket_data_provider1( | |
| 8108 true /* fail all reads */); | |
| 8109 TLSDecompressionFailureSocketDataProvider socket_data_provider2(false); | |
| 8110 SSLSocketDataProvider ssl_socket_data_provider1(SYNCHRONOUS, OK); | |
| 8111 SSLSocketDataProvider ssl_socket_data_provider2(SYNCHRONOUS, OK); | |
| 8112 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider1); | |
| 8113 session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider2); | |
| 8114 session_deps.socket_factory.AddSSLSocketDataProvider( | |
| 8115 &ssl_socket_data_provider1); | |
| 8116 session_deps.socket_factory.AddSSLSocketDataProvider( | |
| 8117 &ssl_socket_data_provider2); | |
| 8118 | |
| 8119 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8120 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 8121 TestCompletionCallback callback; | |
| 8122 | |
| 8123 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8124 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8125 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8126 | |
| 8127 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8128 ASSERT_TRUE(response != NULL); | |
| 8129 ASSERT_TRUE(response->headers != NULL); | |
| 8130 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 8131 | |
| 8132 std::string response_data; | |
| 8133 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 8134 EXPECT_EQ("ok.", response_data); | |
| 8135 } | |
| 8136 | |
| 8137 // This tests the case that a request is issued via http instead of spdy after | |
| 8138 // npn is negotiated. | |
| 8139 TEST_F(HttpNetworkTransactionTest, NpnWithHttpOverSSL) { | |
| 8140 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 8141 HttpStreamFactory::SetNextProtos( | |
| 8142 MakeNextProtos("http/1.1", "http1.1", NULL)); | |
| 8143 SessionDependencies session_deps; | |
| 8144 HttpRequestInfo request; | |
| 8145 request.method = "GET"; | |
| 8146 request.url = GURL("https://www.google.com/"); | |
| 8147 request.load_flags = 0; | |
| 8148 | |
| 8149 MockWrite data_writes[] = { | |
| 8150 MockWrite("GET / HTTP/1.1\r\n" | |
| 8151 "Host: www.google.com\r\n" | |
| 8152 "Connection: keep-alive\r\n\r\n"), | |
| 8153 }; | |
| 8154 | |
| 8155 MockRead data_reads[] = { | |
| 8156 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 8157 MockRead(kAlternateProtocolHttpHeader), | |
| 8158 MockRead("hello world"), | |
| 8159 MockRead(SYNCHRONOUS, OK), | |
| 8160 }; | |
| 8161 | |
| 8162 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 8163 ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; | |
| 8164 ssl.next_proto = "http/1.1"; | |
| 8165 ssl.protocol_negotiated = SSLClientSocket::kProtoHTTP11; | |
| 8166 | |
| 8167 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 8168 | |
| 8169 StaticSocketDataProvider data(data_reads, arraysize(data_reads), | |
| 8170 data_writes, arraysize(data_writes)); | |
| 8171 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 8172 | |
| 8173 TestCompletionCallback callback; | |
| 8174 | |
| 8175 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8176 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 8177 | |
| 8178 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8179 | |
| 8180 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8181 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8182 | |
| 8183 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8184 ASSERT_TRUE(response != NULL); | |
| 8185 ASSERT_TRUE(response->headers != NULL); | |
| 8186 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 8187 | |
| 8188 std::string response_data; | |
| 8189 ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); | |
| 8190 EXPECT_EQ("hello world", response_data); | |
| 8191 | |
| 8192 EXPECT_FALSE(response->was_fetched_via_spdy); | |
| 8193 EXPECT_TRUE(response->was_npn_negotiated); | |
| 8194 | |
| 8195 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
| 8196 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 8197 } | |
| 8198 | |
| 8199 TEST_F(HttpNetworkTransactionTest, SpdyPostNPNServerHangup) { | |
| 8200 // Simulate the SSL handshake completing with an NPN negotiation | |
| 8201 // followed by an immediate server closing of the socket. | |
| 8202 // Fix crash: http://crbug.com/46369 | |
| 8203 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 8204 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
| 8205 SessionDependencies session_deps; | |
| 8206 | |
| 8207 HttpRequestInfo request; | |
| 8208 request.method = "GET"; | |
| 8209 request.url = GURL("https://www.google.com/"); | |
| 8210 request.load_flags = 0; | |
| 8211 | |
| 8212 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 8213 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 8214 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 8215 | |
| 8216 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
| 8217 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
| 8218 | |
| 8219 MockRead spdy_reads[] = { | |
| 8220 MockRead(SYNCHRONOUS, 0, 0) // Not async - return 0 immediately. | |
| 8221 }; | |
| 8222 | |
| 8223 scoped_ptr<DelayedSocketData> spdy_data( | |
| 8224 new DelayedSocketData( | |
| 8225 0, // don't wait in this case, immediate hangup. | |
| 8226 spdy_reads, arraysize(spdy_reads), | |
| 8227 spdy_writes, arraysize(spdy_writes))); | |
| 8228 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 8229 | |
| 8230 TestCompletionCallback callback; | |
| 8231 | |
| 8232 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8233 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
| 8234 | |
| 8235 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8236 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8237 EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult()); | |
| 8238 | |
| 8239 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
| 8240 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 8241 } | |
| 8242 | |
| 8243 TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) { | |
| 8244 // This test ensures that the URL passed into the proxy is upgraded | |
| 8245 // to https when doing an Alternate Protocol upgrade. | |
| 8246 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 8247 HttpStreamFactory::SetNextProtos( | |
| 8248 MakeNextProtos( | |
| 8249 "http/1.1", "http1.1", "spdy/2.1", "spdy/2", "spdy", NULL)); | |
| 8250 | |
| 8251 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 8252 HttpAuthHandlerMock::Factory* auth_factory = | |
| 8253 new HttpAuthHandlerMock::Factory(); | |
| 8254 HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock(); | |
| 8255 auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); | |
| 8256 auth_factory->set_do_init_from_challenge(true); | |
| 8257 session_deps.http_auth_handler_factory.reset(auth_factory); | |
| 8258 | |
| 8259 HttpRequestInfo request; | |
| 8260 request.method = "GET"; | |
| 8261 request.url = GURL("http://www.google.com"); | |
| 8262 request.load_flags = 0; | |
| 8263 | |
| 8264 // First round goes unauthenticated through the proxy. | |
| 8265 MockWrite data_writes_1[] = { | |
| 8266 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 8267 "Host: www.google.com\r\n" | |
| 8268 "Proxy-Connection: keep-alive\r\n" | |
| 8269 "\r\n"), | |
| 8270 }; | |
| 8271 MockRead data_reads_1[] = { | |
| 8272 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 8273 MockRead("HTTP/1.1 200 OK\r\n" | |
| 8274 "Alternate-Protocol: 443:npn-spdy/2.1\r\n" | |
| 8275 "Proxy-Connection: close\r\n" | |
| 8276 "\r\n"), | |
| 8277 }; | |
| 8278 StaticSocketDataProvider data_1(data_reads_1, arraysize(data_reads_1), | |
| 8279 data_writes_1, arraysize(data_writes_1)); | |
| 8280 | |
| 8281 // Second round tries to tunnel to www.google.com due to the | |
| 8282 // Alternate-Protocol announcement in the first round. It fails due | |
| 8283 // to a proxy authentication challenge. | |
| 8284 // After the failure, a tunnel is established to www.google.com using | |
| 8285 // Proxy-Authorization headers. There is then a SPDY request round. | |
| 8286 // | |
| 8287 // NOTE: Despite the "Proxy-Connection: Close", these are done on the | |
| 8288 // same MockTCPClientSocket since the underlying HttpNetworkClientSocket | |
| 8289 // does a Disconnect and Connect on the same socket, rather than trying | |
| 8290 // to obtain a new one. | |
| 8291 // | |
| 8292 // NOTE: Originally, the proxy response to the second CONNECT request | |
| 8293 // simply returned another 407 so the unit test could skip the SSL connection | |
| 8294 // establishment and SPDY framing issues. Alas, the | |
| 8295 // retry-http-when-alternate-protocol fails logic kicks in, which was more | |
| 8296 // complicated to set up expectations for than the SPDY session. | |
| 8297 | |
| 8298 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); | |
| 8299 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 8300 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
| 8301 | |
| 8302 MockWrite data_writes_2[] = { | |
| 8303 // First connection attempt without Proxy-Authorization. | |
| 8304 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 8305 "Host: www.google.com\r\n" | |
| 8306 "Proxy-Connection: keep-alive\r\n" | |
| 8307 "\r\n"), | |
| 8308 | |
| 8309 // Second connection attempt with Proxy-Authorization. | |
| 8310 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 8311 "Host: www.google.com\r\n" | |
| 8312 "Proxy-Connection: keep-alive\r\n" | |
| 8313 "Proxy-Authorization: auth_token\r\n" | |
| 8314 "\r\n"), | |
| 8315 | |
| 8316 // SPDY request | |
| 8317 CreateMockWrite(*req), | |
| 8318 }; | |
| 8319 const char kRejectConnectResponse[] = ("HTTP/1.1 407 Unauthorized\r\n" | |
| 8320 "Proxy-Authenticate: Mock\r\n" | |
| 8321 "Proxy-Connection: close\r\n" | |
| 8322 "\r\n"); | |
| 8323 const char kAcceptConnectResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; | |
| 8324 MockRead data_reads_2[] = { | |
| 8325 // First connection attempt fails | |
| 8326 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ, 1), | |
| 8327 MockRead(ASYNC, kRejectConnectResponse, | |
| 8328 arraysize(kRejectConnectResponse) - 1, 1), | |
| 8329 | |
| 8330 // Second connection attempt passes | |
| 8331 MockRead(ASYNC, kAcceptConnectResponse, | |
| 8332 arraysize(kAcceptConnectResponse) -1, 4), | |
| 8333 | |
| 8334 // SPDY response | |
| 8335 CreateMockRead(*resp.get(), 6), | |
| 8336 CreateMockRead(*data.get(), 6), | |
| 8337 MockRead(ASYNC, 0, 0, 6), | |
| 8338 }; | |
| 8339 scoped_ptr<OrderedSocketData> data_2( | |
| 8340 new OrderedSocketData(data_reads_2, arraysize(data_reads_2), | |
| 8341 data_writes_2, arraysize(data_writes_2))); | |
| 8342 | |
| 8343 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 8344 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 8345 | |
| 8346 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
| 8347 StaticSocketDataProvider hanging_non_alternate_protocol_socket( | |
| 8348 NULL, 0, NULL, 0); | |
| 8349 hanging_non_alternate_protocol_socket.set_connect_data( | |
| 8350 never_finishing_connect); | |
| 8351 | |
| 8352 session_deps.socket_factory.AddSocketDataProvider(&data_1); | |
| 8353 session_deps.socket_factory.AddSocketDataProvider(data_2.get()); | |
| 8354 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 8355 session_deps.socket_factory.AddSocketDataProvider( | |
| 8356 &hanging_non_alternate_protocol_socket); | |
| 8357 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8358 | |
| 8359 // First round should work and provide the Alternate-Protocol state. | |
| 8360 TestCompletionCallback callback_1; | |
| 8361 scoped_ptr<HttpTransaction> trans_1(new HttpNetworkTransaction(session)); | |
| 8362 int rv = trans_1->Start(&request, callback_1.callback(), BoundNetLog()); | |
| 8363 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8364 EXPECT_EQ(OK, callback_1.WaitForResult()); | |
| 8365 | |
| 8366 // Second round should attempt a tunnel connect and get an auth challenge. | |
| 8367 TestCompletionCallback callback_2; | |
| 8368 scoped_ptr<HttpTransaction> trans_2(new HttpNetworkTransaction(session)); | |
| 8369 rv = trans_2->Start(&request, callback_2.callback(), BoundNetLog()); | |
| 8370 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8371 EXPECT_EQ(OK, callback_2.WaitForResult()); | |
| 8372 const HttpResponseInfo* response = trans_2->GetResponseInfo(); | |
| 8373 ASSERT_TRUE(response != NULL); | |
| 8374 ASSERT_FALSE(response->auth_challenge.get() == NULL); | |
| 8375 | |
| 8376 // Restart with auth. Tunnel should work and response received. | |
| 8377 TestCompletionCallback callback_3; | |
| 8378 rv = trans_2->RestartWithAuth( | |
| 8379 AuthCredentials(kFoo, kBar), callback_3.callback()); | |
| 8380 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8381 EXPECT_EQ(OK, callback_3.WaitForResult()); | |
| 8382 | |
| 8383 // After all that work, these two lines (or actually, just the scheme) are | |
| 8384 // what this test is all about. Make sure it happens correctly. | |
| 8385 const GURL& request_url = auth_handler->request_url(); | |
| 8386 EXPECT_EQ("https", request_url.scheme()); | |
| 8387 EXPECT_EQ("www.google.com", request_url.host()); | |
| 8388 | |
| 8389 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
| 8390 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 8391 } | |
| 8392 | |
| 8393 // Test that if we cancel the transaction as the connection is completing, that | |
| 8394 // everything tears down correctly. | |
| 8395 TEST_F(HttpNetworkTransactionTest, SimpleCancel) { | |
| 8396 // Setup everything about the connection to complete synchronously, so that | |
| 8397 // after calling HttpNetworkTransaction::Start, the only thing we're waiting | |
| 8398 // for is the callback from the HttpStreamRequest. | |
| 8399 // Then cancel the transaction. | |
| 8400 // Verify that we don't crash. | |
| 8401 MockConnect mock_connect(SYNCHRONOUS, OK); | |
| 8402 MockRead data_reads[] = { | |
| 8403 MockRead(SYNCHRONOUS, "HTTP/1.0 200 OK\r\n\r\n"), | |
| 8404 MockRead(SYNCHRONOUS, "hello world"), | |
| 8405 MockRead(SYNCHRONOUS, OK), | |
| 8406 }; | |
| 8407 | |
| 8408 HttpRequestInfo request; | |
| 8409 request.method = "GET"; | |
| 8410 request.url = GURL("http://www.google.com/"); | |
| 8411 request.load_flags = 0; | |
| 8412 | |
| 8413 SessionDependencies session_deps; | |
| 8414 session_deps.host_resolver->set_synchronous_mode(true); | |
| 8415 scoped_ptr<HttpTransaction> trans( | |
| 8416 new HttpNetworkTransaction(CreateSession(&session_deps))); | |
| 8417 | |
| 8418 StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); | |
| 8419 data.set_connect_data(mock_connect); | |
| 8420 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 8421 | |
| 8422 TestCompletionCallback callback; | |
| 8423 | |
| 8424 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 8425 int rv = trans->Start(&request, callback.callback(), log.bound()); | |
| 8426 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8427 trans.reset(); // Cancel the transaction here. | |
| 8428 | |
| 8429 MessageLoop::current()->RunAllPending(); | |
| 8430 } | |
| 8431 | |
| 8432 // Test a basic GET request through a proxy. | |
| 8433 TEST_F(HttpNetworkTransactionTest, ProxyGet) { | |
| 8434 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 8435 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 8436 session_deps.net_log = log.bound().net_log(); | |
| 8437 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8438 | |
| 8439 HttpRequestInfo request; | |
| 8440 request.method = "GET"; | |
| 8441 request.url = GURL("http://www.google.com/"); | |
| 8442 | |
| 8443 MockWrite data_writes1[] = { | |
| 8444 MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" | |
| 8445 "Host: www.google.com\r\n" | |
| 8446 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 8447 }; | |
| 8448 | |
| 8449 MockRead data_reads1[] = { | |
| 8450 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 8451 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 8452 MockRead("Content-Length: 100\r\n\r\n"), | |
| 8453 MockRead(SYNCHRONOUS, OK), | |
| 8454 }; | |
| 8455 | |
| 8456 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 8457 data_writes1, arraysize(data_writes1)); | |
| 8458 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 8459 | |
| 8460 TestCompletionCallback callback1; | |
| 8461 | |
| 8462 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 8463 | |
| 8464 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 8465 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8466 | |
| 8467 rv = callback1.WaitForResult(); | |
| 8468 EXPECT_EQ(OK, rv); | |
| 8469 | |
| 8470 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8471 ASSERT_TRUE(response != NULL); | |
| 8472 | |
| 8473 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 8474 EXPECT_EQ(200, response->headers->response_code()); | |
| 8475 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 8476 EXPECT_TRUE(response->was_fetched_via_proxy); | |
| 8477 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 8478 } | |
| 8479 | |
| 8480 // Test a basic HTTPS GET request through a proxy. | |
| 8481 TEST_F(HttpNetworkTransactionTest, ProxyTunnelGet) { | |
| 8482 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 8483 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 8484 session_deps.net_log = log.bound().net_log(); | |
| 8485 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8486 | |
| 8487 HttpRequestInfo request; | |
| 8488 request.method = "GET"; | |
| 8489 request.url = GURL("https://www.google.com/"); | |
| 8490 | |
| 8491 // Since we have proxy, should try to establish tunnel. | |
| 8492 MockWrite data_writes1[] = { | |
| 8493 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 8494 "Host: www.google.com\r\n" | |
| 8495 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 8496 | |
| 8497 MockWrite("GET / HTTP/1.1\r\n" | |
| 8498 "Host: www.google.com\r\n" | |
| 8499 "Connection: keep-alive\r\n\r\n"), | |
| 8500 }; | |
| 8501 | |
| 8502 MockRead data_reads1[] = { | |
| 8503 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 8504 | |
| 8505 MockRead("HTTP/1.1 200 OK\r\n"), | |
| 8506 MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), | |
| 8507 MockRead("Content-Length: 100\r\n\r\n"), | |
| 8508 MockRead(SYNCHRONOUS, OK), | |
| 8509 }; | |
| 8510 | |
| 8511 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 8512 data_writes1, arraysize(data_writes1)); | |
| 8513 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 8514 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 8515 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 8516 | |
| 8517 TestCompletionCallback callback1; | |
| 8518 | |
| 8519 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 8520 | |
| 8521 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 8522 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8523 | |
| 8524 rv = callback1.WaitForResult(); | |
| 8525 EXPECT_EQ(OK, rv); | |
| 8526 net::CapturingNetLog::EntryList entries; | |
| 8527 log.GetEntries(&entries); | |
| 8528 size_t pos = ExpectLogContainsSomewhere( | |
| 8529 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 8530 NetLog::PHASE_NONE); | |
| 8531 ExpectLogContainsSomewhere( | |
| 8532 entries, pos, | |
| 8533 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 8534 NetLog::PHASE_NONE); | |
| 8535 | |
| 8536 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
| 8537 ASSERT_TRUE(response != NULL); | |
| 8538 | |
| 8539 EXPECT_TRUE(response->headers->IsKeepAlive()); | |
| 8540 EXPECT_EQ(200, response->headers->response_code()); | |
| 8541 EXPECT_EQ(100, response->headers->GetContentLength()); | |
| 8542 EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); | |
| 8543 EXPECT_TRUE(response->was_fetched_via_proxy); | |
| 8544 } | |
| 8545 | |
| 8546 // Test a basic HTTPS GET request through a proxy, but the server hangs up | |
| 8547 // while establishing the tunnel. | |
| 8548 TEST_F(HttpNetworkTransactionTest, ProxyTunnelGetHangup) { | |
| 8549 SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); | |
| 8550 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 8551 session_deps.net_log = log.bound().net_log(); | |
| 8552 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8553 | |
| 8554 HttpRequestInfo request; | |
| 8555 request.method = "GET"; | |
| 8556 request.url = GURL("https://www.google.com/"); | |
| 8557 | |
| 8558 // Since we have proxy, should try to establish tunnel. | |
| 8559 MockWrite data_writes1[] = { | |
| 8560 MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" | |
| 8561 "Host: www.google.com\r\n" | |
| 8562 "Proxy-Connection: keep-alive\r\n\r\n"), | |
| 8563 | |
| 8564 MockWrite("GET / HTTP/1.1\r\n" | |
| 8565 "Host: www.google.com\r\n" | |
| 8566 "Connection: keep-alive\r\n\r\n"), | |
| 8567 }; | |
| 8568 | |
| 8569 MockRead data_reads1[] = { | |
| 8570 MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), | |
| 8571 MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), | |
| 8572 MockRead(ASYNC, 0, 0), // EOF | |
| 8573 }; | |
| 8574 | |
| 8575 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), | |
| 8576 data_writes1, arraysize(data_writes1)); | |
| 8577 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 8578 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 8579 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 8580 | |
| 8581 TestCompletionCallback callback1; | |
| 8582 | |
| 8583 scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); | |
| 8584 | |
| 8585 int rv = trans->Start(&request, callback1.callback(), log.bound()); | |
| 8586 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8587 | |
| 8588 rv = callback1.WaitForResult(); | |
| 8589 EXPECT_EQ(ERR_EMPTY_RESPONSE, rv); | |
| 8590 net::CapturingNetLog::EntryList entries; | |
| 8591 log.GetEntries(&entries); | |
| 8592 size_t pos = ExpectLogContainsSomewhere( | |
| 8593 entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, | |
| 8594 NetLog::PHASE_NONE); | |
| 8595 ExpectLogContainsSomewhere( | |
| 8596 entries, pos, | |
| 8597 NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, | |
| 8598 NetLog::PHASE_NONE); | |
| 8599 } | |
| 8600 | |
| 8601 // Test for crbug.com/55424. | |
| 8602 TEST_F(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) { | |
| 8603 SessionDependencies session_deps; | |
| 8604 | |
| 8605 scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet( | |
| 8606 "https://www.google.com", false, 1, LOWEST)); | |
| 8607 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
| 8608 | |
| 8609 scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 8610 scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); | |
| 8611 MockRead spdy_reads[] = { | |
| 8612 CreateMockRead(*resp), | |
| 8613 CreateMockRead(*data), | |
| 8614 MockRead(ASYNC, 0, 0), | |
| 8615 }; | |
| 8616 | |
| 8617 scoped_ptr<DelayedSocketData> spdy_data( | |
| 8618 new DelayedSocketData( | |
| 8619 1, // wait for one write to finish before reading. | |
| 8620 spdy_reads, arraysize(spdy_reads), | |
| 8621 spdy_writes, arraysize(spdy_writes))); | |
| 8622 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 8623 | |
| 8624 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 8625 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 8626 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 8627 | |
| 8628 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8629 | |
| 8630 // Set up an initial SpdySession in the pool to reuse. | |
| 8631 HostPortPair host_port_pair("www.google.com", 443); | |
| 8632 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); | |
| 8633 scoped_refptr<SpdySession> spdy_session = | |
| 8634 session->spdy_session_pool()->Get(pair, BoundNetLog()); | |
| 8635 scoped_refptr<TransportSocketParams> transport_params( | |
| 8636 new TransportSocketParams(host_port_pair, MEDIUM, false, false)); | |
| 8637 TestCompletionCallback callback; | |
| 8638 | |
| 8639 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
| 8640 EXPECT_EQ(ERR_IO_PENDING, | |
| 8641 connection->Init(host_port_pair.ToString(), transport_params, | |
| 8642 LOWEST, callback.callback(), | |
| 8643 session->GetTransportSocketPool(), BoundNetLog())); | |
| 8644 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8645 spdy_session->InitializeWithSocket(connection.release(), false, OK); | |
| 8646 | |
| 8647 HttpRequestInfo request; | |
| 8648 request.method = "GET"; | |
| 8649 request.url = GURL("https://www.google.com/"); | |
| 8650 request.load_flags = 0; | |
| 8651 | |
| 8652 // This is the important line that marks this as a preconnect. | |
| 8653 request.motivation = HttpRequestInfo::PRECONNECT_MOTIVATED; | |
| 8654 | |
| 8655 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
| 8656 | |
| 8657 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
| 8658 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 8659 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 8660 } | |
| 8661 | |
| 8662 // Given a net error, cause that error to be returned from the first Write() | |
| 8663 // call and verify that the HttpTransaction fails with that error. | |
| 8664 static void CheckErrorIsPassedBack(int error, IoMode mode) { | |
| 8665 net::HttpRequestInfo request_info; | |
| 8666 request_info.url = GURL("https://www.example.com/"); | |
| 8667 request_info.method = "GET"; | |
| 8668 request_info.load_flags = net::LOAD_NORMAL; | |
| 8669 | |
| 8670 SessionDependencies session_deps; | |
| 8671 | |
| 8672 SSLSocketDataProvider ssl_data(mode, OK); | |
| 8673 net::MockWrite data_writes[] = { | |
| 8674 net::MockWrite(mode, error), | |
| 8675 }; | |
| 8676 net::StaticSocketDataProvider data(NULL, 0, | |
| 8677 data_writes, arraysize(data_writes)); | |
| 8678 session_deps.socket_factory.AddSocketDataProvider(&data); | |
| 8679 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data); | |
| 8680 | |
| 8681 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8682 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
| 8683 | |
| 8684 TestCompletionCallback callback; | |
| 8685 int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); | |
| 8686 if (rv == net::ERR_IO_PENDING) | |
| 8687 rv = callback.WaitForResult(); | |
| 8688 ASSERT_EQ(error, rv); | |
| 8689 } | |
| 8690 | |
| 8691 TEST_F(HttpNetworkTransactionTest, SSLWriteCertError) { | |
| 8692 // Just check a grab bag of cert errors. | |
| 8693 static const int kErrors[] = { | |
| 8694 ERR_CERT_COMMON_NAME_INVALID, | |
| 8695 ERR_CERT_AUTHORITY_INVALID, | |
| 8696 ERR_CERT_DATE_INVALID, | |
| 8697 }; | |
| 8698 for (size_t i = 0; i < arraysize(kErrors); i++) { | |
| 8699 CheckErrorIsPassedBack(kErrors[i], ASYNC); | |
| 8700 CheckErrorIsPassedBack(kErrors[i], SYNCHRONOUS); | |
| 8701 } | |
| 8702 } | |
| 8703 | |
| 8704 // Ensure that a client certificate is removed from the SSL client auth | |
| 8705 // cache when: | |
| 8706 // 1) No proxy is involved. | |
| 8707 // 2) TLS False Start is disabled. | |
| 8708 // 3) The initial TLS handshake requests a client certificate. | |
| 8709 // 4) The client supplies an invalid/unacceptable certificate. | |
| 8710 TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_NoFalseStart) { | |
| 8711 net::HttpRequestInfo request_info; | |
| 8712 request_info.url = GURL("https://www.example.com/"); | |
| 8713 request_info.method = "GET"; | |
| 8714 request_info.load_flags = net::LOAD_NORMAL; | |
| 8715 | |
| 8716 SessionDependencies session_deps; | |
| 8717 | |
| 8718 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); | |
| 8719 cert_request->host_and_port = "www.example.com:443"; | |
| 8720 | |
| 8721 // [ssl_]data1 contains the data for the first SSL handshake. When a | |
| 8722 // CertificateRequest is received for the first time, the handshake will | |
| 8723 // be aborted to allow the caller to provide a certificate. | |
| 8724 SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); | |
| 8725 ssl_data1.cert_request_info = cert_request.get(); | |
| 8726 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1); | |
| 8727 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); | |
| 8728 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 8729 | |
| 8730 // [ssl_]data2 contains the data for the second SSL handshake. When TLS | |
| 8731 // False Start is not being used, the result of the SSL handshake will be | |
| 8732 // returned as part of the SSLClientSocket::Connect() call. This test | |
| 8733 // matches the result of a server sending a handshake_failure alert, | |
| 8734 // rather than a Finished message, because it requires a client | |
| 8735 // certificate and none was supplied. | |
| 8736 SSLSocketDataProvider ssl_data2(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
| 8737 ssl_data2.cert_request_info = cert_request.get(); | |
| 8738 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2); | |
| 8739 net::StaticSocketDataProvider data2(NULL, 0, NULL, 0); | |
| 8740 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 8741 | |
| 8742 // [ssl_]data3 contains the data for the third SSL handshake. When a | |
| 8743 // connection to a server fails during an SSL handshake, | |
| 8744 // HttpNetworkTransaction will attempt to fallback to SSLv3 if the initial | |
| 8745 // connection was attempted with TLSv1. This is transparent to the caller | |
| 8746 // of the HttpNetworkTransaction. Because this test failure is due to | |
| 8747 // requiring a client certificate, this fallback handshake should also | |
| 8748 // fail. | |
| 8749 SSLSocketDataProvider ssl_data3(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
| 8750 ssl_data3.cert_request_info = cert_request.get(); | |
| 8751 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); | |
| 8752 net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); | |
| 8753 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
| 8754 | |
| 8755 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8756 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
| 8757 | |
| 8758 // Begin the SSL handshake with the peer. This consumes ssl_data1. | |
| 8759 TestCompletionCallback callback; | |
| 8760 int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); | |
| 8761 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 8762 | |
| 8763 // Complete the SSL handshake, which should abort due to requiring a | |
| 8764 // client certificate. | |
| 8765 rv = callback.WaitForResult(); | |
| 8766 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); | |
| 8767 | |
| 8768 // Indicate that no certificate should be supplied. From the perspective | |
| 8769 // of SSLClientCertCache, NULL is just as meaningful as a real | |
| 8770 // certificate, so this is the same as supply a | |
| 8771 // legitimate-but-unacceptable certificate. | |
| 8772 rv = trans->RestartWithCertificate(NULL, callback.callback()); | |
| 8773 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 8774 | |
| 8775 // Ensure the certificate was added to the client auth cache before | |
| 8776 // allowing the connection to continue restarting. | |
| 8777 scoped_refptr<X509Certificate> client_cert; | |
| 8778 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
| 8779 &client_cert)); | |
| 8780 ASSERT_EQ(NULL, client_cert.get()); | |
| 8781 | |
| 8782 // Restart the handshake. This will consume ssl_data2, which fails, and | |
| 8783 // then consume ssl_data3, which should also fail. The result code is | |
| 8784 // checked against what ssl_data3 should return. | |
| 8785 rv = callback.WaitForResult(); | |
| 8786 ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); | |
| 8787 | |
| 8788 // Ensure that the client certificate is removed from the cache on a | |
| 8789 // handshake failure. | |
| 8790 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
| 8791 &client_cert)); | |
| 8792 } | |
| 8793 | |
| 8794 // Ensure that a client certificate is removed from the SSL client auth | |
| 8795 // cache when: | |
| 8796 // 1) No proxy is involved. | |
| 8797 // 2) TLS False Start is enabled. | |
| 8798 // 3) The initial TLS handshake requests a client certificate. | |
| 8799 // 4) The client supplies an invalid/unacceptable certificate. | |
| 8800 TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_FalseStart) { | |
| 8801 net::HttpRequestInfo request_info; | |
| 8802 request_info.url = GURL("https://www.example.com/"); | |
| 8803 request_info.method = "GET"; | |
| 8804 request_info.load_flags = net::LOAD_NORMAL; | |
| 8805 | |
| 8806 SessionDependencies session_deps; | |
| 8807 | |
| 8808 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); | |
| 8809 cert_request->host_and_port = "www.example.com:443"; | |
| 8810 | |
| 8811 // When TLS False Start is used, SSLClientSocket::Connect() calls will | |
| 8812 // return successfully after reading up to the peer's Certificate message. | |
| 8813 // This is to allow the caller to call SSLClientSocket::Write(), which can | |
| 8814 // enqueue application data to be sent in the same packet as the | |
| 8815 // ChangeCipherSpec and Finished messages. | |
| 8816 // The actual handshake will be finished when SSLClientSocket::Read() is | |
| 8817 // called, which expects to process the peer's ChangeCipherSpec and | |
| 8818 // Finished messages. If there was an error negotiating with the peer, | |
| 8819 // such as due to the peer requiring a client certificate when none was | |
| 8820 // supplied, the alert sent by the peer won't be processed until Read() is | |
| 8821 // called. | |
| 8822 | |
| 8823 // Like the non-False Start case, when a client certificate is requested by | |
| 8824 // the peer, the handshake is aborted during the Connect() call. | |
| 8825 // [ssl_]data1 represents the initial SSL handshake with the peer. | |
| 8826 SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); | |
| 8827 ssl_data1.cert_request_info = cert_request.get(); | |
| 8828 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1); | |
| 8829 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); | |
| 8830 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 8831 | |
| 8832 // When a client certificate is supplied, Connect() will not be aborted | |
| 8833 // when the peer requests the certificate. Instead, the handshake will | |
| 8834 // artificially succeed, allowing the caller to write the HTTP request to | |
| 8835 // the socket. The handshake messages are not processed until Read() is | |
| 8836 // called, which then detects that the handshake was aborted, due to the | |
| 8837 // peer sending a handshake_failure because it requires a client | |
| 8838 // certificate. | |
| 8839 SSLSocketDataProvider ssl_data2(ASYNC, net::OK); | |
| 8840 ssl_data2.cert_request_info = cert_request.get(); | |
| 8841 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2); | |
| 8842 net::MockRead data2_reads[] = { | |
| 8843 net::MockRead(ASYNC /* async */, net::ERR_SSL_PROTOCOL_ERROR), | |
| 8844 }; | |
| 8845 net::StaticSocketDataProvider data2( | |
| 8846 data2_reads, arraysize(data2_reads), NULL, 0); | |
| 8847 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 8848 | |
| 8849 // As described in ClientAuthCertCache_Direct_NoFalseStart, [ssl_]data3 is | |
| 8850 // the data for the SSL handshake once the TLSv1 connection falls back to | |
| 8851 // SSLv3. It has the same behaviour as [ssl_]data2. | |
| 8852 SSLSocketDataProvider ssl_data3(ASYNC, net::OK); | |
| 8853 ssl_data3.cert_request_info = cert_request.get(); | |
| 8854 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); | |
| 8855 net::StaticSocketDataProvider data3( | |
| 8856 data2_reads, arraysize(data2_reads), NULL, 0); | |
| 8857 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
| 8858 | |
| 8859 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8860 scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); | |
| 8861 | |
| 8862 // Begin the initial SSL handshake. | |
| 8863 TestCompletionCallback callback; | |
| 8864 int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); | |
| 8865 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 8866 | |
| 8867 // Complete the SSL handshake, which should abort due to requiring a | |
| 8868 // client certificate. | |
| 8869 rv = callback.WaitForResult(); | |
| 8870 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); | |
| 8871 | |
| 8872 // Indicate that no certificate should be supplied. From the perspective | |
| 8873 // of SSLClientCertCache, NULL is just as meaningful as a real | |
| 8874 // certificate, so this is the same as supply a | |
| 8875 // legitimate-but-unacceptable certificate. | |
| 8876 rv = trans->RestartWithCertificate(NULL, callback.callback()); | |
| 8877 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 8878 | |
| 8879 // Ensure the certificate was added to the client auth cache before | |
| 8880 // allowing the connection to continue restarting. | |
| 8881 scoped_refptr<X509Certificate> client_cert; | |
| 8882 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
| 8883 &client_cert)); | |
| 8884 ASSERT_EQ(NULL, client_cert.get()); | |
| 8885 | |
| 8886 | |
| 8887 // Restart the handshake. This will consume ssl_data2, which fails, and | |
| 8888 // then consume ssl_data3, which should also fail. The result code is | |
| 8889 // checked against what ssl_data3 should return. | |
| 8890 rv = callback.WaitForResult(); | |
| 8891 ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); | |
| 8892 | |
| 8893 // Ensure that the client certificate is removed from the cache on a | |
| 8894 // handshake failure. | |
| 8895 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
| 8896 &client_cert)); | |
| 8897 } | |
| 8898 | |
| 8899 // Ensure that a client certificate is removed from the SSL client auth | |
| 8900 // cache when: | |
| 8901 // 1) An HTTPS proxy is involved. | |
| 8902 // 3) The HTTPS proxy requests a client certificate. | |
| 8903 // 4) The client supplies an invalid/unacceptable certificate for the | |
| 8904 // proxy. | |
| 8905 // The test is repeated twice, first for connecting to an HTTPS endpoint, | |
| 8906 // then for connecting to an HTTP endpoint. | |
| 8907 TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) { | |
| 8908 SessionDependencies session_deps( | |
| 8909 ProxyService::CreateFixed("https://proxy:70")); | |
| 8910 CapturingBoundNetLog log(CapturingNetLog::kUnbounded); | |
| 8911 session_deps.net_log = log.bound().net_log(); | |
| 8912 | |
| 8913 scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); | |
| 8914 cert_request->host_and_port = "proxy:70"; | |
| 8915 | |
| 8916 // See ClientAuthCertCache_Direct_NoFalseStart for the explanation of | |
| 8917 // [ssl_]data[1-3]. Rather than represending the endpoint | |
| 8918 // (www.example.com:443), they represent failures with the HTTPS proxy | |
| 8919 // (proxy:70). | |
| 8920 SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); | |
| 8921 ssl_data1.cert_request_info = cert_request.get(); | |
| 8922 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1); | |
| 8923 net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); | |
| 8924 session_deps.socket_factory.AddSocketDataProvider(&data1); | |
| 8925 | |
| 8926 SSLSocketDataProvider ssl_data2(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
| 8927 ssl_data2.cert_request_info = cert_request.get(); | |
| 8928 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2); | |
| 8929 net::StaticSocketDataProvider data2(NULL, 0, NULL, 0); | |
| 8930 session_deps.socket_factory.AddSocketDataProvider(&data2); | |
| 8931 | |
| 8932 SSLSocketDataProvider ssl_data3(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); | |
| 8933 ssl_data3.cert_request_info = cert_request.get(); | |
| 8934 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); | |
| 8935 net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); | |
| 8936 session_deps.socket_factory.AddSocketDataProvider(&data3); | |
| 8937 | |
| 8938 net::HttpRequestInfo requests[2]; | |
| 8939 requests[0].url = GURL("https://www.example.com/"); | |
| 8940 requests[0].method = "GET"; | |
| 8941 requests[0].load_flags = net::LOAD_NORMAL; | |
| 8942 | |
| 8943 requests[1].url = GURL("http://www.example.com/"); | |
| 8944 requests[1].method = "GET"; | |
| 8945 requests[1].load_flags = net::LOAD_NORMAL; | |
| 8946 | |
| 8947 for (size_t i = 0; i < arraysize(requests); ++i) { | |
| 8948 session_deps.socket_factory.ResetNextMockIndexes(); | |
| 8949 scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); | |
| 8950 scoped_ptr<HttpNetworkTransaction> trans( | |
| 8951 new HttpNetworkTransaction(session)); | |
| 8952 | |
| 8953 // Begin the SSL handshake with the proxy. | |
| 8954 TestCompletionCallback callback; | |
| 8955 int rv = trans->Start( | |
| 8956 &requests[i], callback.callback(), net::BoundNetLog()); | |
| 8957 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 8958 | |
| 8959 // Complete the SSL handshake, which should abort due to requiring a | |
| 8960 // client certificate. | |
| 8961 rv = callback.WaitForResult(); | |
| 8962 ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); | |
| 8963 | |
| 8964 // Indicate that no certificate should be supplied. From the perspective | |
| 8965 // of SSLClientCertCache, NULL is just as meaningful as a real | |
| 8966 // certificate, so this is the same as supply a | |
| 8967 // legitimate-but-unacceptable certificate. | |
| 8968 rv = trans->RestartWithCertificate(NULL, callback.callback()); | |
| 8969 ASSERT_EQ(net::ERR_IO_PENDING, rv); | |
| 8970 | |
| 8971 // Ensure the certificate was added to the client auth cache before | |
| 8972 // allowing the connection to continue restarting. | |
| 8973 scoped_refptr<X509Certificate> client_cert; | |
| 8974 ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("proxy:70", | |
| 8975 &client_cert)); | |
| 8976 ASSERT_EQ(NULL, client_cert.get()); | |
| 8977 // Ensure the certificate was NOT cached for the endpoint. This only | |
| 8978 // applies to HTTPS requests, but is fine to check for HTTP requests. | |
| 8979 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
| 8980 &client_cert)); | |
| 8981 | |
| 8982 // Restart the handshake. This will consume ssl_data2, which fails, and | |
| 8983 // then consume ssl_data3, which should also fail. The result code is | |
| 8984 // checked against what ssl_data3 should return. | |
| 8985 rv = callback.WaitForResult(); | |
| 8986 ASSERT_EQ(net::ERR_PROXY_CONNECTION_FAILED, rv); | |
| 8987 | |
| 8988 // Now that the new handshake has failed, ensure that the client | |
| 8989 // certificate was removed from the client auth cache. | |
| 8990 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("proxy:70", | |
| 8991 &client_cert)); | |
| 8992 ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", | |
| 8993 &client_cert)); | |
| 8994 } | |
| 8995 } | |
| 8996 | |
| 8997 void IPPoolingAddAlias(MockCachingHostResolver* host_resolver, | |
| 8998 SpdySessionPoolPeer* pool_peer, | |
| 8999 std::string host, | |
| 9000 int port, | |
| 9001 std::string iplist) { | |
| 9002 // Create a host resolver dependency that returns address |iplist| for | |
| 9003 // resolutions of |host|. | |
| 9004 host_resolver->rules()->AddIPLiteralRule(host, iplist, ""); | |
| 9005 | |
| 9006 // Setup a HostPortProxyPair. | |
| 9007 HostPortPair host_port_pair(host, port); | |
| 9008 HostPortProxyPair pair = HostPortProxyPair(host_port_pair, | |
| 9009 ProxyServer::Direct()); | |
| 9010 | |
| 9011 // Resolve the host and port. | |
| 9012 AddressList addresses; | |
| 9013 HostResolver::RequestInfo info(host_port_pair); | |
| 9014 TestCompletionCallback callback; | |
| 9015 int rv = host_resolver->Resolve(info, &addresses, callback.callback(), NULL, | |
| 9016 BoundNetLog()); | |
| 9017 if (rv == ERR_IO_PENDING) | |
| 9018 rv = callback.WaitForResult(); | |
| 9019 DCHECK_EQ(OK, rv); | |
| 9020 | |
| 9021 // Add the first address as an alias. It would have been better to call | |
| 9022 // MockClientSocket::GetPeerAddress but that returns 192.0.2.33 whereas | |
| 9023 // MockHostResolver returns 127.0.0.1 (MockHostResolverBase::Reset). So we use | |
| 9024 // the first address (127.0.0.1) returned by MockHostResolver as an alias for | |
| 9025 // the |pair|. | |
| 9026 const addrinfo* address = addresses.head(); | |
| 9027 pool_peer->AddAlias(address, pair); | |
| 9028 } | |
| 9029 | |
| 9030 TEST_F(HttpNetworkTransactionTest, UseIPConnectionPooling) { | |
| 9031 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 9032 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
| 9033 | |
| 9034 // Set up a special HttpNetworkSession with a MockCachingHostResolver. | |
| 9035 SessionDependencies session_deps; | |
| 9036 MockCachingHostResolver host_resolver; | |
| 9037 net::HttpNetworkSession::Params params; | |
| 9038 params.client_socket_factory = &session_deps.socket_factory; | |
| 9039 params.host_resolver = &host_resolver; | |
| 9040 params.cert_verifier = session_deps.cert_verifier.get(); | |
| 9041 params.proxy_service = session_deps.proxy_service.get(); | |
| 9042 params.ssl_config_service = session_deps.ssl_config_service; | |
| 9043 params.http_auth_handler_factory = | |
| 9044 session_deps.http_auth_handler_factory.get(); | |
| 9045 params.http_server_properties = &session_deps.http_server_properties; | |
| 9046 params.net_log = session_deps.net_log; | |
| 9047 scoped_refptr<HttpNetworkSession> session(new HttpNetworkSession(params)); | |
| 9048 SpdySessionPoolPeer pool_peer(session->spdy_session_pool()); | |
| 9049 pool_peer.DisableDomainAuthenticationVerification(); | |
| 9050 | |
| 9051 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 9052 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 9053 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 9054 | |
| 9055 scoped_ptr<spdy::SpdyFrame> host1_req(ConstructSpdyGet( | |
| 9056 "https://www.google.com", false, 1, LOWEST)); | |
| 9057 scoped_ptr<spdy::SpdyFrame> host2_req(ConstructSpdyGet( | |
| 9058 "https://www.gmail.com", false, 3, LOWEST)); | |
| 9059 MockWrite spdy_writes[] = { | |
| 9060 CreateMockWrite(*host1_req, 1), | |
| 9061 CreateMockWrite(*host2_req, 4), | |
| 9062 }; | |
| 9063 scoped_ptr<spdy::SpdyFrame> host1_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 9064 scoped_ptr<spdy::SpdyFrame> host1_resp_body(ConstructSpdyBodyFrame(1, true)); | |
| 9065 scoped_ptr<spdy::SpdyFrame> host2_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 9066 scoped_ptr<spdy::SpdyFrame> host2_resp_body(ConstructSpdyBodyFrame(3, true)); | |
| 9067 MockRead spdy_reads[] = { | |
| 9068 CreateMockRead(*host1_resp, 2), | |
| 9069 CreateMockRead(*host1_resp_body, 3), | |
| 9070 CreateMockRead(*host2_resp, 5), | |
| 9071 CreateMockRead(*host2_resp_body, 6), | |
| 9072 MockRead(ASYNC, 0, 7), | |
| 9073 }; | |
| 9074 | |
| 9075 scoped_ptr<OrderedSocketData> spdy_data( | |
| 9076 new OrderedSocketData( | |
| 9077 spdy_reads, arraysize(spdy_reads), | |
| 9078 spdy_writes, arraysize(spdy_writes))); | |
| 9079 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 9080 | |
| 9081 TestCompletionCallback callback; | |
| 9082 HttpRequestInfo request1; | |
| 9083 request1.method = "GET"; | |
| 9084 request1.url = GURL("https://www.google.com/"); | |
| 9085 request1.load_flags = 0; | |
| 9086 HttpNetworkTransaction trans1(session); | |
| 9087 | |
| 9088 int rv = trans1.Start(&request1, callback.callback(), BoundNetLog()); | |
| 9089 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9090 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 9091 | |
| 9092 const HttpResponseInfo* response = trans1.GetResponseInfo(); | |
| 9093 ASSERT_TRUE(response != NULL); | |
| 9094 ASSERT_TRUE(response->headers != NULL); | |
| 9095 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9096 | |
| 9097 std::string response_data; | |
| 9098 ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); | |
| 9099 EXPECT_EQ("hello!", response_data); | |
| 9100 | |
| 9101 // Preload www.gmail.com into HostCache. | |
| 9102 HostPortPair host_port("www.gmail.com", 443); | |
| 9103 HostResolver::RequestInfo resolve_info(host_port); | |
| 9104 AddressList ignored; | |
| 9105 rv = host_resolver.Resolve(resolve_info, &ignored, callback.callback(), NULL, | |
| 9106 BoundNetLog()); | |
| 9107 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9108 rv = callback.WaitForResult(); | |
| 9109 EXPECT_EQ(OK, rv); | |
| 9110 | |
| 9111 // MockHostResolver returns 127.0.0.1, port 443 for https://www.google.com/ | |
| 9112 // and https://www.gmail.com/. Add 127.0.0.1 as alias for host_port_pair: | |
| 9113 // (www.google.com, 443). | |
| 9114 IPPoolingAddAlias(&host_resolver, &pool_peer, "www.google.com", 443, | |
| 9115 "127.0.0.1"); | |
| 9116 | |
| 9117 HttpRequestInfo request2; | |
| 9118 request2.method = "GET"; | |
| 9119 request2.url = GURL("https://www.gmail.com/"); | |
| 9120 request2.load_flags = 0; | |
| 9121 HttpNetworkTransaction trans2(session); | |
| 9122 | |
| 9123 rv = trans2.Start(&request2, callback.callback(), BoundNetLog()); | |
| 9124 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9125 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 9126 | |
| 9127 response = trans2.GetResponseInfo(); | |
| 9128 ASSERT_TRUE(response != NULL); | |
| 9129 ASSERT_TRUE(response->headers != NULL); | |
| 9130 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9131 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 9132 EXPECT_TRUE(response->was_npn_negotiated); | |
| 9133 ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); | |
| 9134 EXPECT_EQ("hello!", response_data); | |
| 9135 | |
| 9136 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
| 9137 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 9138 } | |
| 9139 | |
| 9140 class OneTimeCachingHostResolver : public net::HostResolver { | |
| 9141 public: | |
| 9142 explicit OneTimeCachingHostResolver(const HostPortPair& host_port) | |
| 9143 : host_port_(host_port) {} | |
| 9144 virtual ~OneTimeCachingHostResolver() {} | |
| 9145 | |
| 9146 RuleBasedHostResolverProc* rules() { return host_resolver_.rules(); } | |
| 9147 | |
| 9148 // HostResolver methods: | |
| 9149 virtual int Resolve(const RequestInfo& info, | |
| 9150 AddressList* addresses, | |
| 9151 const CompletionCallback& callback, | |
| 9152 RequestHandle* out_req, | |
| 9153 const BoundNetLog& net_log) OVERRIDE { | |
| 9154 return host_resolver_.Resolve( | |
| 9155 info, addresses, callback, out_req, net_log); | |
| 9156 } | |
| 9157 | |
| 9158 virtual int ResolveFromCache(const RequestInfo& info, | |
| 9159 AddressList* addresses, | |
| 9160 const BoundNetLog& net_log) OVERRIDE { | |
| 9161 int rv = host_resolver_.ResolveFromCache(info, addresses, net_log); | |
| 9162 if (rv == OK && info.host_port_pair().Equals(host_port_)) | |
| 9163 host_resolver_.GetHostCache()->clear(); | |
| 9164 return rv; | |
| 9165 } | |
| 9166 | |
| 9167 virtual void CancelRequest(RequestHandle req) OVERRIDE { | |
| 9168 host_resolver_.CancelRequest(req); | |
| 9169 } | |
| 9170 | |
| 9171 MockCachingHostResolver* GetMockHostResolver() { | |
| 9172 return &host_resolver_; | |
| 9173 } | |
| 9174 | |
| 9175 private: | |
| 9176 MockCachingHostResolver host_resolver_; | |
| 9177 const HostPortPair host_port_; | |
| 9178 }; | |
| 9179 | |
| 9180 TEST_F(HttpNetworkTransactionTest, | |
| 9181 UseIPConnectionPoolingWithHostCacheExpiration) { | |
| 9182 HttpStreamFactory::set_use_alternate_protocols(true); | |
| 9183 HttpStreamFactory::SetNextProtos(SpdyNextProtos()); | |
| 9184 | |
| 9185 // Set up a special HttpNetworkSession with a OneTimeCachingHostResolver. | |
| 9186 SessionDependencies session_deps; | |
| 9187 OneTimeCachingHostResolver host_resolver(HostPortPair("www.gmail.com", 443)); | |
| 9188 net::HttpNetworkSession::Params params; | |
| 9189 params.client_socket_factory = &session_deps.socket_factory; | |
| 9190 params.host_resolver = &host_resolver; | |
| 9191 params.cert_verifier = session_deps.cert_verifier.get(); | |
| 9192 params.proxy_service = session_deps.proxy_service.get(); | |
| 9193 params.ssl_config_service = session_deps.ssl_config_service; | |
| 9194 params.http_auth_handler_factory = | |
| 9195 session_deps.http_auth_handler_factory.get(); | |
| 9196 params.http_server_properties = &session_deps.http_server_properties; | |
| 9197 params.net_log = session_deps.net_log; | |
| 9198 scoped_refptr<HttpNetworkSession> session(new HttpNetworkSession(params)); | |
| 9199 SpdySessionPoolPeer pool_peer(session->spdy_session_pool()); | |
| 9200 pool_peer.DisableDomainAuthenticationVerification(); | |
| 9201 | |
| 9202 SSLSocketDataProvider ssl(ASYNC, OK); | |
| 9203 ssl.SetNextProto(SSLClientSocket::kProtoSPDY21); | |
| 9204 session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); | |
| 9205 | |
| 9206 scoped_ptr<spdy::SpdyFrame> host1_req(ConstructSpdyGet( | |
| 9207 "https://www.google.com", false, 1, LOWEST)); | |
| 9208 scoped_ptr<spdy::SpdyFrame> host2_req(ConstructSpdyGet( | |
| 9209 "https://www.gmail.com", false, 3, LOWEST)); | |
| 9210 MockWrite spdy_writes[] = { | |
| 9211 CreateMockWrite(*host1_req, 1), | |
| 9212 CreateMockWrite(*host2_req, 4), | |
| 9213 }; | |
| 9214 scoped_ptr<spdy::SpdyFrame> host1_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); | |
| 9215 scoped_ptr<spdy::SpdyFrame> host1_resp_body(ConstructSpdyBodyFrame(1, true)); | |
| 9216 scoped_ptr<spdy::SpdyFrame> host2_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); | |
| 9217 scoped_ptr<spdy::SpdyFrame> host2_resp_body(ConstructSpdyBodyFrame(3, true)); | |
| 9218 MockRead spdy_reads[] = { | |
| 9219 CreateMockRead(*host1_resp, 2), | |
| 9220 CreateMockRead(*host1_resp_body, 3), | |
| 9221 CreateMockRead(*host2_resp, 5), | |
| 9222 CreateMockRead(*host2_resp_body, 6), | |
| 9223 MockRead(ASYNC, 0, 7), | |
| 9224 }; | |
| 9225 | |
| 9226 scoped_ptr<OrderedSocketData> spdy_data( | |
| 9227 new OrderedSocketData( | |
| 9228 spdy_reads, arraysize(spdy_reads), | |
| 9229 spdy_writes, arraysize(spdy_writes))); | |
| 9230 session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); | |
| 9231 | |
| 9232 TestCompletionCallback callback; | |
| 9233 HttpRequestInfo request1; | |
| 9234 request1.method = "GET"; | |
| 9235 request1.url = GURL("https://www.google.com/"); | |
| 9236 request1.load_flags = 0; | |
| 9237 HttpNetworkTransaction trans1(session); | |
| 9238 | |
| 9239 int rv = trans1.Start(&request1, callback.callback(), BoundNetLog()); | |
| 9240 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9241 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 9242 | |
| 9243 const HttpResponseInfo* response = trans1.GetResponseInfo(); | |
| 9244 ASSERT_TRUE(response != NULL); | |
| 9245 ASSERT_TRUE(response->headers != NULL); | |
| 9246 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9247 | |
| 9248 std::string response_data; | |
| 9249 ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); | |
| 9250 EXPECT_EQ("hello!", response_data); | |
| 9251 | |
| 9252 // Preload cache entries into HostCache. | |
| 9253 HostResolver::RequestInfo resolve_info(HostPortPair("www.gmail.com", 443)); | |
| 9254 AddressList ignored; | |
| 9255 rv = host_resolver.Resolve(resolve_info, &ignored, callback.callback(), NULL, | |
| 9256 BoundNetLog()); | |
| 9257 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9258 rv = callback.WaitForResult(); | |
| 9259 EXPECT_EQ(OK, rv); | |
| 9260 | |
| 9261 HttpRequestInfo request2; | |
| 9262 request2.method = "GET"; | |
| 9263 request2.url = GURL("https://www.gmail.com/"); | |
| 9264 request2.load_flags = 0; | |
| 9265 HttpNetworkTransaction trans2(session); | |
| 9266 | |
| 9267 // MockHostResolver returns 127.0.0.1, port 443 for https://www.google.com/ | |
| 9268 // and https://www.gmail.com/. Add 127.0.0.1 as alias for host_port_pair: | |
| 9269 // (www.google.com, 443). | |
| 9270 IPPoolingAddAlias(host_resolver.GetMockHostResolver(), &pool_peer, | |
| 9271 "www.google.com", 443, "127.0.0.1"); | |
| 9272 | |
| 9273 rv = trans2.Start(&request2, callback.callback(), BoundNetLog()); | |
| 9274 EXPECT_EQ(ERR_IO_PENDING, rv); | |
| 9275 EXPECT_EQ(OK, callback.WaitForResult()); | |
| 9276 | |
| 9277 response = trans2.GetResponseInfo(); | |
| 9278 ASSERT_TRUE(response != NULL); | |
| 9279 ASSERT_TRUE(response->headers != NULL); | |
| 9280 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
| 9281 EXPECT_TRUE(response->was_fetched_via_spdy); | |
| 9282 EXPECT_TRUE(response->was_npn_negotiated); | |
| 9283 ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); | |
| 9284 EXPECT_EQ("hello!", response_data); | |
| 9285 | |
| 9286 HttpStreamFactory::SetNextProtos(std::vector<std::string>()); | |
| 9287 HttpStreamFactory::set_use_alternate_protocols(false); | |
| 9288 } | |
| 9289 | |
| 9290 TEST_F(HttpNetworkTransactionTest, ReadPipelineEvictionFallback) { | |
| 9291 MockRead data_reads1[] = { | |
| 9292 MockRead(SYNCHRONOUS, ERR_PIPELINE_EVICTION), | |
| 9293 }; | |
| 9294 MockRead data_reads2[] = { | |
| 9295 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
| 9296 MockRead("hello world"), | |
| 9297 MockRead(SYNCHRONOUS, OK), | |
| 9298 }; | |
| 9299 StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), NULL, 0); | |
| 9300 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), NULL, 0); | |
| 9301 StaticSocketDataProvider* data[] = { &data1, &data2 }; | |
| 9302 | |
| 9303 SimpleGetHelperResult out = SimpleGetHelperForData(data, arraysize(data)); | |
| 9304 | |
| 9305 EXPECT_EQ(OK, out.rv); | |
| 9306 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); | |
| 9307 EXPECT_EQ("hello world", out.response_data); | |
| 9308 } | |
| 9309 | |
| 9310 TEST_F(HttpNetworkTransactionTest, SendPipelineEvictionFallback) { | |
| 9311 MockWrite data_writes1[] = { | |
| 9312 MockWrite(SYNCHRONOUS, ERR_PIPELINE_EVICTION), | |
| 9313 }; | |
| 9314 MockWrite data_writes2[] = { | |
| 9315 MockWrite("GET / HTTP/1.1\r\n" | |
| 9316 "Host: www.google.com\r\n" | |
| 9317 "Connection: keep-alive\r\n\r\n"), | |
| 9318 }; | |
| 9319 MockRead data_reads2[] = { | |
| 9320 MockRead("HTTP/1.0 200 OK\r\n\r\n"), | |
| 9321 MockRead("hello world"), | |
| 9322 MockRead(SYNCHRONOUS, OK), | |
| 9323 }; | |
| 9324 StaticSocketDataProvider data1(NULL, 0, | |
| 9325 data_writes1, arraysize(data_writes1)); | |
| 9326 StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), | |
| 9327 data_writes2, arraysize(data_writes2)); | |
| 9328 StaticSocketDataProvider* data[] = { &data1, &data2 }; | |
| 9329 | |
| 9330 SimpleGetHelperResult out = SimpleGetHelperForData(data, arraysize(data)); | |
| 9331 | |
| 9332 EXPECT_EQ(OK, out.rv); | |
| 9333 EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); | |
| 9334 EXPECT_EQ("hello world", out.response_data); | |
| 9335 } | |
| 9336 | |
| 9337 } // namespace net | |
| OLD | NEW |