diff options
author | Kristian Monsen <kristianm@google.com> | 2011-06-28 21:49:31 +0100 |
---|---|---|
committer | Kristian Monsen <kristianm@google.com> | 2011-07-08 17:55:00 +0100 |
commit | ddb351dbec246cf1fab5ec20d2d5520909041de1 (patch) | |
tree | 158e3fb57bdcac07c7f1e767fde3c70687c9fbb1 /net/http | |
parent | 6b92e04f5f151c896e3088e86f70db7081009308 (diff) | |
download | external_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.zip external_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.tar.gz external_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.tar.bz2 |
Merge Chromium at r12.0.742.93: Initial merge by git
Change-Id: Ic5ee2fec31358bbee305f7e915442377bfa6cda6
Diffstat (limited to 'net/http')
62 files changed, 1510 insertions, 970 deletions
diff --git a/net/http/des.cc b/net/http/des.cc index 30706e9..e9d6388 100644 --- a/net/http/des.cc +++ b/net/http/des.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,17 +8,17 @@ #if defined(USE_OPENSSL) #include <openssl/des.h> -#include "base/openssl_util.h" +#include "crypto/openssl_util.h" #elif defined(USE_NSS) #include <nss.h> #include <pk11pub.h> -#include "base/nss_util.h" +#include "crypto/nss_util.h" #elif defined(OS_MACOSX) #include <CommonCrypto/CommonCryptor.h> #elif defined(OS_WIN) #include <windows.h> #include <wincrypt.h> -#include "base/crypto/scoped_capi_types.h" +#include "crypto/scoped_capi_types.h" #endif // The Mac and Windows (CryptoAPI) versions of DESEncrypt are our own code. @@ -90,7 +90,7 @@ void DESMakeKey(const uint8* raw, uint8* key) { #if defined(USE_OPENSSL) void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) { - base::EnsureOpenSSLInit(); + crypto::EnsureOpenSSLInit(); DES_key_schedule ks; DES_set_key_unchecked( @@ -112,7 +112,7 @@ void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) { SECStatus rv; unsigned int n; - base::EnsureNSSInit(); + crypto::EnsureNSSInit(); slot = PK11_GetBestSlot(cipher_mech, NULL); if (!slot) @@ -171,7 +171,7 @@ void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) { #elif defined(OS_WIN) void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) { - base::ScopedHCRYPTPROV provider; + crypto::ScopedHCRYPTPROV provider; if (!CryptAcquireContext(provider.receive(), NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) return; @@ -191,7 +191,7 @@ void DESEncrypt(const uint8* key, const uint8* src, uint8* hash) { key_blob.key_size = 8; // 64 bits memcpy(key_blob.key_data, key, 8); - base::ScopedHCRYPTKEY key; + crypto::ScopedHCRYPTKEY key; BOOL import_ok = CryptImportKey(provider, reinterpret_cast<BYTE*>(&key_blob), sizeof key_blob, 0, 0, key.receive()); diff --git a/net/http/disk_cache_based_ssl_host_info.h b/net/http/disk_cache_based_ssl_host_info.h index 905a3a9..1df838c 100644 --- a/net/http/disk_cache_based_ssl_host_info.h +++ b/net/http/disk_cache_based_ssl_host_info.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,9 +7,9 @@ #include <string> -#include "base/scoped_ptr.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/threading/non_thread_safe.h" -#include "base/weak_ptr.h" #include "net/base/completion_callback.h" #include "net/disk_cache/disk_cache.h" #include "net/socket/ssl_host_info.h" diff --git a/net/http/http_auth.h b/net/http/http_auth.h index cc147a2..99c3c81 100644 --- a/net/http/http_auth.h +++ b/net/http/http_auth.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,7 +9,7 @@ #include <set> #include <string> -#include "base/scoped_ptr.h" +#include "base/memory/scoped_ptr.h" #include "base/string16.h" #include "net/http/http_util.h" diff --git a/net/http/http_auth_cache.h b/net/http/http_auth_cache.h index 965cff7..e8f7f16 100644 --- a/net/http/http_auth_cache.h +++ b/net/http/http_auth_cache.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,7 +10,7 @@ #include <string> #include "base/gtest_prod_util.h" -#include "base/ref_counted.h" +#include "base/memory/ref_counted.h" #include "base/string16.h" #include "googleurl/src/gurl.h" #include "net/http/http_auth.h" diff --git a/net/http/http_auth_controller.cc b/net/http/http_auth_controller.cc index 52fc3f1..f337c30 100644 --- a/net/http/http_auth_controller.cc +++ b/net/http/http_auth_controller.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -192,13 +192,12 @@ int HttpAuthController::MaybeGenerateAuthToken(const HttpRequestInfo* request, request, &io_callback_, &auth_token_); + if (DisableOnAuthHandlerResult(rv)) + rv = OK; if (rv == ERR_IO_PENDING) user_callback_ = callback; else OnIOComplete(rv); - // This error occurs with GSSAPI, if the user has not already logged in. - if (rv == ERR_MISSING_AUTH_CREDENTIALS) - rv = OK; return rv; } @@ -244,9 +243,13 @@ void HttpAuthController::AddAuthorizationHeader( HttpRequestHeaders* authorization_headers) { DCHECK(CalledOnValidThread()); DCHECK(HaveAuth()); - authorization_headers->SetHeader( - HttpAuth::GetAuthorizationHeaderName(target_), auth_token_); - auth_token_.clear(); + // auth_token_ can be empty if we encountered a permanent error with + // the auth scheme and want to retry. + if (!auth_token_.empty()) { + authorization_headers->SetHeader( + HttpAuth::GetAuthorizationHeaderName(target_), auth_token_); + auth_token_.clear(); + } } int HttpAuthController::HandleAuthChallenge( @@ -498,15 +501,40 @@ void HttpAuthController::PopulateAuthChallenge() { auth_info_->realm = ASCIIToWide(handler_->realm()); } +bool HttpAuthController::DisableOnAuthHandlerResult(int result) { + DCHECK(CalledOnValidThread()); + + switch (result) { + // Occurs with GSSAPI, if the user has not already logged in. + case ERR_MISSING_AUTH_CREDENTIALS: + + // Can occur with GSSAPI or SSPI if the underlying library reports + // a permanent error. + case ERR_UNSUPPORTED_AUTH_SCHEME: + + // These two error codes represent failures we aren't handling. + case ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS: + case ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS: + + // Can be returned by SSPI if the authenticating authority or + // target is not known. + case ERR_MISCONFIGURED_AUTH_ENVIRONMENT: + + // In these cases, disable the current scheme as it cannot + // succeed. + DisableAuthScheme(handler_->auth_scheme()); + auth_token_.clear(); + return true; + + default: + return false; + } +} + void HttpAuthController::OnIOComplete(int result) { DCHECK(CalledOnValidThread()); - // This error occurs with GSSAPI, if the user has not already logged in. - // In that case, disable the current scheme as it cannot succeed. - if (result == ERR_MISSING_AUTH_CREDENTIALS) { - DisableAuthScheme(handler_->auth_scheme()); - auth_token_.clear(); + if (DisableOnAuthHandlerResult(result)) result = OK; - } if (user_callback_) { CompletionCallback* c = user_callback_; user_callback_ = NULL; diff --git a/net/http/http_auth_controller.h b/net/http/http_auth_controller.h index d7faaac..8fed8c8 100644 --- a/net/http/http_auth_controller.h +++ b/net/http/http_auth_controller.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,8 +10,8 @@ #include <string> #include "base/basictypes.h" -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/string16.h" #include "base/threading/non_thread_safe.h" #include "googleurl/src/gurl.h" @@ -107,6 +107,11 @@ class HttpAuthController : public base::RefCounted<HttpAuthController>, // URLRequestHttpJob can prompt for a username/password. void PopulateAuthChallenge(); + // If |result| indicates a permanent failure, disables the current + // auth scheme for this controller and returns true. Returns false + // otherwise. + bool DisableOnAuthHandlerResult(int result); + void OnIOComplete(int result); // Indicates if this handler is for Proxy auth or Server auth. diff --git a/net/http/http_auth_controller_unittest.cc b/net/http/http_auth_controller_unittest.cc new file mode 100644 index 0000000..f324e66 --- /dev/null +++ b/net/http/http_auth_controller_unittest.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/http/http_auth_controller.h" + +#include "net/base/net_errors.h" +#include "net/base/net_log.h" +#include "net/base/test_completion_callback.h" +#include "net/http/http_auth_cache.h" +#include "net/http/http_auth_handler_mock.h" +#include "net/http/http_request_info.h" +#include "net/http/http_response_headers.h" +#include "net/http/http_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace { + +enum HandlerRunMode { + RUN_HANDLER_SYNC, + RUN_HANDLER_ASYNC +}; + +enum SchemeState { + SCHEME_IS_DISABLED, + SCHEME_IS_ENABLED +}; + +// Runs an HttpAuthController with a single round mock auth handler +// that returns |handler_rv| on token generation. The handler runs in +// async if |run_mode| is RUN_HANDLER_ASYNC. Upon completion, the +// return value of the controller is tested against +// |expected_controller_rv|. |scheme_state| indicates whether the +// auth scheme used should be disabled after this run. +void RunSingleRoundAuthTest(HandlerRunMode run_mode, + int handler_rv, + int expected_controller_rv, + SchemeState scheme_state) { + BoundNetLog dummy_log; + HttpAuthCache dummy_auth_cache; + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://example.com"); + + const std::string headers_raw_string = + "HTTP/1.1 407\r\n" + "Proxy-Authenticate: MOCK foo\r\n" + "\r\n"; + std::string headers_string = HttpUtil::AssembleRawHeaders( + headers_raw_string.c_str(), headers_raw_string.length()); + scoped_refptr<HttpResponseHeaders> headers( + new HttpResponseHeaders(headers_string)); + + HttpAuthHandlerMock::Factory auth_handler_factory; + HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock(); + auth_handler->SetGenerateExpectation((run_mode == RUN_HANDLER_ASYNC), + handler_rv); + auth_handler_factory.set_mock_handler(auth_handler, HttpAuth::AUTH_PROXY); + auth_handler_factory.set_do_init_from_challenge(true); + + scoped_refptr<HttpAuthController> controller( + new HttpAuthController(HttpAuth::AUTH_PROXY, + GURL("http://example.com"), + &dummy_auth_cache, &auth_handler_factory)); + ASSERT_EQ(OK, + controller->HandleAuthChallenge(headers, false, false, dummy_log)); + EXPECT_TRUE(controller->HaveAuthHandler()); + controller->ResetAuth(string16(), string16()); + EXPECT_TRUE(controller->HaveAuth()); + + TestCompletionCallback callback; + EXPECT_EQ((run_mode == RUN_HANDLER_ASYNC)? ERR_IO_PENDING: + expected_controller_rv, + controller->MaybeGenerateAuthToken(&request, &callback, + dummy_log)); + if (run_mode == RUN_HANDLER_ASYNC) + EXPECT_EQ(expected_controller_rv, callback.WaitForResult()); + EXPECT_EQ((scheme_state == SCHEME_IS_DISABLED), + controller->IsAuthSchemeDisabled(HttpAuth::AUTH_SCHEME_MOCK)); +} + +} // namespace + +// If an HttpAuthHandler returns an error code that indicates a +// permanent error, the HttpAuthController should disable the scheme +// used and retry the request. +TEST(HttpAuthControllerTest, PermanentErrors) { + + // Run a synchronous handler that returns + // ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS. We expect a return value + // of OK from the controller so we can retry the request. + RunSingleRoundAuthTest(RUN_HANDLER_SYNC, + ERR_UNEXPECTED_SECURITY_LIBRARY_STATUS, + OK, SCHEME_IS_DISABLED); + + // Now try an async handler that returns + // ERR_MISSING_AUTH_CREDENTIALS. Async and sync handlers invoke + // different code paths in HttpAuthController when generating + // tokens. + RunSingleRoundAuthTest(RUN_HANDLER_ASYNC, ERR_MISSING_AUTH_CREDENTIALS, OK, + SCHEME_IS_DISABLED); + + // If a non-permanent error is returned by the handler, then the + // controller should report it unchanged. + RunSingleRoundAuthTest(RUN_HANDLER_ASYNC, ERR_INVALID_AUTH_CREDENTIALS, + ERR_INVALID_AUTH_CREDENTIALS, SCHEME_IS_ENABLED); +} + +} // namespace net diff --git a/net/http/http_auth_filter_unittest.cc b/net/http/http_auth_filter_unittest.cc index c7f91f9..73f649e 100644 --- a/net/http/http_auth_filter_unittest.cc +++ b/net/http/http_auth_filter_unittest.cc @@ -1,11 +1,11 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <iostream> -#include "base/scoped_ptr.h" +#include "base/memory/scoped_ptr.h" #include "googleurl/src/gurl.h" #include "net/http/http_auth_filter.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/net/http/http_auth_gssapi_posix.cc b/net/http/http_auth_gssapi_posix.cc index 9a69ec3..8a39688 100644 --- a/net/http/http_auth_gssapi_posix.cc +++ b/net/http/http_auth_gssapi_posix.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -437,6 +437,7 @@ base::NativeLibrary GSSAPISharedLibrary::LoadSharedLibrary() { #else "libgssapi_krb5.so.2", // MIT Kerberos - FC, Suse10, Debian "libgssapi.so.4", // Heimdal - Suse10, MDK + "libgssapi.so.2", // Heimdal - Gentoo "libgssapi.so.1" // Heimdal - Suse9, CITI - FC, MDK, Suse10 #endif }; @@ -451,7 +452,7 @@ base::NativeLibrary GSSAPISharedLibrary::LoadSharedLibrary() { // TODO(asanka): Move library loading to a separate thread. // http://crbug.com/66702 base::ThreadRestrictions::ScopedAllowIO allow_io_temporarily; - base::NativeLibrary lib = base::LoadNativeLibrary(file_path); + base::NativeLibrary lib = base::LoadNativeLibrary(file_path, NULL); if (lib) { // Only return this library if we can bind the functions we need. if (BindMethods(lib)) diff --git a/net/http/http_auth_gssapi_posix_unittest.cc b/net/http/http_auth_gssapi_posix_unittest.cc index 43a3285..01a62b3 100644 --- a/net/http/http_auth_gssapi_posix_unittest.cc +++ b/net/http/http_auth_gssapi_posix_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,8 +6,8 @@ #include "base/basictypes.h" #include "base/logging.h" +#include "base/memory/scoped_ptr.h" #include "base/native_library.h" -#include "base/scoped_ptr.h" #include "net/base/net_errors.h" #include "net/http/mock_gssapi_library_posix.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/net/http/http_auth_handler_basic_unittest.cc b/net/http/http_auth_handler_basic_unittest.cc index 51352da..b75e2c9 100644 --- a/net/http/http_auth_handler_basic_unittest.cc +++ b/net/http/http_auth_handler_basic_unittest.cc @@ -1,11 +1,11 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <string> #include "base/basictypes.h" -#include "base/scoped_ptr.h" +#include "base/memory/scoped_ptr.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "net/base/net_errors.h" diff --git a/net/http/http_auth_handler_digest.h b/net/http/http_auth_handler_digest.h index fca77e4..f279b65 100644 --- a/net/http/http_auth_handler_digest.h +++ b/net/http/http_auth_handler_digest.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,7 +10,7 @@ #include "base/basictypes.h" #include "base/gtest_prod_util.h" -#include "base/scoped_ptr.h" +#include "base/memory/scoped_ptr.h" #include "base/string16.h" #include "net/http/http_auth_handler.h" #include "net/http/http_auth_handler_factory.h" diff --git a/net/http/http_auth_handler_factory.h b/net/http/http_auth_handler_factory.h index 1e4134f..c5cf98e 100644 --- a/net/http/http_auth_handler_factory.h +++ b/net/http/http_auth_handler_factory.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,7 +10,7 @@ #include <string> #include <vector> -#include "base/scoped_ptr.h" +#include "base/memory/scoped_ptr.h" #include "net/http/http_auth.h" #include "net/http/url_security_manager.h" diff --git a/net/http/http_auth_handler_factory_unittest.cc b/net/http/http_auth_handler_factory_unittest.cc index 3145c4b..81c4af6 100644 --- a/net/http/http_auth_handler_factory_unittest.cc +++ b/net/http/http_auth_handler_factory_unittest.cc @@ -1,8 +1,8 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/scoped_ptr.h" +#include "base/memory/scoped_ptr.h" #include "net/base/mock_host_resolver.h" #include "net/base/net_errors.h" #include "net/http/http_auth_handler.h" diff --git a/net/http/http_auth_unittest.cc b/net/http/http_auth_unittest.cc index 6788be2..fe11c03 100644 --- a/net/http/http_auth_unittest.cc +++ b/net/http/http_auth_unittest.cc @@ -1,12 +1,12 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <set> #include <string> -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/string_util.h" #include "net/base/mock_host_resolver.h" #include "net/base/net_errors.h" diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc index 3e69d7a..6501a59 100644 --- a/net/http/http_basic_stream.cc +++ b/net/http/http_basic_stream.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -102,6 +102,10 @@ void HttpBasicStream::SetConnectionReused() { parser_->SetConnectionReused(); } +bool HttpBasicStream::IsConnectionReusable() const { + return parser_->IsConnectionReusable(); +} + void HttpBasicStream::GetSSLInfo(SSLInfo* ssl_info) { parser_->GetSSLInfo(ssl_info); } @@ -111,4 +115,8 @@ void HttpBasicStream::GetSSLCertRequestInfo( parser_->GetSSLCertRequestInfo(cert_request_info); } +bool HttpBasicStream::IsSpdyHttpStream() const { + return false; +} + } // namespace net diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h index 918596a..267c7c1 100644 --- a/net/http/http_basic_stream.h +++ b/net/http/http_basic_stream.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -13,7 +13,7 @@ #include <string> #include "base/basictypes.h" -#include "base/scoped_ptr.h" +#include "base/memory/scoped_ptr.h" #include "net/http/http_stream.h" namespace net { @@ -42,39 +42,44 @@ class HttpBasicStream : public HttpStream { // HttpStream methods: virtual int InitializeStream(const HttpRequestInfo* request_info, const BoundNetLog& net_log, - CompletionCallback* callback); + CompletionCallback* callback) OVERRIDE; virtual int SendRequest(const HttpRequestHeaders& headers, UploadDataStream* request_body, HttpResponseInfo* response, - CompletionCallback* callback); + CompletionCallback* callback) OVERRIDE; - virtual uint64 GetUploadProgress() const; + virtual uint64 GetUploadProgress() const OVERRIDE; - virtual int ReadResponseHeaders(CompletionCallback* callback); + virtual int ReadResponseHeaders(CompletionCallback* callback) OVERRIDE; - virtual const HttpResponseInfo* GetResponseInfo() const; + virtual const HttpResponseInfo* GetResponseInfo() const OVERRIDE; virtual int ReadResponseBody(IOBuffer* buf, int buf_len, - CompletionCallback* callback); + CompletionCallback* callback) OVERRIDE; - virtual void Close(bool not_reusable); + virtual void Close(bool not_reusable) OVERRIDE; - virtual HttpStream* RenewStreamForAuth(); + virtual HttpStream* RenewStreamForAuth() OVERRIDE; - virtual bool IsResponseBodyComplete() const; + virtual bool IsResponseBodyComplete() const OVERRIDE; - virtual bool CanFindEndOfResponse() const; + virtual bool CanFindEndOfResponse() const OVERRIDE; - virtual bool IsMoreDataBuffered() const; + virtual bool IsMoreDataBuffered() const OVERRIDE; - virtual bool IsConnectionReused() const; + virtual bool IsConnectionReused() const OVERRIDE; - virtual void SetConnectionReused(); + virtual void SetConnectionReused() OVERRIDE; - virtual void GetSSLInfo(SSLInfo* ssl_info); + virtual bool IsConnectionReusable() const OVERRIDE; - virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info); + virtual void GetSSLInfo(SSLInfo* ssl_info) OVERRIDE; + + virtual void GetSSLCertRequestInfo( + SSLCertRequestInfo* cert_request_info) OVERRIDE; + + virtual bool IsSpdyHttpStream() const OVERRIDE; private: scoped_refptr<GrowableIOBuffer> read_buf_; diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index 830fbaa..3943619 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,9 +14,9 @@ #include "base/callback.h" #include "base/format_macros.h" +#include "base/memory/ref_counted.h" #include "base/message_loop.h" #include "base/pickle.h" -#include "base/ref_counted.h" #include "base/stl_util-inl.h" #include "base/string_number_conversions.h" #include "base/string_util.h" diff --git a/net/http/http_cache.h b/net/http/http_cache.h index b33689d..f1c5fbe 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -22,11 +22,11 @@ #include "base/basictypes.h" #include "base/file_path.h" #include "base/hash_tables.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/message_loop_proxy.h" -#include "base/scoped_ptr.h" #include "base/task.h" #include "base/threading/non_thread_safe.h" -#include "base/weak_ptr.h" #include "net/base/cache_type.h" #include "net/base/completion_callback.h" #include "net/base/load_states.h" diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index 6665d5f..a12a64f 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,9 +13,9 @@ #include <string> #include "base/compiler_specific.h" +#include "base/memory/ref_counted.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" -#include "base/ref_counted.h" #include "base/string_util.h" #include "base/time.h" #include "net/base/cert_status_flags.h" @@ -23,10 +23,12 @@ #include "net/base/load_flags.h" #include "net/base/net_errors.h" #include "net/base/net_log.h" +#include "net/base/network_delegate.h" #include "net/base/ssl_cert_request_info.h" #include "net/base/ssl_config_service.h" #include "net/disk_cache/disk_cache.h" #include "net/http/disk_cache_based_ssl_host_info.h" +#include "net/http/http_network_session.h" #include "net/http/http_request_info.h" #include "net/http/http_response_headers.h" #include "net/http/http_transaction.h" @@ -179,19 +181,6 @@ int HttpCache::Transaction::WriteMetadata(IOBuffer* buf, int buf_len, callback, true); } -// Histogram data from the end of 2010 show the following distribution of -// response headers: -// -// Content-Length............... 87% -// Date......................... 98% -// Last-Modified................ 49% -// Etag......................... 19% -// Accept-Ranges: bytes......... 25% -// Accept-Ranges: none.......... 0.4% -// Strong Validator............. 50% -// Strong Validator + ranges.... 24% -// Strong Validator + CL........ 49% -// bool HttpCache::Transaction::AddTruncatedFlag() { DCHECK(mode_ & WRITE); @@ -199,13 +188,7 @@ bool HttpCache::Transaction::AddTruncatedFlag() { if (partial_.get() && !truncated_) return true; - // Double check that there is something worth keeping. - if (!entry_->disk_entry->GetDataSize(kResponseContentIndex)) - return false; - - if (response_.headers->GetContentLength() <= 0 || - response_.headers->HasHeaderValue("Accept-Ranges", "none") || - !response_.headers->HasStrongValidators()) + if (!CanResume(true)) return false; truncated_ = true; @@ -486,6 +469,13 @@ int HttpCache::Transaction::DoLoop(int result) { case STATE_ADD_TO_ENTRY_COMPLETE: rv = DoAddToEntryComplete(rv); break; + case STATE_NOTIFY_BEFORE_SEND_HEADERS: + DCHECK_EQ(OK, rv); + rv = DoNotifyBeforeSendHeaders(); + break; + case STATE_NOTIFY_BEFORE_SEND_HEADERS_COMPLETE: + rv = DoNotifyBeforeSendHeadersComplete(rv); + break; case STATE_START_PARTIAL_CACHE_VALIDATION: DCHECK_EQ(OK, rv); rv = DoStartPartialCacheValidation(); @@ -909,6 +899,57 @@ int HttpCache::Transaction::DoAddToEntryComplete(int result) { return OK; } +int HttpCache::Transaction::DoNotifyBeforeSendHeaders() { + // Balanced in DoNotifyBeforeSendHeadersComplete. + cache_callback_->AddRef(); + next_state_ = STATE_NOTIFY_BEFORE_SEND_HEADERS_COMPLETE; + + if (cache_->GetSession() && cache_->GetSession()->network_delegate()) { + // TODO(mpcomplete): need to be able to modify these headers. + HttpRequestHeaders headers = request_->extra_headers; + return cache_->GetSession()->network_delegate()->NotifyBeforeSendHeaders( + request_->request_id, cache_callback_, &headers); + } + + return OK; +} + +int HttpCache::Transaction::DoNotifyBeforeSendHeadersComplete(int result) { + cache_callback_->Release(); // Balanced in DoNotifyBeforeSendHeaders. + + // We now have access to the cache entry. + // + // o if we are a reader for the transaction, then we can start reading the + // cache entry. + // + // o if we can read or write, then we should check if the cache entry needs + // to be validated and then issue a network request if needed or just read + // from the cache if the cache entry is already valid. + // + // o if we are set to UPDATE, then we are handling an externally + // conditionalized request (if-modified-since / if-none-match). We check + // if the request headers define a validation request. + // + if (result == net::OK) { + switch (mode_) { + case READ: + result = BeginCacheRead(); + break; + case READ_WRITE: + result = BeginPartialCacheValidation(); + break; + case UPDATE: + result = BeginExternallyConditionalizedRequest(); + break; + case WRITE: + default: + NOTREACHED(); + result = ERR_FAILED; + } + } + return result; +} + // We may end up here multiple times for a given request. int HttpCache::Transaction::DoStartPartialCacheValidation() { if (mode_ == NONE) @@ -1013,6 +1054,16 @@ int HttpCache::Transaction::DoOverwriteCachedResponse() { partial_->FixContentLength(new_response_->headers); response_ = *new_response_; + + if (server_responded_206_ && !CanResume(false)) { + // There is no point in storing this resource because it will never be used. + DoneWritingToEntry(false); + if (partial_.get()) + partial_->FixResponseHeaders(response_.headers, true); + next_state_ = STATE_PARTIAL_HEADERS_RECEIVED; + return OK; + } + target_state_ = STATE_TRUNCATE_CACHED_DATA; next_state_ = truncated_ ? STATE_CACHE_WRITE_TRUNCATED_RESPONSE : STATE_CACHE_WRITE_RESPONSE; @@ -1109,6 +1160,7 @@ int HttpCache::Transaction::DoCacheReadResponse() { int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { cache_callback_->Release(); // Balance the AddRef from DoCacheReadResponse. + net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result); if (result != io_buf_len_ || !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_, @@ -1117,35 +1169,8 @@ int HttpCache::Transaction::DoCacheReadResponseComplete(int result) { return ERR_CACHE_READ_FAILURE; } - // We now have access to the cache entry. - // - // o if we are a reader for the transaction, then we can start reading the - // cache entry. - // - // o if we can read or write, then we should check if the cache entry needs - // to be validated and then issue a network request if needed or just read - // from the cache if the cache entry is already valid. - // - // o if we are set to UPDATE, then we are handling an externally - // conditionalized request (if-modified-since / if-none-match). We check - // if the request headers define a validation request. - // - switch (mode_) { - case READ: - result = BeginCacheRead(); - break; - case READ_WRITE: - result = BeginPartialCacheValidation(); - break; - case UPDATE: - result = BeginExternallyConditionalizedRequest(); - break; - case WRITE: - default: - NOTREACHED(); - result = ERR_FAILED; - } - return result; + next_state_ = STATE_NOTIFY_BEFORE_SEND_HEADERS; + return OK; } int HttpCache::Transaction::DoCacheWriteResponse() { @@ -1480,8 +1505,11 @@ int HttpCache::Transaction::BeginCacheValidation() { // response. If we cannot do so, then we just resort to a normal fetch. // Our mode remains READ_WRITE for a conditional request. We'll switch to // either READ or WRITE mode once we hear back from the server. - if (!ConditionalizeRequest()) + if (!ConditionalizeRequest()) { + DCHECK(!partial_.get()); + DCHECK_NE(206, response_.headers->response_code()); mode_ = WRITE; + } next_state_ = STATE_SEND_REQUEST; } return OK; @@ -1634,6 +1662,10 @@ bool HttpCache::Transaction::ConditionalizeRequest() { response_.headers->response_code() != 206) return false; + // We should have handled this case before. + DCHECK(response_.headers->response_code() != 206 || + response_.headers->HasStrongValidators()); + // Just use the first available ETag and/or Last-Modified header value. // TODO(darin): Or should we use the last? @@ -1936,6 +1968,35 @@ int HttpCache::Transaction::DoPartialCacheReadCompleted(int result) { return result; } +// Histogram data from the end of 2010 show the following distribution of +// response headers: +// +// Content-Length............... 87% +// Date......................... 98% +// Last-Modified................ 49% +// Etag......................... 19% +// Accept-Ranges: bytes......... 25% +// Accept-Ranges: none.......... 0.4% +// Strong Validator............. 50% +// Strong Validator + ranges.... 24% +// Strong Validator + CL........ 49% +// +bool HttpCache::Transaction::CanResume(bool has_data) { + // Double check that there is something worth keeping. + if (has_data && !entry_->disk_entry->GetDataSize(kResponseContentIndex)) + return false; + + if (request_->method != "GET") + return false; + + if (response_.headers->GetContentLength() <= 0 || + response_.headers->HasHeaderValue("Accept-Ranges", "none") || + !response_.headers->HasStrongValidators()) + return false; + + return true; +} + void HttpCache::Transaction::OnIOComplete(int result) { DoLoop(result); } diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h index 81160d5..945a70e 100644 --- a/net/http/http_cache_transaction.h +++ b/net/http/http_cache_transaction.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -141,6 +141,8 @@ class HttpCache::Transaction : public HttpTransaction { STATE_DOOM_ENTRY_COMPLETE, STATE_ADD_TO_ENTRY, STATE_ADD_TO_ENTRY_COMPLETE, + STATE_NOTIFY_BEFORE_SEND_HEADERS, + STATE_NOTIFY_BEFORE_SEND_HEADERS_COMPLETE, STATE_START_PARTIAL_CACHE_VALIDATION, STATE_COMPLETE_PARTIAL_CACHE_VALIDATION, STATE_UPDATE_CACHED_RESPONSE, @@ -195,6 +197,8 @@ class HttpCache::Transaction : public HttpTransaction { int DoDoomEntryComplete(int result); int DoAddToEntry(); int DoAddToEntryComplete(int result); + int DoNotifyBeforeSendHeaders(); + int DoNotifyBeforeSendHeadersComplete(int result); int DoStartPartialCacheValidation(); int DoCompletePartialCacheValidation(int result); int DoUpdateCachedResponse(); @@ -314,6 +318,11 @@ class HttpCache::Transaction : public HttpTransaction { // working with range requests. int DoPartialCacheReadCompleted(int result); + // Returns true if we should bother attempting to resume this request if it + // is aborted while in progress. If |has_data| is true, the size of the stored + // data is considered for the result. + bool CanResume(bool has_data); + // Called to signal completion of asynchronous IO. void OnIOComplete(int result); diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc index 52e48e6..5e52c31 100644 --- a/net/http/http_cache_unittest.cc +++ b/net/http/http_cache_unittest.cc @@ -1,12 +1,12 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/http/http_cache.h" #include "base/hash_tables.h" +#include "base/memory/scoped_vector.h" #include "base/message_loop.h" -#include "base/scoped_vector.h" #include "base/string_util.h" #include "base/stringprintf.h" #include "net/base/cache_type.h" @@ -1176,6 +1176,29 @@ TEST(HttpCache, SimpleGETWithDiskFailures2) { EXPECT_EQ(2, cache.disk_cache()->create_count()); } +// Tests that we don't crash after failures to read from the cache. +TEST(HttpCache, SimpleGETWithDiskFailures3) { + MockHttpCache cache; + + // Read from the network, and write to the cache. + RunTransactionTest(cache.http_cache(), kSimpleGET_Transaction); + + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + cache.disk_cache()->set_soft_failures(true); + + // Now fail to read from the cache. + scoped_ptr<Context> c(new Context()); + int rv = cache.http_cache()->CreateTransaction(&c->trans); + EXPECT_EQ(net::OK, rv); + + MockHttpRequest request(kSimpleGET_Transaction); + rv = c->trans->Start(&request, &c->callback, net::BoundNetLog()); + EXPECT_EQ(net::ERR_CACHE_READ_FAILURE, c->callback.GetResult(rv)); +} + TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Hit) { MockHttpCache cache; @@ -2877,6 +2900,35 @@ TEST(HttpCache, GET_Crazy206) { RemoveMockTransaction(&transaction); } +// Tests that we don't cache partial responses that can't be validated. +TEST(HttpCache, RangeGET_NoStrongValidators) { + MockHttpCache cache; + std::string headers; + + // Attempt to write to the cache (40-49). + MockTransaction transaction(kRangeGET_TransactionOK); + AddMockTransaction(&transaction); + transaction.response_headers = "Content-Length: 10\n" + "ETag: w/\"foo\"\n"; + RunTransactionTestWithResponse(cache.http_cache(), transaction, &headers); + + Verify206Response(headers, 40, 49); + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(1, cache.disk_cache()->create_count()); + + // Now verify that there's no cached data. + RunTransactionTestWithResponse(cache.http_cache(), kRangeGET_TransactionOK, + &headers); + + Verify206Response(headers, 40, 49); + EXPECT_EQ(2, cache.network_layer()->transaction_count()); + EXPECT_EQ(0, cache.disk_cache()->open_count()); + EXPECT_EQ(2, cache.disk_cache()->create_count()); + + RemoveMockTransaction(&transaction); +} + // Tests that we can cache range requests and fetch random blocks from the // cache and the network. TEST(HttpCache, RangeGET_OK) { @@ -3425,6 +3477,49 @@ TEST(HttpCache, RangeGET_Previous206_NotSparse_2) { RemoveMockTransaction(&kRangeGET_TransactionOK); } +// Tests that we can handle cached 206 responses that can't be validated. +TEST(HttpCache, GET_Previous206_NotValidation) { + MockHttpCache cache; + + // Create a disk cache entry that stores 206 headers. + disk_cache::Entry* entry; + ASSERT_TRUE(cache.CreateBackendEntry(kSimpleGET_Transaction.url, &entry, + NULL)); + + // Make sure that the headers cannot be validated with the server. + std::string raw_headers(kRangeGET_TransactionOK.status); + raw_headers.append("\n"); + raw_headers.append("Content-Length: 80\n"); + raw_headers = net::HttpUtil::AssembleRawHeaders(raw_headers.data(), + raw_headers.size()); + + net::HttpResponseInfo response; + response.headers = new net::HttpResponseHeaders(raw_headers); + EXPECT_TRUE(MockHttpCache::WriteResponseInfo(entry, &response, true, false)); + + scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(500)); + int len = static_cast<int>(base::strlcpy(buf->data(), + kRangeGET_TransactionOK.data, 500)); + TestCompletionCallback cb; + int rv = entry->WriteData(1, 0, buf, len, &cb, true); + EXPECT_EQ(len, cb.GetResult(rv)); + entry->Close(); + + // Now see that we don't use the stored entry. + std::string headers; + RunTransactionTestWithResponse(cache.http_cache(), kSimpleGET_Transaction, + &headers); + + // We are expecting a 200. + std::string expected_headers(kSimpleGET_Transaction.status); + expected_headers.append("\n"); + expected_headers.append(kSimpleGET_Transaction.response_headers); + EXPECT_EQ(expected_headers, headers); + EXPECT_EQ(1, cache.network_layer()->transaction_count()); + EXPECT_EQ(1, cache.disk_cache()->open_count()); + EXPECT_EQ(2, cache.disk_cache()->create_count()); +} + // Tests that we can handle range requests with cached 200 responses. TEST(HttpCache, RangeGET_Previous200) { MockHttpCache cache; @@ -3823,6 +3918,7 @@ TEST(HttpCache, RangeGET_LargeValues) { transaction.request_headers = "Range: bytes = 4294967288-4294967297\r\n" EXTRA_HEADER; transaction.response_headers = + "ETag: \"foo\"\n" "Content-Range: bytes 4294967288-4294967297/4294967299\n" "Content-Length: 10\n"; AddMockTransaction(&transaction); diff --git a/net/http/http_net_log_params.h b/net/http/http_net_log_params.h index c32250e..92039ca 100644 --- a/net/http/http_net_log_params.h +++ b/net/http/http_net_log_params.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,7 +9,7 @@ #include <string> #include "base/basictypes.h" -#include "base/ref_counted.h" +#include "base/memory/ref_counted.h" #include "net/base/net_log.h" #include "net/http/http_request_headers.h" diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc index 0fb1050..ce3fab8 100644 --- a/net/http/http_network_layer.cc +++ b/net/http/http_network_layer.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/net/http/http_network_layer.h b/net/http/http_network_layer.h index db3d809..f4843fe 100644 --- a/net/http/http_network_layer.h +++ b/net/http/http_network_layer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,8 +8,8 @@ #include <string> -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/threading/non_thread_safe.h" #include "net/http/http_transaction_factory.h" diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index e67390c..d13ec97 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -40,7 +40,7 @@ HttpNetworkSession::HttpNetworkSession(const Params& params) params.ssl_host_info_factory, params.proxy_service, params.ssl_config_service), - spdy_session_pool_(params.ssl_config_service), + spdy_session_pool_(params.host_resolver, params.ssl_config_service), ALLOW_THIS_IN_INITIALIZER_LIST(http_stream_factory_( new HttpStreamFactoryImpl(this))) { DCHECK(params.proxy_service); diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 9a4b85c..14b85ae 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,7 +7,7 @@ #pragma once #include <set> -#include "base/ref_counted.h" +#include "base/memory/ref_counted.h" #include "base/threading/non_thread_safe.h" #include "net/base/host_port_pair.h" #include "net/base/host_resolver.h" @@ -87,8 +87,8 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession>, return &alternate_protocols_; } - TCPClientSocketPool* tcp_socket_pool() { - return socket_pool_manager_.tcp_socket_pool(); + TransportClientSocketPool* transport_socket_pool() { + return socket_pool_manager_.transport_socket_pool(); } SSLClientSocketPool* ssl_socket_pool() { diff --git a/net/http/http_network_session_peer.cc b/net/http/http_network_session_peer.cc index 2ed3e76..921322a 100644 --- a/net/http/http_network_session_peer.cc +++ b/net/http/http_network_session_peer.cc @@ -9,7 +9,7 @@ #include "net/proxy/proxy_service.h" #include "net/socket/socks_client_socket_pool.h" #include "net/socket/ssl_client_socket_pool.h" -#include "net/socket/tcp_client_socket_pool.h" +#include "net/socket/transport_client_socket_pool.h" namespace net { @@ -19,8 +19,9 @@ HttpNetworkSessionPeer::HttpNetworkSessionPeer( HttpNetworkSessionPeer::~HttpNetworkSessionPeer() {} -void HttpNetworkSessionPeer::SetTCPSocketPool(TCPClientSocketPool* pool) { - session_->socket_pool_manager_.tcp_socket_pool_.reset(pool); +void HttpNetworkSessionPeer::SetTransportSocketPool( + TransportClientSocketPool* pool) { + session_->socket_pool_manager_.transport_socket_pool_.reset(pool); } void HttpNetworkSessionPeer::SetSocketPoolForSOCKSProxy( diff --git a/net/http/http_network_session_peer.h b/net/http/http_network_session_peer.h index 06101ca..51b1f81 100644 --- a/net/http/http_network_session_peer.h +++ b/net/http/http_network_session_peer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,7 @@ #define NET_HTTP_HTTP_NETWORK_SESSION_PEER_H_ #pragma once -#include "base/ref_counted.h" +#include "base/memory/ref_counted.h" namespace net { @@ -17,7 +17,7 @@ class HttpStreamFactory; class ProxyService; class SOCKSClientSocketPool; class SSLClientSocketPool; -class TCPClientSocketPool; +class TransportClientSocketPool; class HttpNetworkSessionPeer { public: @@ -25,7 +25,7 @@ class HttpNetworkSessionPeer { const scoped_refptr<HttpNetworkSession>& session); ~HttpNetworkSessionPeer(); - void SetTCPSocketPool(TCPClientSocketPool* pool); + void SetTransportSocketPool(TransportClientSocketPool* pool); void SetSocketPoolForSOCKSProxy( const HostPortPair& socks_proxy, diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index d3ed391..55330e2 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,10 +9,10 @@ #include "base/compiler_specific.h" #include "base/format_macros.h" +#include "base/memory/scoped_ptr.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" #include "base/metrics/stats_counters.h" -#include "base/scoped_ptr.h" #include "base/stl_util-inl.h" #include "base/string_number_conversions.h" #include "base/string_util.h" @@ -20,6 +20,7 @@ #include "build/build_config.h" #include "googleurl/src/gurl.h" #include "net/base/auth.h" +#include "net/base/host_port_pair.h" #include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" @@ -49,7 +50,7 @@ #include "net/socket/socks_client_socket_pool.h" #include "net/socket/ssl_client_socket.h" #include "net/socket/ssl_client_socket_pool.h" -#include "net/socket/tcp_client_socket_pool.h" +#include "net/socket/transport_client_socket_pool.h" #include "net/spdy/spdy_http_stream.h" #include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session_pool.h" @@ -98,6 +99,9 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session) : pending_auth_target_(HttpAuth::AUTH_NONE), ALLOW_THIS_IN_INITIALIZER_LIST( io_callback_(this, &HttpNetworkTransaction::OnIOComplete)), + ALLOW_THIS_IN_INITIALIZER_LIST(delegate_callback_( + new CancelableCompletionCallback<HttpNetworkTransaction>( + this, &HttpNetworkTransaction::OnIOComplete))), user_callback_(NULL), session_(session), request_(NULL), @@ -128,6 +132,9 @@ HttpNetworkTransaction::~HttpNetworkTransaction() { if (stream_->IsResponseBodyComplete()) { // If the response body is complete, we can just reuse the socket. stream_->Close(false /* reusable */); + } else if (stream_->IsSpdyHttpStream()) { + // Doesn't really matter for SpdyHttpStream. Just close it. + stream_->Close(true /* not reusable */); } else { // Otherwise, we try to drain the response body. // TODO(willchan): Consider moving this response body draining to the @@ -142,6 +149,8 @@ HttpNetworkTransaction::~HttpNetworkTransaction() { } } } + + delegate_callback_->Cancel(); } int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info, @@ -264,7 +273,7 @@ void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) { if (stream_.get()) { HttpStream* new_stream = NULL; - if (keep_alive) { + if (keep_alive && stream_->IsConnectionReusable()) { // We should call connection_->set_idle_time(), but this doesn't occur // often enough to be worth the trouble. stream_->SetConnectionReused(); @@ -272,7 +281,10 @@ void HttpNetworkTransaction::DidDrainBodyForAuthRestart(bool keep_alive) { } if (!new_stream) { - stream_->Close(!keep_alive); + // Close the stream and mark it as not_reusable. Even in the + // keep_alive case, we've determined that the stream_ is not + // reusable if new_stream is NULL. + stream_->Close(true); next_state_ = STATE_CREATE_STREAM; } else { next_state_ = STATE_INIT_STREAM; @@ -368,8 +380,6 @@ void HttpNetworkTransaction::OnStreamReady(const SSLConfig& used_ssl_config, stream_.reset(stream); ssl_config_ = used_ssl_config; proxy_info_ = used_proxy_info; - response_.was_alternate_protocol_available = - stream_request_->was_alternate_protocol_available(); response_.was_npn_negotiated = stream_request_->was_npn_negotiated(); response_.was_fetched_via_spdy = stream_request_->using_spdy(); response_.was_fetched_via_proxy = !proxy_info_.is_direct(); @@ -512,9 +522,16 @@ int HttpNetworkTransaction::DoLoop(int result) { case STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE: rv = DoGenerateServerAuthTokenComplete(rv); break; - case STATE_SEND_REQUEST: + case STATE_BUILD_REQUEST: DCHECK_EQ(OK, rv); net_log_.BeginEvent(NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, NULL); + rv = DoBuildRequest(); + break; + case STATE_BUILD_REQUEST_COMPLETE: + rv = DoBuildRequestComplete(rv); + break; + case STATE_SEND_REQUEST: + DCHECK_EQ(OK, rv); rv = DoSendRequest(); break; case STATE_SEND_REQUEST_COMPLETE: @@ -659,38 +676,123 @@ int HttpNetworkTransaction::DoGenerateServerAuthToken() { int HttpNetworkTransaction::DoGenerateServerAuthTokenComplete(int rv) { DCHECK_NE(ERR_IO_PENDING, rv); if (rv == OK) - next_state_ = STATE_SEND_REQUEST; + next_state_ = STATE_BUILD_REQUEST; return rv; } -int HttpNetworkTransaction::DoSendRequest() { - next_state_ = STATE_SEND_REQUEST_COMPLETE; +void HttpNetworkTransaction::BuildRequestHeaders(bool using_proxy) { + request_headers_.SetHeader(HttpRequestHeaders::kHost, + GetHostAndOptionalPort(request_->url)); - UploadDataStream* request_body = NULL; + // For compat with HTTP/1.0 servers and proxies: + if (using_proxy) { + request_headers_.SetHeader(HttpRequestHeaders::kProxyConnection, + "keep-alive"); + } else { + request_headers_.SetHeader(HttpRequestHeaders::kConnection, "keep-alive"); + } + + // Our consumer should have made sure that this is a safe referrer. See for + // instance WebCore::FrameLoader::HideReferrer. + if (request_->referrer.is_valid()) { + request_headers_.SetHeader(HttpRequestHeaders::kReferer, + request_->referrer.spec()); + } + + // Add a content length header? + if (request_body_.get()) { + if (request_body_->is_chunked()) { + request_headers_.SetHeader( + HttpRequestHeaders::kTransferEncoding, "chunked"); + } else { + request_headers_.SetHeader( + HttpRequestHeaders::kContentLength, + base::Uint64ToString(request_body_->size())); + } + } else if (request_->method == "POST" || request_->method == "PUT" || + request_->method == "HEAD") { + // An empty POST/PUT request still needs a content length. As for HEAD, + // IE and Safari also add a content length header. Presumably it is to + // support sending a HEAD request to an URL that only expects to be sent a + // POST or some other method that normally would have a message body. + request_headers_.SetHeader(HttpRequestHeaders::kContentLength, "0"); + } + + // Honor load flags that impact proxy caches. + if (request_->load_flags & LOAD_BYPASS_CACHE) { + request_headers_.SetHeader(HttpRequestHeaders::kPragma, "no-cache"); + request_headers_.SetHeader(HttpRequestHeaders::kCacheControl, "no-cache"); + } else if (request_->load_flags & LOAD_VALIDATE_CACHE) { + request_headers_.SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0"); + } + + if (ShouldApplyProxyAuth() && HaveAuth(HttpAuth::AUTH_PROXY)) + auth_controllers_[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader( + &request_headers_); + if (ShouldApplyServerAuth() && HaveAuth(HttpAuth::AUTH_SERVER)) + auth_controllers_[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader( + &request_headers_); + + // Headers that will be stripped from request_->extra_headers to prevent, + // e.g., plugins from overriding headers that are controlled using other + // means. Otherwise a plugin could set a referrer although sending the + // referrer is inhibited. + // TODO(jochen): check whether also other headers should be stripped. + static const char* const kExtraHeadersToBeStripped[] = { + "Referer" + }; + + HttpRequestHeaders stripped_extra_headers; + stripped_extra_headers.CopyFrom(request_->extra_headers); + for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i) + stripped_extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]); + request_headers_.MergeFrom(stripped_extra_headers); +} + +int HttpNetworkTransaction::DoBuildRequest() { + next_state_ = STATE_BUILD_REQUEST_COMPLETE; + delegate_callback_->AddRef(); // balanced in DoSendRequestComplete + + request_body_.reset(NULL); if (request_->upload_data) { int error_code; - request_body = UploadDataStream::Create(request_->upload_data, &error_code); - if (!request_body) + request_body_.reset( + UploadDataStream::Create(request_->upload_data, &error_code)); + if (!request_body_.get()) return error_code; } + headers_valid_ = false; + // This is constructed lazily (instead of within our Start method), so that // we have proxy info available. if (request_headers_.IsEmpty()) { - bool using_proxy = (proxy_info_.is_http()|| proxy_info_.is_https()) && + bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) && !is_https_request(); - HttpUtil::BuildRequestHeaders(request_, request_body, auth_controllers_, - ShouldApplyServerAuth(), - ShouldApplyProxyAuth(), using_proxy, - &request_headers_); + BuildRequestHeaders(using_proxy); + } - if (session_->network_delegate()) - session_->network_delegate()->NotifySendHttpRequest(&request_headers_); + if (session_->network_delegate()) { + return session_->network_delegate()->NotifyBeforeSendHeaders( + request_->request_id, delegate_callback_, &request_headers_); } - headers_valid_ = false; - return stream_->SendRequest(request_headers_, request_body, &response_, - &io_callback_); + return OK; +} + +int HttpNetworkTransaction::DoBuildRequestComplete(int result) { + delegate_callback_->Release(); // balanced in DoBuildRequest + + if (result == OK) + next_state_ = STATE_SEND_REQUEST; + return result; +} + +int HttpNetworkTransaction::DoSendRequest() { + next_state_ = STATE_SEND_REQUEST_COMPLETE; + + return stream_->SendRequest( + request_headers_, request_body_.release(), &response_, &io_callback_); } int HttpNetworkTransaction::DoSendRequestComplete(int result) { @@ -1062,26 +1164,16 @@ int HttpNetworkTransaction::HandleSSLHandshakeError(int error) { case ERR_SSL_VERSION_OR_CIPHER_MISMATCH: case ERR_SSL_DECOMPRESSION_FAILURE_ALERT: case ERR_SSL_BAD_RECORD_MAC_ALERT: - if (ssl_config_.tls1_enabled && - !SSLConfigService::IsKnownStrictTLSServer(request_->url.host())) { + if (ssl_config_.tls1_enabled) { // This could be a TLS-intolerant server, an SSL 3.0 server that // chose a TLS-only cipher suite or a server with buggy DEFLATE // support. Turn off TLS 1.0, DEFLATE support and retry. - session_->http_stream_factory()->AddTLSIntolerantServer(request_->url); + session_->http_stream_factory()->AddTLSIntolerantServer( + HostPortPair::FromURL(request_->url)); ResetConnectionAndRequestForResend(); error = OK; } break; - case ERR_SSL_SNAP_START_NPN_MISPREDICTION: - // This means that we tried to Snap Start a connection, but we - // mispredicted the NPN result. This isn't a problem from the point of - // view of the SSL layer because the server will ignore the application - // data in the Snap Start extension. However, at the HTTP layer, we have - // already decided that it's a HTTP or SPDY connection and it's easier to - // abort and start again. - ResetConnectionAndRequestForResend(); - error = OK; - break; } return error; } @@ -1206,7 +1298,6 @@ bool HttpNetworkTransaction::HaveAuth(HttpAuth::Target target) const { auth_controllers_[target]->HaveAuth(); } - GURL HttpNetworkTransaction::AuthURL(HttpAuth::Target target) const { switch (target) { case HttpAuth::AUTH_PROXY: { @@ -1235,6 +1326,8 @@ std::string HttpNetworkTransaction::DescribeState(State state) { switch (state) { STATE_CASE(STATE_CREATE_STREAM); STATE_CASE(STATE_CREATE_STREAM_COMPLETE); + STATE_CASE(STATE_BUILD_REQUEST); + STATE_CASE(STATE_BUILD_REQUEST_COMPLETE); STATE_CASE(STATE_SEND_REQUEST); STATE_CASE(STATE_SEND_REQUEST_COMPLETE); STATE_CASE(STATE_READ_HEADERS); diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index 3cec010..00e9a65 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,8 +10,8 @@ #include "base/basictypes.h" #include "base/gtest_prod_util.h" -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/time.h" #include "net/base/net_log.h" #include "net/base/request_priority.h" @@ -94,6 +94,8 @@ class HttpNetworkTransaction : public HttpTransaction, STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE, STATE_GENERATE_SERVER_AUTH_TOKEN, STATE_GENERATE_SERVER_AUTH_TOKEN_COMPLETE, + STATE_BUILD_REQUEST, + STATE_BUILD_REQUEST_COMPLETE, STATE_SEND_REQUEST, STATE_SEND_REQUEST_COMPLETE, STATE_READ_HEADERS, @@ -125,6 +127,8 @@ class HttpNetworkTransaction : public HttpTransaction, int DoGenerateProxyAuthTokenComplete(int result); int DoGenerateServerAuthToken(); int DoGenerateServerAuthTokenComplete(int result); + int DoBuildRequest(); + int DoBuildRequestComplete(int result); int DoSendRequest(); int DoSendRequestComplete(int result); int DoReadHeaders(); @@ -134,6 +138,8 @@ class HttpNetworkTransaction : public HttpTransaction, int DoDrainBodyForAuthRestart(); int DoDrainBodyForAuthRestartComplete(int result); + void BuildRequestHeaders(bool using_proxy); + // Record histogram of time until first byte of header is received. void LogTransactionConnectedMetrics(); @@ -217,7 +223,10 @@ class HttpNetworkTransaction : public HttpTransaction, HttpAuth::Target pending_auth_target_; CompletionCallbackImpl<HttpNetworkTransaction> io_callback_; + scoped_refptr<CancelableCompletionCallback<HttpNetworkTransaction> > + delegate_callback_; CompletionCallback* user_callback_; + scoped_ptr<UploadDataStream> request_body_; scoped_refptr<HttpNetworkSession> session_; diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index ecd6132..b614ec8 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,7 +11,7 @@ #include "base/compiler_specific.h" #include "base/file_path.h" #include "base/file_util.h" -#include "base/scoped_ptr.h" +#include "base/memory/scoped_ptr.h" #include "base/utf_string_conversions.h" #include "net/base/auth.h" #include "net/base/capturing_net_log.h" @@ -295,8 +295,8 @@ class CaptureGroupNameSocketPool : public ParentPool { std::string last_group_name_; }; -typedef CaptureGroupNameSocketPool<TCPClientSocketPool> -CaptureGroupNameTCPSocketPool; +typedef CaptureGroupNameSocketPool<TransportClientSocketPool> +CaptureGroupNameTransportSocketPool; typedef CaptureGroupNameSocketPool<HttpProxyClientSocketPool> CaptureGroupNameHttpProxySocketPool; typedef CaptureGroupNameSocketPool<SOCKSClientSocketPool> @@ -1192,9 +1192,18 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) { MockRead("Hello"), }; + // If there is a regression where we disconnect a Keep-Alive + // connection during an auth roundtrip, we'll end up reading this. + MockRead data_reads2[] = { + MockRead(false, ERR_FAILED), + }; + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), data_writes1, arraysize(data_writes1)); + StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), + NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&data1); + session_deps.socket_factory.AddSocketDataProvider(&data2); TestCompletionCallback callback1; @@ -1224,7 +1233,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) { EXPECT_EQ(OK, rv); response = trans->GetResponseInfo(); - EXPECT_FALSE(response == NULL); + ASSERT_FALSE(response == NULL); EXPECT_TRUE(response->auth_challenge.get() == NULL); EXPECT_EQ(5, response->headers->GetContentLength()); } @@ -1265,9 +1274,17 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) { MockRead("hello"), }; + // An incorrect reconnect would cause this to be read. + MockRead data_reads2[] = { + MockRead(false, ERR_FAILED), + }; + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), data_writes1, arraysize(data_writes1)); + StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), + NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&data1); + session_deps.socket_factory.AddSocketDataProvider(&data2); TestCompletionCallback callback1; @@ -1297,7 +1314,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) { EXPECT_EQ(OK, rv); response = trans->GetResponseInfo(); - EXPECT_FALSE(response == NULL); + ASSERT_FALSE(response == NULL); EXPECT_TRUE(response->auth_challenge.get() == NULL); EXPECT_EQ(5, response->headers->GetContentLength()); } @@ -1346,9 +1363,17 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) { MockRead("hello"), }; + // An incorrect reconnect would cause this to be read. + MockRead data_reads2[] = { + MockRead(false, ERR_FAILED), + }; + StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), data_writes1, arraysize(data_writes1)); + StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), + NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&data1); + session_deps.socket_factory.AddSocketDataProvider(&data2); TestCompletionCallback callback1; @@ -1378,7 +1403,7 @@ TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) { EXPECT_EQ(OK, rv); response = trans->GetResponseInfo(); - EXPECT_FALSE(response == NULL); + ASSERT_FALSE(response == NULL); EXPECT_TRUE(response->auth_challenge.get() == NULL); EXPECT_EQ(5, response->headers->GetContentLength()); } @@ -3120,7 +3145,7 @@ TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) { // Make sure that we don't try to reuse a TCPClientSocket when failing to // establish tunnel. // http://code.google.com/p/chromium/issues/detail?id=3772 -TEST_F(HttpNetworkTransactionTest, DontRecycleTCPSocketForSSLTunnel) { +TEST_F(HttpNetworkTransactionTest, DontRecycleTransportSocketForSSLTunnel) { HttpRequestInfo request; request.method = "GET"; request.url = GURL("https://www.google.com/"); @@ -3170,11 +3195,11 @@ TEST_F(HttpNetworkTransactionTest, DontRecycleTCPSocketForSSLTunnel) { // We now check to make sure the TCPClientSocket was not added back to // the pool. - EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); + EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); trans.reset(); MessageLoop::current()->RunAllPending(); // Make sure that the socket didn't get recycled after calling the destructor. - EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); + EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); } // Make sure that we recycle a socket after reading all of the response body. @@ -3217,7 +3242,7 @@ TEST_F(HttpNetworkTransactionTest, RecycleSocket) { std::string status_line = response->headers->GetStatusLine(); EXPECT_EQ("HTTP/1.1 200 OK", status_line); - EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); + EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); std::string response_data; rv = ReadTransaction(trans.get(), &response_data); @@ -3229,7 +3254,7 @@ TEST_F(HttpNetworkTransactionTest, RecycleSocket) { MessageLoop::current()->RunAllPending(); // We now check to make sure the socket was added back to the pool. - EXPECT_EQ(1, session->tcp_socket_pool()->IdleSocketCount()); + EXPECT_EQ(1, session->transport_socket_pool()->IdleSocketCount()); } // Make sure that we recycle a SSL socket after reading all of the response @@ -3276,7 +3301,7 @@ TEST_F(HttpNetworkTransactionTest, RecycleSSLSocket) { ASSERT_TRUE(response->headers != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); + EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); std::string response_data; rv = ReadTransaction(trans.get(), &response_data); @@ -3344,7 +3369,7 @@ TEST_F(HttpNetworkTransactionTest, RecycleDeadSSLSocket) { ASSERT_TRUE(response->headers != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); + EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); std::string response_data; rv = ReadTransaction(trans.get(), &response_data); @@ -3372,7 +3397,7 @@ TEST_F(HttpNetworkTransactionTest, RecycleDeadSSLSocket) { ASSERT_TRUE(response->headers != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); + EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); rv = ReadTransaction(trans.get(), &response_data); EXPECT_EQ(OK, rv); @@ -3428,7 +3453,7 @@ TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) { std::string status_line = response->headers->GetStatusLine(); EXPECT_EQ("HTTP/1.1 204 No Content", status_line); - EXPECT_EQ(0, session->tcp_socket_pool()->IdleSocketCount()); + EXPECT_EQ(0, session->transport_socket_pool()->IdleSocketCount()); std::string response_data; rv = ReadTransaction(trans.get(), &response_data); @@ -3440,7 +3465,7 @@ TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) { MessageLoop::current()->RunAllPending(); // We now check to make sure the socket was added back to the pool. - EXPECT_EQ(1, session->tcp_socket_pool()->IdleSocketCount()); + EXPECT_EQ(1, session->transport_socket_pool()->IdleSocketCount()); } TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) { @@ -5439,9 +5464,8 @@ struct GroupNameTest { }; scoped_refptr<HttpNetworkSession> SetupSessionForGroupNameTests( - const std::string& proxy_server) { - SessionDependencies session_deps(ProxyService::CreateFixed(proxy_server)); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + SessionDependencies* session_deps) { + scoped_refptr<HttpNetworkSession> session(CreateSession(session_deps)); HttpAlternateProtocols* alternate_protocols = session->mutable_alternate_protocols(); @@ -5507,13 +5531,15 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) { HttpStreamFactory::set_use_alternate_protocols(true); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { + SessionDependencies session_deps( + ProxyService::CreateFixed(tests[i].proxy_server)); scoped_refptr<HttpNetworkSession> session( - SetupSessionForGroupNameTests(tests[i].proxy_server)); + SetupSessionForGroupNameTests(&session_deps)); HttpNetworkSessionPeer peer(session); - CaptureGroupNameTCPSocketPool* tcp_conn_pool = - new CaptureGroupNameTCPSocketPool(NULL, NULL); - peer.SetTCPSocketPool(tcp_conn_pool); + CaptureGroupNameTransportSocketPool* transport_conn_pool = + new CaptureGroupNameTransportSocketPool(NULL, NULL); + peer.SetTransportSocketPool(transport_conn_pool); CaptureGroupNameSSLSocketPool* ssl_conn_pool = new CaptureGroupNameSSLSocketPool(NULL, NULL); peer.SetSSLSocketPool(ssl_conn_pool); @@ -5525,7 +5551,7 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForDirectConnections) { ssl_conn_pool->last_group_name_received()); else EXPECT_EQ(tests[i].expected_group_name, - tcp_conn_pool->last_group_name_received()); + transport_conn_pool->last_group_name_received()); } HttpStreamFactory::set_use_alternate_protocols(false); @@ -5559,8 +5585,10 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) { HttpStreamFactory::set_use_alternate_protocols(true); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { + SessionDependencies session_deps( + ProxyService::CreateFixed(tests[i].proxy_server)); scoped_refptr<HttpNetworkSession> session( - SetupSessionForGroupNameTests(tests[i].proxy_server)); + SetupSessionForGroupNameTests(&session_deps)); HttpNetworkSessionPeer peer(session); @@ -5625,8 +5653,11 @@ TEST_F(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) { HttpStreamFactory::set_use_alternate_protocols(true); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { + SessionDependencies session_deps( + ProxyService::CreateFixed(tests[i].proxy_server)); scoped_refptr<HttpNetworkSession> session( - SetupSessionForGroupNameTests(tests[i].proxy_server)); + SetupSessionForGroupNameTests(&session_deps)); + HttpNetworkSessionPeer peer(session); HostPortPair proxy_host("socks_proxy", 1080); @@ -6437,7 +6468,6 @@ TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) { EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); EXPECT_FALSE(response->was_fetched_via_spdy); EXPECT_FALSE(response->was_npn_negotiated); - EXPECT_FALSE(response->was_alternate_protocol_available); std::string response_data; ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); @@ -6455,7 +6485,7 @@ TEST_F(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) { HttpStreamFactory::set_next_protos(""); } -TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) { +TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocolAndFallback) { HttpStreamFactory::set_use_alternate_protocols(true); SessionDependencies session_deps; @@ -6478,11 +6508,6 @@ TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) { data_reads, arraysize(data_reads), NULL, 0); session_deps.socket_factory.AddSocketDataProvider(&second_data); - // TODO(willchan): Delete this extra data provider. It's necessary due to a - // ClientSocketPoolBaseHelper bug that starts up too many ConnectJobs: - // http://crbug.com/37454. - session_deps.socket_factory.AddSocketDataProvider(&second_data); - TestCompletionCallback callback; scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); @@ -6517,60 +6542,7 @@ TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocol) { HttpStreamFactory::set_use_alternate_protocols(false); } -// TODO(willchan): Redo this test to use TLS/NPN=>SPDY. Currently, the code -// says that it does SPDY, but it just does the TLS handshake, but the NPN -// response does not indicate SPDY, so we just do standard HTTPS over the port. -// We should add code such that we don't fallback to HTTPS, but fallback to HTTP -// on the original port. -// TEST_F(HttpNetworkTransactionTest, UseAlternateProtocol) { -// SessionDependencies session_deps; -// -// HttpRequestInfo request; -// request.method = "GET"; -// request.url = GURL("http://www.google.com/"); -// request.load_flags = 0; -// -// MockRead data_reads[] = { -// MockRead("HTTP/1.1 200 OK\r\n\r\n"), -// MockRead("hello world"), -// MockRead(true, OK), -// }; -// StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); -// session_deps.socket_factory.AddSocketDataProvider(&data); -// -// SSLSocketDataProvider ssl(true, OK); -// session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); -// -// TestCompletionCallback callback; -// -// scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); -// -// HostPortPair http_host_port_pair; -// http_host_port_pair.host = "www.google.com"; -// http_host_port_pair.port = 80; -// HttpAlternateProtocols* alternate_protocols = -// session->mutable_alternate_protocols(); -// alternate_protocols->SetAlternateProtocolFor( -// http_host_port_pair, 1234 /* port is ignored */, -// HttpAlternateProtocols::NPN_SPDY_1); -// -// scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); -// -// int rv = trans->Start(&request, &callback, BoundNetLog()); -// EXPECT_EQ(ERR_IO_PENDING, rv); -// EXPECT_EQ(OK, callback.WaitForResult()); -// -// const HttpResponseInfo* response = trans->GetResponseInfo(); -// ASSERT_TRUE(response != NULL); -// ASSERT_TRUE(response->headers != NULL); -// EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); -// -// std::string response_data; -// ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); -// EXPECT_EQ("hello world", response_data); -// } - -TEST_F(HttpNetworkTransactionTest, FailNpnSpdyAndFallback) { +TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) { HttpStreamFactory::set_use_alternate_protocols(true); HttpStreamFactory::set_next_protos(kExpectedNPNString); SessionDependencies session_deps; @@ -6580,33 +6552,53 @@ TEST_F(HttpNetworkTransactionTest, FailNpnSpdyAndFallback) { request.url = GURL("http://www.google.com/"); request.load_flags = 0; - StaticSocketDataProvider first_tcp_connect; - session_deps.socket_factory.AddSocketDataProvider(&first_tcp_connect); - - SSLSocketDataProvider ssl(true, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n\r\n"), + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead(kAlternateProtocolHttpHeader), MockRead("hello world"), MockRead(true, OK), }; - StaticSocketDataProvider fallback_data( + + StaticSocketDataProvider first_transaction( data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&fallback_data); + session_deps.socket_factory.AddSocketDataProvider(&first_transaction); - TestCompletionCallback callback; + SSLSocketDataProvider ssl(true, OK); + ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; + ssl.next_proto = "spdy/2"; + ssl.was_npn_negotiated = true; + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); + MockWrite spdy_writes[] = { CreateMockWrite(*req) }; - HostPortPair http_host_port_pair("www.google.com", 80); - HttpAlternateProtocols* alternate_protocols = - session->mutable_alternate_protocols(); - alternate_protocols->SetAlternateProtocolFor( - http_host_port_pair, 1234 /* port is ignored */, - HttpAlternateProtocols::NPN_SPDY_2); + scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); + scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); + MockRead spdy_reads[] = { + CreateMockRead(*resp), + CreateMockRead(*data), + MockRead(true, 0, 0), + }; - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); + scoped_refptr<DelayedSocketData> spdy_data( + new DelayedSocketData( + 1, // wait for one write to finish before reading. + spdy_reads, arraysize(spdy_reads), + spdy_writes, arraysize(spdy_writes))); + session_deps.socket_factory.AddSocketDataProvider(spdy_data); + + MockConnect never_finishing_connect(false, ERR_IO_PENDING); + StaticSocketDataProvider hanging_non_alternate_protocol_socket( + NULL, 0, NULL, 0); + hanging_non_alternate_protocol_socket.set_connect_data( + never_finishing_connect); + session_deps.socket_factory.AddSocketDataProvider( + &hanging_non_alternate_protocol_socket); + + TestCompletionCallback callback; + + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); int rv = trans->Start(&request, &callback, BoundNetLog()); EXPECT_EQ(ERR_IO_PENDING, rv); @@ -6620,11 +6612,28 @@ TEST_F(HttpNetworkTransactionTest, FailNpnSpdyAndFallback) { std::string response_data; ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); EXPECT_EQ("hello world", response_data); + + trans.reset(new HttpNetworkTransaction(session)); + + rv = trans->Start(&request, &callback, BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback.WaitForResult()); + + response = trans->GetResponseInfo(); + ASSERT_TRUE(response != NULL); + ASSERT_TRUE(response->headers != NULL); + EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); + EXPECT_TRUE(response->was_fetched_via_spdy); + EXPECT_TRUE(response->was_npn_negotiated); + + ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); + EXPECT_EQ("hello!", response_data); + HttpStreamFactory::set_next_protos(""); HttpStreamFactory::set_use_alternate_protocols(false); } -TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) { +TEST_F(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) { HttpStreamFactory::set_use_alternate_protocols(true); HttpStreamFactory::set_next_protos(kExpectedNPNString); SessionDependencies session_deps; @@ -6643,32 +6652,143 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) { StaticSocketDataProvider first_transaction( data_reads, arraysize(data_reads), NULL, 0); + // Socket 1 is the HTTP transaction with the Alternate-Protocol header. session_deps.socket_factory.AddSocketDataProvider(&first_transaction); + MockConnect never_finishing_connect(false, ERR_IO_PENDING); + StaticSocketDataProvider hanging_socket( + NULL, 0, NULL, 0); + hanging_socket.set_connect_data(never_finishing_connect); + // Socket 2 and 3 are the hanging Alternate-Protocol and + // non-Alternate-Protocol jobs from the 2nd transaction. + session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); + session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); + SSLSocketDataProvider ssl(true, OK); ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; ssl.next_proto = "spdy/2"; ssl.was_npn_negotiated = true; session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - scoped_ptr<spdy::SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite spdy_writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<spdy::SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); + scoped_ptr<spdy::SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); + scoped_ptr<spdy::SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); + MockWrite spdy_writes[] = { + CreateMockWrite(*req1), + CreateMockWrite(*req2), + }; + scoped_ptr<spdy::SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1)); + scoped_ptr<spdy::SpdyFrame> data1(ConstructSpdyBodyFrame(1, true)); + scoped_ptr<spdy::SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); + scoped_ptr<spdy::SpdyFrame> data2(ConstructSpdyBodyFrame(3, true)); MockRead spdy_reads[] = { - CreateMockRead(*resp), - CreateMockRead(*data), + CreateMockRead(*resp1), + CreateMockRead(*data1), + CreateMockRead(*resp2), + CreateMockRead(*data2), MockRead(true, 0, 0), }; scoped_refptr<DelayedSocketData> spdy_data( new DelayedSocketData( - 1, // wait for one write to finish before reading. + 2, // wait for writes to finish before reading. spdy_reads, arraysize(spdy_reads), spdy_writes, arraysize(spdy_writes))); + // Socket 4 is the successful Alternate-Protocol for transaction 3. session_deps.socket_factory.AddSocketDataProvider(spdy_data); + // Socket 5 is the unsuccessful non-Alternate-Protocol for transaction 3. + session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); + + scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); + TestCompletionCallback callback1; + HttpNetworkTransaction trans1(session); + + int rv = trans1.Start(&request, &callback1, BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_EQ(OK, callback1.WaitForResult()); + + const HttpResponseInfo* response = trans1.GetResponseInfo(); + ASSERT_TRUE(response != NULL); + ASSERT_TRUE(response->headers != NULL); + EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); + + std::string response_data; + ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); + EXPECT_EQ("hello world", response_data); + + TestCompletionCallback callback2; + HttpNetworkTransaction trans2(session); + rv = trans2.Start(&request, &callback2, BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + TestCompletionCallback callback3; + HttpNetworkTransaction trans3(session); + rv = trans3.Start(&request, &callback3, BoundNetLog()); + EXPECT_EQ(ERR_IO_PENDING, rv); + + EXPECT_EQ(OK, callback2.WaitForResult()); + EXPECT_EQ(OK, callback3.WaitForResult()); + + response = trans2.GetResponseInfo(); + ASSERT_TRUE(response != NULL); + ASSERT_TRUE(response->headers != NULL); + EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); + EXPECT_TRUE(response->was_fetched_via_spdy); + EXPECT_TRUE(response->was_npn_negotiated); + ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); + EXPECT_EQ("hello!", response_data); + + response = trans3.GetResponseInfo(); + ASSERT_TRUE(response != NULL); + ASSERT_TRUE(response->headers != NULL); + EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); + EXPECT_TRUE(response->was_fetched_via_spdy); + EXPECT_TRUE(response->was_npn_negotiated); + ASSERT_EQ(OK, ReadTransaction(&trans3, &response_data)); + EXPECT_EQ("hello!", response_data); + + HttpStreamFactory::set_next_protos(""); + HttpStreamFactory::set_use_alternate_protocols(false); +} + +TEST_F(HttpNetworkTransactionTest, StallAlternateProtocolForNpnSpdy) { + HttpStreamFactory::set_use_alternate_protocols(true); + HttpStreamFactory::set_next_protos(kExpectedNPNString); + SessionDependencies session_deps; + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + MockRead data_reads[] = { + MockRead("HTTP/1.1 200 OK\r\n"), + MockRead(kAlternateProtocolHttpHeader), + MockRead("hello world"), + MockRead(true, OK), + }; + + StaticSocketDataProvider first_transaction( + data_reads, arraysize(data_reads), NULL, 0); + session_deps.socket_factory.AddSocketDataProvider(&first_transaction); + + SSLSocketDataProvider ssl(true, OK); + ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; + ssl.next_proto = "spdy/2"; + ssl.was_npn_negotiated = true; + session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); + + MockConnect never_finishing_connect(false, ERR_IO_PENDING); + StaticSocketDataProvider hanging_alternate_protocol_socket( + NULL, 0, NULL, 0); + hanging_alternate_protocol_socket.set_connect_data( + never_finishing_connect); + session_deps.socket_factory.AddSocketDataProvider( + &hanging_alternate_protocol_socket); + + // 2nd request is just a copy of the first one, over HTTP again. + session_deps.socket_factory.AddSocketDataProvider(&first_transaction); + TestCompletionCallback callback; scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); @@ -6697,12 +6817,11 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) { ASSERT_TRUE(response != NULL); ASSERT_TRUE(response->headers != NULL); EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_TRUE(response->was_fetched_via_spdy); - EXPECT_TRUE(response->was_npn_negotiated); - EXPECT_TRUE(response->was_alternate_protocol_available); + EXPECT_FALSE(response->was_fetched_via_spdy); + EXPECT_FALSE(response->was_npn_negotiated); ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello!", response_data); + EXPECT_EQ("hello world", response_data); HttpStreamFactory::set_next_protos(""); HttpStreamFactory::set_use_alternate_protocols(false); @@ -6807,6 +6926,14 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForTunneledNpnSpdy) { spdy_writes, arraysize(spdy_writes))); session_deps.socket_factory.AddSocketDataProvider(spdy_data); + MockConnect never_finishing_connect(false, ERR_IO_PENDING); + StaticSocketDataProvider hanging_non_alternate_protocol_socket( + NULL, 0, NULL, 0); + hanging_non_alternate_protocol_socket.set_connect_data( + never_finishing_connect); + session_deps.socket_factory.AddSocketDataProvider( + &hanging_non_alternate_protocol_socket); + TestCompletionCallback callback; scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); @@ -6842,7 +6969,7 @@ TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForTunneledNpnSpdy) { ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); EXPECT_EQ("hello!", response_data); - ASSERT_EQ(2u, capturing_proxy_resolver->resolved().size()); + ASSERT_EQ(3u, capturing_proxy_resolver->resolved().size()); EXPECT_EQ("http://www.google.com/", capturing_proxy_resolver->resolved()[0].spec()); EXPECT_EQ("https://www.google.com/", @@ -6924,13 +7051,16 @@ TEST_F(HttpNetworkTransactionTest, HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); scoped_refptr<SpdySession> spdy_session = session->spdy_session_pool()->Get(pair, BoundNetLog()); - scoped_refptr<TCPSocketParams> tcp_params( - new TCPSocketParams("www.google.com", 443, MEDIUM, GURL(), false)); + scoped_refptr<TransportSocketParams> transport_params( + new TransportSocketParams(host_port_pair, MEDIUM, GURL(), false, false)); scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); EXPECT_EQ(ERR_IO_PENDING, - connection->Init(host_port_pair.ToString(),tcp_params, LOWEST, - &callback, session->tcp_socket_pool(), + connection->Init(host_port_pair.ToString(), + transport_params, + LOWEST, + &callback, + session->transport_socket_pool(), BoundNetLog())); EXPECT_EQ(OK, callback.WaitForResult()); @@ -6958,7 +7088,6 @@ TEST_F(HttpNetworkTransactionTest, EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); EXPECT_TRUE(response->was_fetched_via_spdy); EXPECT_TRUE(response->was_npn_negotiated); - EXPECT_TRUE(response->was_alternate_protocol_available); ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); EXPECT_EQ("hello!", response_data); @@ -7412,15 +7541,15 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) { // to validate that the TCP socket is not released to the pool between // each round of multi-round authentication. HttpNetworkSessionPeer session_peer(session); - ClientSocketPoolHistograms tcp_pool_histograms("SmallTCP"); - TCPClientSocketPool* tcp_pool = new TCPClientSocketPool( + ClientSocketPoolHistograms transport_pool_histograms("SmallTCP"); + TransportClientSocketPool* transport_pool = new TransportClientSocketPool( 50, // Max sockets for pool 1, // Max sockets per group - &tcp_pool_histograms, + &transport_pool_histograms, session_deps.host_resolver.get(), &session_deps.socket_factory, session_deps.net_log); - session_peer.SetTCPSocketPool(tcp_pool); + session_peer.SetTransportSocketPool(transport_pool); scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); TestCompletionCallback callback; @@ -7486,7 +7615,7 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) { response = trans->GetResponseInfo(); ASSERT_FALSE(response == NULL); EXPECT_FALSE(response->auth_challenge.get() == NULL); - EXPECT_EQ(0, tcp_pool->IdleSocketCountInGroup(kSocketGroup)); + EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); // In between rounds, another request comes in for the same domain. // It should not be able to grab the TCP socket that trans has already @@ -7509,7 +7638,7 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) { response = trans->GetResponseInfo(); ASSERT_FALSE(response == NULL); EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(0, tcp_pool->IdleSocketCountInGroup(kSocketGroup)); + EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); // Third round of authentication. auth_handler->SetGenerateExpectation(false, OK); @@ -7520,7 +7649,7 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) { response = trans->GetResponseInfo(); ASSERT_FALSE(response == NULL); EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(0, tcp_pool->IdleSocketCountInGroup(kSocketGroup)); + EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); // Fourth round of authentication, which completes successfully. auth_handler->SetGenerateExpectation(false, OK); @@ -7531,7 +7660,7 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) { response = trans->GetResponseInfo(); ASSERT_FALSE(response == NULL); EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(0, tcp_pool->IdleSocketCountInGroup(kSocketGroup)); + EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); // Read the body since the fourth round was successful. This will also // release the socket back to the pool. @@ -7544,7 +7673,7 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) { EXPECT_EQ(0, rv); // There are still 0 idle sockets, since the trans_compete transaction // will be handed it immediately after trans releases it to the group. - EXPECT_EQ(0, tcp_pool->IdleSocketCountInGroup(kSocketGroup)); + EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); // The competing request can now finish. Wait for the headers and then // read the body. @@ -7558,7 +7687,7 @@ TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) { EXPECT_EQ(0, rv); // Finally, the socket is released to the group. - EXPECT_EQ(1, tcp_pool->IdleSocketCountInGroup(kSocketGroup)); + EXPECT_EQ(1, transport_pool->IdleSocketCountInGroup(kSocketGroup)); } class TLSDecompressionFailureSocketDataProvider : public SocketDataProvider { @@ -7729,7 +7858,6 @@ TEST_F(HttpNetworkTransactionTest, NpnWithHttpOverSSL) { EXPECT_FALSE(response->was_fetched_via_spdy); EXPECT_TRUE(response->was_npn_negotiated); - EXPECT_FALSE(response->was_alternate_protocol_available); HttpStreamFactory::set_next_protos(""); HttpStreamFactory::set_use_alternate_protocols(false); @@ -7885,9 +8013,17 @@ TEST_F(HttpNetworkTransactionTest, SpdyAlternateProtocolThroughProxy) { ssl.next_proto = "spdy/2"; ssl.was_npn_negotiated = true; + MockConnect never_finishing_connect(false, ERR_IO_PENDING); + StaticSocketDataProvider hanging_non_alternate_protocol_socket( + NULL, 0, NULL, 0); + hanging_non_alternate_protocol_socket.set_connect_data( + never_finishing_connect); + session_deps.socket_factory.AddSocketDataProvider(&data_1); session_deps.socket_factory.AddSocketDataProvider(data_2.get()); session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); + session_deps.socket_factory.AddSocketDataProvider( + &hanging_non_alternate_protocol_socket); scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); // First round should work and provide the Alternate-Protocol state. @@ -8167,15 +8303,15 @@ TEST_F(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) { HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); scoped_refptr<SpdySession> spdy_session = session->spdy_session_pool()->Get(pair, BoundNetLog()); - scoped_refptr<TCPSocketParams> tcp_params( - new TCPSocketParams("www.google.com", 443, MEDIUM, GURL(), false)); + scoped_refptr<TransportSocketParams> transport_params( + new TransportSocketParams(host_port_pair, MEDIUM, GURL(), false, false)); TestCompletionCallback callback; scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); EXPECT_EQ(ERR_IO_PENDING, - connection->Init(host_port_pair.ToString(), tcp_params, LOWEST, - &callback, session->tcp_socket_pool(), - BoundNetLog())); + connection->Init(host_port_pair.ToString(), transport_params, + LOWEST, &callback, + session->transport_socket_pool(), BoundNetLog())); EXPECT_EQ(OK, callback.WaitForResult()); spdy_session->InitializeWithSocket(connection.release(), false, OK); @@ -8236,56 +8372,6 @@ TEST_F(HttpNetworkTransactionTest, SSLWriteCertError) { } } -// Test that the transaction is restarted in the event of an NPN misprediction. -TEST_F(HttpNetworkTransactionTest, NPNMispredict) { - net::HttpRequestInfo request_info; - request_info.url = GURL("https://www.example.com/"); - request_info.method = "GET"; - request_info.load_flags = net::LOAD_NORMAL; - - SessionDependencies session_deps; - - SSLSocketDataProvider ssl_data1(true /* async */, OK); - SSLSocketDataProvider ssl_data2(true /* async */, OK); - - net::MockWrite data1_writes[] = { - net::MockWrite(true /* async */, ERR_SSL_SNAP_START_NPN_MISPREDICTION), - }; - net::MockRead data2_reads[] = { - net::MockRead("HTTP/1.0 200 OK\r\n\r\n"), - net::MockRead("hello world"), - net::MockRead(false, net::OK), - }; - net::MockWrite data2_writes[] = { - net::MockWrite("GET / HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - net::StaticSocketDataProvider data1( - NULL, 0, data1_writes, arraysize(data1_writes)); - net::StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), - data2_writes, arraysize(data2_writes)); - - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); - - TestCompletionCallback callback; - int rv = trans->Start(&request_info, &callback, net::BoundNetLog()); - if (rv == net::ERR_IO_PENDING) - rv = callback.WaitForResult(); - ASSERT_EQ(OK, rv); - - std::string contents; - rv = ReadTransaction(trans.get(), &contents); - EXPECT_EQ(net::OK, rv); - EXPECT_EQ("hello world", contents); -} - // Ensure that a client certificate is removed from the SSL client auth // cache when: // 1) No proxy is involved. diff --git a/net/http/http_proxy_client_socket.cc b/net/http/http_proxy_client_socket.cc index 4932da0..6cf6b78 100644 --- a/net/http/http_proxy_client_socket.cc +++ b/net/http/http_proxy_client_socket.cc @@ -212,6 +212,10 @@ int HttpProxyClientSocket::GetPeerAddress(AddressList* address) const { return transport_->socket()->GetPeerAddress(address); } +int HttpProxyClientSocket::GetLocalAddress(IPEndPoint* address) const { + return transport_->socket()->GetLocalAddress(address); +} + int HttpProxyClientSocket::PrepareForAuthRestart() { if (!response_.headers.get()) return ERR_CONNECTION_RESET; diff --git a/net/http/http_proxy_client_socket.h b/net/http/http_proxy_client_socket.h index e4276b7..fe2069b 100644 --- a/net/http/http_proxy_client_socket.h +++ b/net/http/http_proxy_client_socket.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,7 +9,7 @@ #include <string> #include "base/basictypes.h" -#include "base/ref_counted.h" +#include "base/memory/ref_counted.h" #include "net/base/completion_callback.h" #include "net/base/host_port_pair.h" #include "net/base/net_log.h" @@ -89,6 +89,7 @@ class HttpProxyClientSocket : public ProxyClientSocket { virtual bool SetReceiveBufferSize(int32 size); virtual bool SetSendBufferSize(int32 size); virtual int GetPeerAddress(AddressList* address) const; + virtual int GetLocalAddress(IPEndPoint* address) const; private: enum State { diff --git a/net/http/http_proxy_client_socket_pool.cc b/net/http/http_proxy_client_socket_pool.cc index 18b1c6d..78b9b6b 100644 --- a/net/http/http_proxy_client_socket_pool.cc +++ b/net/http/http_proxy_client_socket_pool.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -18,7 +18,7 @@ #include "net/socket/client_socket_pool_base.h" #include "net/socket/ssl_client_socket.h" #include "net/socket/ssl_client_socket_pool.h" -#include "net/socket/tcp_client_socket_pool.h" +#include "net/socket/transport_client_socket_pool.h" #include "net/spdy/spdy_proxy_client_socket.h" #include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session_pool.h" @@ -28,7 +28,7 @@ namespace net { HttpProxySocketParams::HttpProxySocketParams( - const scoped_refptr<TCPSocketParams>& tcp_params, + const scoped_refptr<TransportSocketParams>& transport_params, const scoped_refptr<SSLSocketParams>& ssl_params, const GURL& request_url, const std::string& user_agent, @@ -37,7 +37,7 @@ HttpProxySocketParams::HttpProxySocketParams( HttpAuthHandlerFactory* http_auth_handler_factory, SpdySessionPool* spdy_session_pool, bool tunnel) - : tcp_params_(tcp_params), + : transport_params_(transport_params), ssl_params_(ssl_params), spdy_session_pool_(spdy_session_pool), request_url_(request_url), @@ -46,6 +46,7 @@ HttpProxySocketParams::HttpProxySocketParams( http_auth_cache_(tunnel ? http_auth_cache : NULL), http_auth_handler_factory_(tunnel ? http_auth_handler_factory : NULL), tunnel_(tunnel) { +<<<<<<< HEAD DCHECK((tcp_params == NULL && ssl_params != NULL) || (tcp_params != NULL && ssl_params == NULL)); #ifdef ANDROID @@ -54,13 +55,21 @@ HttpProxySocketParams::HttpProxySocketParams( else ignore_limits_ = ssl_params->ignore_limits(); #endif +======= + DCHECK((transport_params == NULL && ssl_params != NULL) || + (transport_params != NULL && ssl_params == NULL)); + if (transport_params_) + ignore_limits_ = transport_params->ignore_limits(); + else + ignore_limits_ = ssl_params->ignore_limits(); +>>>>>>> chromium.org at r12.0.742.93 } const HostResolver::RequestInfo& HttpProxySocketParams::destination() const { - if (tcp_params_ == NULL) - return ssl_params_->tcp_params()->destination(); + if (transport_params_ == NULL) + return ssl_params_->transport_params()->destination(); else - return tcp_params_->destination(); + return transport_params_->destination(); } HttpProxySocketParams::~HttpProxySocketParams() {} @@ -73,7 +82,7 @@ HttpProxyConnectJob::HttpProxyConnectJob( const std::string& group_name, const scoped_refptr<HttpProxySocketParams>& params, const base::TimeDelta& timeout_duration, - TCPClientSocketPool* tcp_pool, + TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, HostResolver* host_resolver, Delegate* delegate, @@ -81,7 +90,7 @@ HttpProxyConnectJob::HttpProxyConnectJob( : ConnectJob(group_name, timeout_duration, delegate, BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)), params_(params), - tcp_pool_(tcp_pool), + transport_pool_(transport_pool), ssl_pool_(ssl_pool), resolver_(host_resolver), ALLOW_THIS_IN_INITIALIZER_LIST( @@ -132,10 +141,10 @@ int HttpProxyConnectJob::DoLoop(int result) { switch (state) { case STATE_TCP_CONNECT: DCHECK_EQ(OK, rv); - rv = DoTCPConnect(); + rv = DoTransportConnect(); break; case STATE_TCP_CONNECT_COMPLETE: - rv = DoTCPConnectComplete(rv); + rv = DoTransportConnectComplete(rv); break; case STATE_SSL_CONNECT: DCHECK_EQ(OK, rv); @@ -168,16 +177,19 @@ int HttpProxyConnectJob::DoLoop(int result) { return rv; } -int HttpProxyConnectJob::DoTCPConnect() { +int HttpProxyConnectJob::DoTransportConnect() { next_state_ = STATE_TCP_CONNECT_COMPLETE; transport_socket_handle_.reset(new ClientSocketHandle()); return transport_socket_handle_->Init( - group_name(), params_->tcp_params(), - params_->tcp_params()->destination().priority(), &callback_, tcp_pool_, + group_name(), + params_->transport_params(), + params_->transport_params()->destination().priority(), + &callback_, + transport_pool_, net_log()); } -int HttpProxyConnectJob::DoTCPConnectComplete(int result) { +int HttpProxyConnectJob::DoTransportConnectComplete(int result) { if (result != OK) return ERR_PROXY_CONNECTION_FAILED; @@ -205,7 +217,7 @@ int HttpProxyConnectJob::DoSSLConnect() { transport_socket_handle_.reset(new ClientSocketHandle()); return transport_socket_handle_->Init( group_name(), params_->ssl_params(), - params_->ssl_params()->tcp_params()->destination().priority(), + params_->ssl_params()->transport_params()->destination().priority(), &callback_, ssl_pool_, net_log()); } @@ -343,7 +355,7 @@ int HttpProxyConnectJob::DoSpdyProxyCreateStreamComplete(int result) { } int HttpProxyConnectJob::ConnectInternal() { - if (params_->tcp_params()) + if (params_->transport_params()) next_state_ = STATE_TCP_CONNECT; else next_state_ = STATE_SSL_CONNECT; @@ -352,17 +364,17 @@ int HttpProxyConnectJob::ConnectInternal() { HttpProxyClientSocketPool:: HttpProxyConnectJobFactory::HttpProxyConnectJobFactory( - TCPClientSocketPool* tcp_pool, + TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, HostResolver* host_resolver, NetLog* net_log) - : tcp_pool_(tcp_pool), + : transport_pool_(transport_pool), ssl_pool_(ssl_pool), host_resolver_(host_resolver), net_log_(net_log) { base::TimeDelta max_pool_timeout = base::TimeDelta(); - if (tcp_pool_) - max_pool_timeout = tcp_pool_->ConnectionTimeout(); + if (transport_pool_) + max_pool_timeout = transport_pool_->ConnectionTimeout(); if (ssl_pool_) max_pool_timeout = std::max(max_pool_timeout, ssl_pool_->ConnectionTimeout()); @@ -376,9 +388,14 @@ HttpProxyClientSocketPool::HttpProxyConnectJobFactory::NewConnectJob( const std::string& group_name, const PoolBase::Request& request, ConnectJob::Delegate* delegate) const { - return new HttpProxyConnectJob(group_name, request.params(), - ConnectionTimeout(), tcp_pool_, ssl_pool_, - host_resolver_, delegate, net_log_); + return new HttpProxyConnectJob(group_name, + request.params(), + ConnectionTimeout(), + transport_pool_, + ssl_pool_, + host_resolver_, + delegate, + net_log_); } HttpProxyClientSocketPool::HttpProxyClientSocketPool( @@ -386,16 +403,18 @@ HttpProxyClientSocketPool::HttpProxyClientSocketPool( int max_sockets_per_group, ClientSocketPoolHistograms* histograms, HostResolver* host_resolver, - TCPClientSocketPool* tcp_pool, + TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, NetLog* net_log) - : tcp_pool_(tcp_pool), + : transport_pool_(transport_pool), ssl_pool_(ssl_pool), base_(max_sockets, max_sockets_per_group, histograms, base::TimeDelta::FromSeconds( ClientSocketPool::unused_idle_socket_timeout()), base::TimeDelta::FromSeconds(kUsedIdleSocketTimeout), - new HttpProxyConnectJobFactory(tcp_pool, ssl_pool, host_resolver, + new HttpProxyConnectJobFactory(transport_pool, + ssl_pool, + host_resolver, net_log)) {} HttpProxyClientSocketPool::~HttpProxyClientSocketPool() {} @@ -464,10 +483,10 @@ DictionaryValue* HttpProxyClientSocketPool::GetInfoAsValue( DictionaryValue* dict = base_.GetInfoAsValue(name, type); if (include_nested_pools) { ListValue* list = new ListValue(); - if (tcp_pool_) { - list->Append(tcp_pool_->GetInfoAsValue("tcp_socket_pool", - "tcp_socket_pool", - true)); + if (transport_pool_) { + list->Append(transport_pool_->GetInfoAsValue("transport_socket_pool", + "transport_socket_pool", + true)); } if (ssl_pool_) { list->Append(ssl_pool_->GetInfoAsValue("ssl_socket_pool", diff --git a/net/http/http_proxy_client_socket_pool.h b/net/http/http_proxy_client_socket_pool.h index bf9b4c2..2f8b6fb 100644 --- a/net/http/http_proxy_client_socket_pool.h +++ b/net/http/http_proxy_client_socket_pool.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,8 +9,8 @@ #include <string> #include "base/basictypes.h" -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/time.h" #include "net/base/host_port_pair.h" #include "net/http/http_auth.h" @@ -29,27 +29,28 @@ class SSLClientSocketPool; class SSLSocketParams; class SpdySessionPool; class SpdyStream; -class TCPClientSocketPool; -class TCPSocketParams; +class TransportClientSocketPool; +class TransportSocketParams; // HttpProxySocketParams only needs the socket params for one of the proxy // types. The other param must be NULL. When using an HTTP Proxy, -// |tcp_params| must be set. When using an HTTPS Proxy, |ssl_params| +// |transport_params| must be set. When using an HTTPS Proxy, |ssl_params| // must be set. class HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> { public: - HttpProxySocketParams(const scoped_refptr<TCPSocketParams>& tcp_params, - const scoped_refptr<SSLSocketParams>& ssl_params, - const GURL& request_url, - const std::string& user_agent, - HostPortPair endpoint, - HttpAuthCache* http_auth_cache, - HttpAuthHandlerFactory* http_auth_handler_factory, - SpdySessionPool* spdy_session_pool, - bool tunnel); - - const scoped_refptr<TCPSocketParams>& tcp_params() const { - return tcp_params_; + HttpProxySocketParams( + const scoped_refptr<TransportSocketParams>& transport_params, + const scoped_refptr<SSLSocketParams>& ssl_params, + const GURL& request_url, + const std::string& user_agent, + HostPortPair endpoint, + HttpAuthCache* http_auth_cache, + HttpAuthHandlerFactory* http_auth_handler_factory, + SpdySessionPool* spdy_session_pool, + bool tunnel); + + const scoped_refptr<TransportSocketParams>& transport_params() const { + return transport_params_; } const scoped_refptr<SSLSocketParams>& ssl_params() const { return ssl_params_; @@ -66,15 +67,19 @@ class HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> { } const HostResolver::RequestInfo& destination() const; bool tunnel() const { return tunnel_; } +<<<<<<< HEAD #ifdef ANDROID bool ignore_limits() const { return ignore_limits_; } #endif +======= + bool ignore_limits() const { return ignore_limits_; } +>>>>>>> chromium.org at r12.0.742.93 private: friend class base::RefCounted<HttpProxySocketParams>; ~HttpProxySocketParams(); - const scoped_refptr<TCPSocketParams> tcp_params_; + const scoped_refptr<TransportSocketParams> transport_params_; const scoped_refptr<SSLSocketParams> ssl_params_; SpdySessionPool* spdy_session_pool_; const GURL request_url_; @@ -83,9 +88,13 @@ class HttpProxySocketParams : public base::RefCounted<HttpProxySocketParams> { HttpAuthCache* const http_auth_cache_; HttpAuthHandlerFactory* const http_auth_handler_factory_; const bool tunnel_; +<<<<<<< HEAD #ifdef ANDROID bool ignore_limits_; #endif +======= + bool ignore_limits_; +>>>>>>> chromium.org at r12.0.742.93 DISALLOW_COPY_AND_ASSIGN(HttpProxySocketParams); }; @@ -97,7 +106,7 @@ class HttpProxyConnectJob : public ConnectJob { HttpProxyConnectJob(const std::string& group_name, const scoped_refptr<HttpProxySocketParams>& params, const base::TimeDelta& timeout_duration, - TCPClientSocketPool* tcp_pool, + TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, HostResolver* host_resolver, Delegate* delegate, @@ -129,8 +138,8 @@ class HttpProxyConnectJob : public ConnectJob { int DoLoop(int result); // Connecting to HTTP Proxy - int DoTCPConnect(); - int DoTCPConnectComplete(int result); + int DoTransportConnect(); + int DoTransportConnectComplete(int result); // Connecting to HTTPS Proxy int DoSSLConnect(); int DoSSLConnectComplete(int result); @@ -151,7 +160,7 @@ class HttpProxyConnectJob : public ConnectJob { virtual int ConnectInternal(); scoped_refptr<HttpProxySocketParams> params_; - TCPClientSocketPool* const tcp_pool_; + TransportClientSocketPool* const transport_pool_; SSLClientSocketPool* const ssl_pool_; HostResolver* const resolver_; @@ -175,7 +184,7 @@ class HttpProxyClientSocketPool : public ClientSocketPool { int max_sockets_per_group, ClientSocketPoolHistograms* histograms, HostResolver* host_resolver, - TCPClientSocketPool* tcp_pool, + TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, NetLog* net_log); @@ -226,7 +235,7 @@ class HttpProxyClientSocketPool : public ClientSocketPool { class HttpProxyConnectJobFactory : public PoolBase::ConnectJobFactory { public: HttpProxyConnectJobFactory( - TCPClientSocketPool* tcp_pool, + TransportClientSocketPool* transport_pool, SSLClientSocketPool* ssl_pool, HostResolver* host_resolver, NetLog* net_log); @@ -239,7 +248,7 @@ class HttpProxyClientSocketPool : public ClientSocketPool { virtual base::TimeDelta ConnectionTimeout() const { return timeout_; } private: - TCPClientSocketPool* const tcp_pool_; + TransportClientSocketPool* const transport_pool_; SSLClientSocketPool* const ssl_pool_; HostResolver* const host_resolver_; NetLog* net_log_; @@ -248,7 +257,7 @@ class HttpProxyClientSocketPool : public ClientSocketPool { DISALLOW_COPY_AND_ASSIGN(HttpProxyConnectJobFactory); }; - TCPClientSocketPool* const tcp_pool_; + TransportClientSocketPool* const transport_pool_; SSLClientSocketPool* const ssl_pool_; PoolBase base_; diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc index 5830b3a..fb6bef0 100644 --- a/net/http/http_proxy_client_socket_pool_unittest.cc +++ b/net/http/http_proxy_client_socket_pool_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -48,13 +48,14 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam { protected: HttpProxyClientSocketPoolTest() : ssl_config_(), - ignored_tcp_socket_params_(new TCPSocketParams( - HostPortPair("proxy", 80), LOWEST, GURL(), false)), + ignored_transport_socket_params_(new TransportSocketParams( + HostPortPair("proxy", 80), LOWEST, GURL(), false, false)), ignored_ssl_socket_params_(new SSLSocketParams( - ignored_tcp_socket_params_, NULL, NULL, ProxyServer::SCHEME_DIRECT, - HostPortPair("www.google.com", 443), ssl_config_, 0, false, false)), + ignored_transport_socket_params_, NULL, NULL, + ProxyServer::SCHEME_DIRECT, HostPortPair("www.google.com", 443), + ssl_config_, 0, false, false)), tcp_histograms_("MockTCP"), - tcp_socket_pool_( + transport_socket_pool_( kMaxSockets, kMaxSocketsPerGroup, &tcp_histograms_, &socket_factory_), @@ -69,7 +70,7 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam { NULL /* dns_cert_checker */, NULL /* ssl_host_info_factory */, &socket_factory_, - &tcp_socket_pool_, + &transport_socket_pool_, NULL, NULL, ssl_config_service_.get(), @@ -83,7 +84,7 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam { pool_(kMaxSockets, kMaxSocketsPerGroup, &http_proxy_histograms_, NULL, - &tcp_socket_pool_, + &transport_socket_pool_, &ssl_socket_pool_, NULL) { } @@ -103,10 +104,10 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam { "/"); } - scoped_refptr<TCPSocketParams> GetTcpParams() { + scoped_refptr<TransportSocketParams> GetTcpParams() { if (GetParam() != HTTP) - return scoped_refptr<TCPSocketParams>(); - return ignored_tcp_socket_params_; + return scoped_refptr<TransportSocketParams>(); + return ignored_transport_socket_params_; } scoped_refptr<SSLSocketParams> GetSslParams() { @@ -189,11 +190,11 @@ class HttpProxyClientSocketPoolTest : public TestWithHttpParam { private: SSLConfig ssl_config_; - scoped_refptr<TCPSocketParams> ignored_tcp_socket_params_; + scoped_refptr<TransportSocketParams> ignored_transport_socket_params_; scoped_refptr<SSLSocketParams> ignored_ssl_socket_params_; ClientSocketPoolHistograms tcp_histograms_; DeterministicMockClientSocketFactory socket_factory_; - MockTCPClientSocketPool tcp_socket_pool_; + MockTransportClientSocketPool transport_socket_pool_; ClientSocketPoolHistograms ssl_histograms_; MockHostResolver host_resolver_; CertVerifier cert_verifier_; diff --git a/net/http/http_request_info.cc b/net/http/http_request_info.cc index 8ab3096..18c1b84 100644 --- a/net/http/http_request_info.cc +++ b/net/http/http_request_info.cc @@ -9,7 +9,8 @@ namespace net { HttpRequestInfo::HttpRequestInfo() : load_flags(0), priority(LOWEST), - motivation(NORMAL_MOTIVATION) { + motivation(NORMAL_MOTIVATION), + request_id(0) { } HttpRequestInfo::~HttpRequestInfo() {} diff --git a/net/http/http_request_info.h b/net/http/http_request_info.h index 7c73aa6..b906cf5 100644 --- a/net/http/http_request_info.h +++ b/net/http/http_request_info.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,7 +7,7 @@ #pragma once #include <string> -#include "base/ref_counted.h" +#include "base/memory/ref_counted.h" #include "googleurl/src/gurl.h" #include "net/base/request_priority.h" #include "net/base/upload_data.h" @@ -52,6 +52,10 @@ struct HttpRequestInfo { // The motivation behind this request. RequestMotivation motivation; + + // An optional globally unique identifier for this request for use by the + // consumer. 0 is invalid. + uint64 request_id; }; } // namespace net diff --git a/net/http/http_response_body_drainer.h b/net/http/http_response_body_drainer.h index 1aa4e93..7ee1d7c 100644 --- a/net/http/http_response_body_drainer.h +++ b/net/http/http_response_body_drainer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,8 +7,8 @@ #pragma once #include "base/basictypes.h" -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/timer.h" #include "net/base/completion_callback.h" #include "net/http/http_network_session.h" diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc index 5745865..1bdecea 100644 --- a/net/http/http_response_body_drainer_unittest.cc +++ b/net/http/http_response_body_drainer_unittest.cc @@ -74,42 +74,48 @@ class MockHttpStream : public HttpStream { // HttpStream implementation: virtual int InitializeStream(const HttpRequestInfo* request_info, const BoundNetLog& net_log, - CompletionCallback* callback) { + CompletionCallback* callback) OVERRIDE { return ERR_UNEXPECTED; } virtual int SendRequest(const HttpRequestHeaders& request_headers, UploadDataStream* request_body, HttpResponseInfo* response, - CompletionCallback* callback) { + CompletionCallback* callback) OVERRIDE { return ERR_UNEXPECTED; } - virtual uint64 GetUploadProgress() const { return 0; } - virtual int ReadResponseHeaders(CompletionCallback* callback) { + virtual uint64 GetUploadProgress() const OVERRIDE { return 0; } + virtual int ReadResponseHeaders(CompletionCallback* callback) OVERRIDE { return ERR_UNEXPECTED; } - virtual const HttpResponseInfo* GetResponseInfo() const { return NULL; } + virtual const HttpResponseInfo* GetResponseInfo() const OVERRIDE { + return NULL; + } - virtual bool CanFindEndOfResponse() const { return true; } - virtual bool IsMoreDataBuffered() const { return false; } - virtual bool IsConnectionReused() const { return false; } - virtual void SetConnectionReused() {} - virtual void GetSSLInfo(SSLInfo* ssl_info) {} - virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) {} + virtual bool CanFindEndOfResponse() const OVERRIDE { return true; } + virtual bool IsMoreDataBuffered() const OVERRIDE { return false; } + virtual bool IsConnectionReused() const OVERRIDE { return false; } + virtual void SetConnectionReused() OVERRIDE {} + virtual bool IsConnectionReusable() const OVERRIDE { return false; } + virtual void GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {} + virtual void GetSSLCertRequestInfo( + SSLCertRequestInfo* cert_request_info) OVERRIDE {} // Mocked API virtual int ReadResponseBody(IOBuffer* buf, int buf_len, - CompletionCallback* callback); - virtual void Close(bool not_reusable) { + CompletionCallback* callback) OVERRIDE; + virtual void Close(bool not_reusable) OVERRIDE { DCHECK(!closed_); closed_ = true; result_waiter_->set_result(not_reusable); } - virtual HttpStream* RenewStreamForAuth() { + virtual HttpStream* RenewStreamForAuth() OVERRIDE { return NULL; } - virtual bool IsResponseBodyComplete() const { return is_complete_; } + virtual bool IsResponseBodyComplete() const OVERRIDE { return is_complete_; } + + virtual bool IsSpdyHttpStream() const OVERRIDE { return false; } // Methods to tweak/observer mock behavior: void StallReadsForever() { stall_reads_forever_ = true; } diff --git a/net/http/http_response_headers.h b/net/http/http_response_headers.h index 3c2eae0..7187da5 100644 --- a/net/http/http_response_headers.h +++ b/net/http/http_response_headers.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,7 +11,7 @@ #include "base/basictypes.h" #include "base/hash_tables.h" -#include "base/ref_counted.h" +#include "base/memory/ref_counted.h" #include "net/http/http_version.h" class Pickle; diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc index 9b3444a..49090e0 100644 --- a/net/http/http_response_info.cc +++ b/net/http/http_response_info.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -22,7 +22,10 @@ namespace net { // serialized HttpResponseInfo. enum { // The version of the response info used when persisting response info. - RESPONSE_INFO_VERSION = 1, + RESPONSE_INFO_VERSION = 2, + + // The minimum version supported for deserializing response info. + RESPONSE_INFO_MINIMUM_VERSION = 1, // We reserve up to 8 bits for the version number. RESPONSE_INFO_VERSION_MASK = 0xFF, @@ -52,10 +55,6 @@ enum { // This bit is set if the request was fetched via an explicit proxy. RESPONSE_INFO_WAS_PROXY = 1 << 15, - // This bit is set if response could use alternate protocol. However, browser - // will ingore the alternate protocol if spdy is not enabled. - RESPONSE_INFO_WAS_ALTERNATE_PROTOCOL_AVAILABLE = 1 << 16, - // TODO(darin): Add other bits to indicate alternate request methods. // For now, we don't support storing those. }; @@ -64,7 +63,6 @@ HttpResponseInfo::HttpResponseInfo() : was_cached(false), was_fetched_via_spdy(false), was_npn_negotiated(false), - was_alternate_protocol_available(false), was_fetched_via_proxy(false) { } @@ -72,7 +70,6 @@ HttpResponseInfo::HttpResponseInfo(const HttpResponseInfo& rhs) : was_cached(rhs.was_cached), was_fetched_via_spdy(rhs.was_fetched_via_spdy), was_npn_negotiated(rhs.was_npn_negotiated), - was_alternate_protocol_available(rhs.was_alternate_protocol_available), was_fetched_via_proxy(rhs.was_fetched_via_proxy), socket_address(rhs.socket_address), request_time(rhs.request_time), @@ -92,7 +89,6 @@ HttpResponseInfo& HttpResponseInfo::operator=(const HttpResponseInfo& rhs) { was_cached = rhs.was_cached; was_fetched_via_spdy = rhs.was_fetched_via_spdy; was_npn_negotiated = rhs.was_npn_negotiated; - was_alternate_protocol_available = rhs.was_alternate_protocol_available; was_fetched_via_proxy = rhs.was_fetched_via_proxy; socket_address = rhs.socket_address; request_time = rhs.request_time; @@ -115,7 +111,8 @@ bool HttpResponseInfo::InitFromPickle(const Pickle& pickle, if (!pickle.ReadInt(&iter, &flags)) return false; int version = flags & RESPONSE_INFO_VERSION_MASK; - if (version != RESPONSE_INFO_VERSION) { + if (version < RESPONSE_INFO_MINIMUM_VERSION || + version > RESPONSE_INFO_VERSION) { DLOG(ERROR) << "unexpected response info version: " << version; return false; } @@ -138,8 +135,12 @@ bool HttpResponseInfo::InitFromPickle(const Pickle& pickle, // read ssl-info if (flags & RESPONSE_INFO_HAS_CERT) { - ssl_info.cert = - X509Certificate::CreateFromPickle(pickle, &iter); + // Version 1 only serialized only the end-entity certificate, + // while subsequent versions include the entire chain. + X509Certificate::PickleType type = (version == 1) ? + X509Certificate::PICKLETYPE_SINGLE_CERTIFICATE : + X509Certificate::PICKLETYPE_CERTIFICATE_CHAIN; + ssl_info.cert = X509Certificate::CreateFromPickle(pickle, &iter, type); } if (flags & RESPONSE_INFO_HAS_CERT_STATUS) { int cert_status; @@ -176,9 +177,6 @@ bool HttpResponseInfo::InitFromPickle(const Pickle& pickle, was_npn_negotiated = (flags & RESPONSE_INFO_WAS_NPN) != 0; - was_alternate_protocol_available = - (flags & RESPONSE_INFO_WAS_ALTERNATE_PROTOCOL_AVAILABLE) != 0; - was_fetched_via_proxy = (flags & RESPONSE_INFO_WAS_PROXY) != 0; *response_truncated = (flags & RESPONSE_INFO_TRUNCATED) ? true : false; @@ -205,8 +203,6 @@ void HttpResponseInfo::Persist(Pickle* pickle, flags |= RESPONSE_INFO_WAS_SPDY; if (was_npn_negotiated) flags |= RESPONSE_INFO_WAS_NPN; - if (was_alternate_protocol_available) - flags |= RESPONSE_INFO_WAS_ALTERNATE_PROTOCOL_AVAILABLE; if (was_fetched_via_proxy) flags |= RESPONSE_INFO_WAS_PROXY; diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h index e13f288..c925aa9 100644 --- a/net/http/http_response_info.h +++ b/net/http/http_response_info.h @@ -52,10 +52,6 @@ class HttpResponseInfo { // True if the npn was negotiated for this request. bool was_npn_negotiated; - // True if response could use alternate protocol. However, browser - // will ingore the alternate protocol if spdy is not enabled. - bool was_alternate_protocol_available; - // True if the request was fetched via an explicit proxy. The proxy could // be any type of proxy, HTTP or SOCKS. Note, we do not know if a // transparent proxy may have been involved. diff --git a/net/http/http_stream.h b/net/http/http_stream.h index 16f84cc..fed6465 100644 --- a/net/http/http_stream.h +++ b/net/http/http_stream.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // @@ -116,6 +116,10 @@ class HttpStream { virtual bool IsConnectionReused() const = 0; virtual void SetConnectionReused() = 0; + // Checks whether the current state of the underlying connection + // allows it to be reused. + virtual bool IsConnectionReusable() const = 0; + // Get the SSLInfo associated with this stream's connection. This should // only be called for streams over SSL sockets, otherwise the behavior is // undefined. @@ -126,6 +130,10 @@ class HttpStream { // behavior is undefined. virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) = 0; + // HACK(willchan): Really, we should move the HttpResponseDrainer logic into + // the HttpStream implementation. This is just a quick hack. + virtual bool IsSpdyHttpStream() const = 0; + private: DISALLOW_COPY_AND_ASSIGN(HttpStream); }; diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc index 9189e99..e5ffc26 100644 --- a/net/http/http_stream_factory.cc +++ b/net/http/http_stream_factory.cc @@ -108,6 +108,19 @@ void HttpStreamFactory::add_forced_spdy_exclusion(const std::string& value) { } // static +bool HttpStreamFactory::HasSpdyExclusion(const HostPortPair& endpoint) { + std::list<HostPortPair>* exclusions = forced_spdy_exclusions_; + if (!exclusions) + return false; + + std::list<HostPortPair>::const_iterator it; + for (it = exclusions->begin(); it != exclusions->end(); ++it) + if (it->Equals(endpoint)) + return true; + return false; +} + +// static void HttpStreamFactory::SetHostMappingRules(const std::string& rules) { HostMappingRules* host_mapping_rules = new HostMappingRules; host_mapping_rules->SetRulesFromString(rules); diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h index 3d3bada..4375f3f 100644 --- a/net/http/http_stream_factory.h +++ b/net/http/http_stream_factory.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,8 +8,8 @@ #include <list> #include <string> +#include "base/memory/ref_counted.h" #include "base/string16.h" -#include "base/ref_counted.h" #include "net/base/completion_callback.h" #include "net/base/load_states.h" @@ -135,9 +135,6 @@ class HttpStreamRequest { // Returns the LoadState for the request. virtual LoadState GetLoadState() const = 0; - // Returns true if an AlternateProtocol for this request was available. - virtual bool was_alternate_protocol_available() const = 0; - // Returns true if TLS/NPN was negotiated for this stream. virtual bool was_npn_negotiated() const = 0; @@ -171,8 +168,8 @@ class HttpStreamFactory { const SSLConfig& ssl_config, const BoundNetLog& net_log) = 0; - virtual void AddTLSIntolerantServer(const GURL& url) = 0; - virtual bool IsTLSIntolerantServer(const GURL& url) const = 0; + virtual void AddTLSIntolerantServer(const HostPortPair& server) = 0; + virtual bool IsTLSIntolerantServer(const HostPortPair& server) const = 0; // Static settings static GURL ApplyHostMappingRules(const GURL& url, HostPortPair* endpoint); @@ -207,9 +204,8 @@ class HttpStreamFactory { // Add a URL to exclude from forced SPDY. static void add_forced_spdy_exclusion(const std::string& value); - static std::list<HostPortPair>* forced_spdy_exclusions() { - return forced_spdy_exclusions_; - } + // Check if a HostPortPair is excluded from using spdy. + static bool HasSpdyExclusion(const HostPortPair& endpoint); // Sets the next protocol negotiation value used during the SSL handshake. static void set_next_protos(const std::string& value) { diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc index c7b0c93..63db456 100644 --- a/net/http/http_stream_factory_impl.cc +++ b/net/http/http_stream_factory_impl.cc @@ -4,6 +4,7 @@ #include "net/http/http_stream_factory_impl.h" +#include "base/string_number_conversions.h" #include "base/stl_util-inl.h" #include "googleurl/src/gurl.h" #include "net/base/net_log.h" @@ -15,6 +16,21 @@ namespace net { +namespace { + +GURL UpgradeUrlToHttps(const GURL& original_url) { + GURL::Replacements replacements; + // new_sheme and new_port need to be in scope here because GURL::Replacements + // references the memory contained by them directly. + const std::string new_scheme = "https"; + const std::string new_port = base::IntToString(443); + replacements.SetSchemeStr(new_scheme); + replacements.SetPortStr(new_port); + return original_url.ReplaceComponents(replacements); +} + +} // namespace + HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session) : session_(session) {} @@ -23,6 +39,11 @@ HttpStreamFactoryImpl::~HttpStreamFactoryImpl() { DCHECK(spdy_session_request_map_.empty()); std::set<const Job*> tmp_job_set; + tmp_job_set.swap(orphaned_job_set_); + STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end()); + DCHECK(orphaned_job_set_.empty()); + + tmp_job_set.clear(); tmp_job_set.swap(preconnect_job_set_); STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end()); DCHECK(preconnect_job_set_.empty()); @@ -33,10 +54,34 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestStream( const SSLConfig& ssl_config, HttpStreamRequest::Delegate* delegate, const BoundNetLog& net_log) { - Job* job = new Job(this, session_); Request* request = new Request(request_info.url, this, delegate, net_log); + + GURL alternate_url; + bool has_alternate_protocol = + GetAlternateProtocolRequestFor(request_info.url, &alternate_url); + Job* alternate_job = NULL; + if (has_alternate_protocol) { + HttpRequestInfo alternate_request_info = request_info; + alternate_request_info.url = alternate_url; + alternate_job = + new Job(this, session_, alternate_request_info, ssl_config, net_log); + request->AttachJob(alternate_job); + alternate_job->MarkAsAlternate(request_info.url); + } + + Job* job = new Job(this, session_, request_info, ssl_config, net_log); request->AttachJob(job); - job->Start(request, request_info, ssl_config, net_log); + if (alternate_job) { + job->WaitFor(alternate_job); + // Make sure to wait until we call WaitFor(), before starting + // |alternate_job|, otherwise |alternate_job| will not notify |job| + // appropriately. + alternate_job->Start(request); + } + // Even if |alternate_job| has already finished, it won't have notified the + // request yet, since we defer that to the next iteration of the MessageLoop, + // so starting |job| is always safe. + job->Start(request); return request; } @@ -45,17 +90,66 @@ void HttpStreamFactoryImpl::PreconnectStreams( const HttpRequestInfo& request_info, const SSLConfig& ssl_config, const BoundNetLog& net_log) { - Job* job = new Job(this, session_); + GURL alternate_url; + bool has_alternate_protocol = + GetAlternateProtocolRequestFor(request_info.url, &alternate_url); + Job* job = NULL; + if (has_alternate_protocol) { + HttpRequestInfo alternate_request_info = request_info; + alternate_request_info.url = alternate_url; + job = new Job(this, session_, alternate_request_info, ssl_config, net_log); + job->MarkAsAlternate(request_info.url); + } else { + job = new Job(this, session_, request_info, ssl_config, net_log); + } preconnect_job_set_.insert(job); - job->Preconnect(num_streams, request_info, ssl_config, net_log); + job->Preconnect(num_streams); } -void HttpStreamFactoryImpl::AddTLSIntolerantServer(const GURL& url) { - tls_intolerant_servers_.insert(GetHostAndPort(url)); +void HttpStreamFactoryImpl::AddTLSIntolerantServer(const HostPortPair& server) { + tls_intolerant_servers_.insert(server); } -bool HttpStreamFactoryImpl::IsTLSIntolerantServer(const GURL& url) const { - return ContainsKey(tls_intolerant_servers_, GetHostAndPort(url)); +bool HttpStreamFactoryImpl::IsTLSIntolerantServer( + const HostPortPair& server) const { + return ContainsKey(tls_intolerant_servers_, server); +} + +bool HttpStreamFactoryImpl::GetAlternateProtocolRequestFor( + const GURL& original_url, + GURL* alternate_url) const { + if (!spdy_enabled()) + return false; + + if (!use_alternate_protocols()) + return false; + + HostPortPair origin = HostPortPair(original_url.HostNoBrackets(), + original_url.EffectiveIntPort()); + + const HttpAlternateProtocols& alternate_protocols = + session_->alternate_protocols(); + if (!alternate_protocols.HasAlternateProtocolFor(origin)) + return false; + + HttpAlternateProtocols::PortProtocolPair alternate = + alternate_protocols.GetAlternateProtocolFor(origin); + if (alternate.protocol == HttpAlternateProtocols::BROKEN) + return false; + + DCHECK_LE(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol); + DCHECK_GT(HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS, + alternate.protocol); + + if (alternate.protocol != HttpAlternateProtocols::NPN_SPDY_2) + return false; + + origin.set_port(alternate.port); + if (HttpStreamFactory::HasSpdyExclusion(origin)) + return false; + + *alternate_url = UpgradeUrlToHttps(original_url); + return true; } void HttpStreamFactoryImpl::OrphanJob(Job* job, const Request* request) { @@ -74,7 +168,6 @@ void HttpStreamFactoryImpl::OnSpdySessionReady( bool direct, const SSLConfig& used_ssl_config, const ProxyInfo& used_proxy_info, - bool was_alternate_protocol_available, bool was_npn_negotiated, bool using_spdy, const NetLog::Source& source) { @@ -91,8 +184,7 @@ void HttpStreamFactoryImpl::OnSpdySessionReady( if (!ContainsKey(spdy_session_request_map_, spdy_session_key)) break; Request* request = *spdy_session_request_map_[spdy_session_key].begin(); - request->Complete(was_alternate_protocol_available, - was_npn_negotiated, + request->Complete(was_npn_negotiated, using_spdy, source); bool use_relative_url = direct || request->url().SchemeIs("https"); diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h index 4bdbfca..93e8c57 100644 --- a/net/http/http_stream_factory_impl.h +++ b/net/http/http_stream_factory_impl.h @@ -7,9 +7,9 @@ #include <map> #include <set> -#include <string> -#include "base/ref_counted.h" +#include "base/memory/ref_counted.h" +#include "net/base/host_port_pair.h" #include "net/http/http_stream_factory.h" #include "net/base/net_log.h" #include "net/proxy/proxy_server.h" @@ -35,8 +35,8 @@ class HttpStreamFactoryImpl : public HttpStreamFactory { const HttpRequestInfo& info, const SSLConfig& ssl_config, const BoundNetLog& net_log); - virtual void AddTLSIntolerantServer(const GURL& url); - virtual bool IsTLSIntolerantServer(const GURL& url) const; + virtual void AddTLSIntolerantServer(const HostPortPair& server); + virtual bool IsTLSIntolerantServer(const HostPortPair& server) const; private: class Request; @@ -45,6 +45,9 @@ class HttpStreamFactoryImpl : public HttpStreamFactory { typedef std::set<Request*> RequestSet; typedef std::map<HostPortProxyPair, RequestSet> SpdySessionRequestMap; + bool GetAlternateProtocolRequestFor(const GURL& original_url, + GURL* alternate_url) const; + // Detaches |job| from |request|. void OrphanJob(Job* job, const Request* request); @@ -55,7 +58,6 @@ class HttpStreamFactoryImpl : public HttpStreamFactory { bool direct, const SSLConfig& used_ssl_config, const ProxyInfo& used_proxy_info, - bool was_alternate_protocol_available, bool was_npn_negotiated, bool using_spdy, const NetLog::Source& source); @@ -76,7 +78,7 @@ class HttpStreamFactoryImpl : public HttpStreamFactory { HttpNetworkSession* const session_; - std::set<std::string> tls_intolerant_servers_; + std::set<HostPortPair> tls_intolerant_servers_; // All Requests are handed out to clients. By the time HttpStreamFactoryImpl // is destroyed, all Requests should be deleted (which should remove them from diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc index 224403b..75011e3 100644 --- a/net/http/http_stream_factory_impl_job.cc +++ b/net/http/http_stream_factory_impl_job.cc @@ -6,7 +6,6 @@ #include "base/logging.h" #include "base/stl_util-inl.h" -#include "base/string_number_conversions.h" #include "base/string_util.h" #include "base/stringprintf.h" #include "base/values.h" @@ -25,7 +24,6 @@ #include "net/socket/socks_client_socket_pool.h" #include "net/socket/ssl_client_socket.h" #include "net/socket/ssl_client_socket_pool.h" -#include "net/socket/tcp_client_socket_pool.h" #include "net/spdy/spdy_http_stream.h" #include "net/spdy/spdy_session.h" #include "net/spdy/spdy_session_pool.h" @@ -34,46 +32,38 @@ namespace net { namespace { -GURL UpgradeUrlToHttps(const GURL& original_url) { - GURL::Replacements replacements; - // new_sheme and new_port need to be in scope here because GURL::Replacements - // references the memory contained by them directly. - const std::string new_scheme = "https"; - const std::string new_port = base::IntToString(443); - replacements.SetSchemeStr(new_scheme); - replacements.SetPortStr(new_port); - return original_url.ReplaceComponents(replacements); -} - } // namespace HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory, - HttpNetworkSession* session) + HttpNetworkSession* session, + const HttpRequestInfo& request_info, + const SSLConfig& ssl_config, + const BoundNetLog& net_log) : request_(NULL), + request_info_(request_info), + ssl_config_(ssl_config), + net_log_(BoundNetLog::Make(net_log.net_log(), + NetLog::SOURCE_HTTP_STREAM_JOB)), ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(this, &Job::OnIOComplete)), connection_(new ClientSocketHandle), session_(session), stream_factory_(stream_factory), next_state_(STATE_NONE), pac_request_(NULL), + blocking_job_(NULL), + dependent_job_(NULL), using_ssl_(false), using_spdy_(false), force_spdy_always_(HttpStreamFactory::force_spdy_always()), force_spdy_over_ssl_(HttpStreamFactory::force_spdy_over_ssl()), spdy_certificate_error_(OK), - alternate_protocol_(HttpAlternateProtocols::UNINITIALIZED), establishing_tunnel_(false), - was_alternate_protocol_available_(false), was_npn_negotiated_(false), num_streams_(0), spdy_session_direct_(false), ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { DCHECK(stream_factory); DCHECK(session); - if (HttpStreamFactory::use_alternate_protocols()) - alternate_protocol_mode_ = kUnspecified; - else - alternate_protocol_mode_ = kDoNotUseAlternateProtocol; } HttpStreamFactoryImpl::Job::~Job() { @@ -95,22 +85,16 @@ HttpStreamFactoryImpl::Job::~Job() { stream_->Close(true /* not reusable */); } -void HttpStreamFactoryImpl::Job::Start(Request* request, - const HttpRequestInfo& request_info, - const SSLConfig& ssl_config, - const BoundNetLog& net_log) { +void HttpStreamFactoryImpl::Job::Start(Request* request) { DCHECK(request); request_ = request; - StartInternal(request_info, ssl_config, net_log); + StartInternal(); } -int HttpStreamFactoryImpl::Job::Preconnect(int num_streams, - const HttpRequestInfo& request_info, - const SSLConfig& ssl_config, - const BoundNetLog& net_log) { +int HttpStreamFactoryImpl::Job::Preconnect(int num_streams) { DCHECK_GT(num_streams, 0); num_streams_ = num_streams; - return StartInternal(request_info, ssl_config, net_log); + return StartInternal(); } int HttpStreamFactoryImpl::Job::RestartTunnelWithProxyAuth( @@ -134,13 +118,45 @@ LoadState HttpStreamFactoryImpl::Job::GetLoadState() const { } } +void HttpStreamFactoryImpl::Job::MarkAsAlternate(const GURL& original_url) { + DCHECK(!original_url_.get()); + original_url_.reset(new GURL(original_url)); +} + +void HttpStreamFactoryImpl::Job::WaitFor(Job* job) { + DCHECK_EQ(STATE_NONE, next_state_); + DCHECK_EQ(STATE_NONE, job->next_state_); + DCHECK(!blocking_job_); + DCHECK(!job->dependent_job_); + blocking_job_ = job; + job->dependent_job_ = this; +} + +void HttpStreamFactoryImpl::Job::Resume(Job* job) { + DCHECK_EQ(blocking_job_, job); + blocking_job_ = NULL; + + // We know we're blocked if the next_state_ is STATE_WAIT_FOR_JOB_COMPLETE. + // Unblock |this|. + if (next_state_ == STATE_WAIT_FOR_JOB_COMPLETE) { + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &HttpStreamFactoryImpl::Job::OnIOComplete, OK)); + } +} + void HttpStreamFactoryImpl::Job::Orphan(const Request* request) { DCHECK_EQ(request_, request); request_ = NULL; -} - -bool HttpStreamFactoryImpl::Job::was_alternate_protocol_available() const { - return was_alternate_protocol_available_; + // We've been orphaned, but there's a job we're blocked on. Don't bother + // racing, just cancel ourself. + if (blocking_job_) { + DCHECK(blocking_job_->dependent_job_); + blocking_job_->dependent_job_ = NULL; + blocking_job_ = NULL; + stream_factory_->OnOrphanedJobComplete(this); + } } bool HttpStreamFactoryImpl::Job::was_npn_negotiated() const { @@ -174,8 +190,7 @@ void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() { if (IsOrphaned()) { stream_factory_->OnOrphanedJobComplete(this); } else { - request_->Complete(was_alternate_protocol_available(), - was_npn_negotiated(), + request_->Complete(was_npn_negotiated(), using_spdy(), net_log_.source()); request_->OnStreamReady(this, ssl_config_, proxy_info_, stream_.release()); @@ -193,8 +208,7 @@ void HttpStreamFactoryImpl::Job::OnSpdySessionReadyCallback() { if (IsOrphaned()) { stream_factory_->OnSpdySessionReady( spdy_session, spdy_session_direct_, ssl_config_, proxy_info_, - was_alternate_protocol_available(), was_npn_negotiated(), - using_spdy(), net_log_.source()); + was_npn_negotiated(), using_spdy(), net_log_.source()); stream_factory_->OnOrphanedJobComplete(this); } else { request_->OnSpdySessionReady(this, spdy_session, spdy_session_direct_); @@ -260,8 +274,7 @@ void HttpStreamFactoryImpl::Job::OnPreconnectsComplete() { if (new_spdy_session_) { stream_factory_->OnSpdySessionReady( new_spdy_session_, spdy_session_direct_, ssl_config_, - proxy_info_, was_alternate_protocol_available(), - was_npn_negotiated(), using_spdy(), net_log_.source()); + proxy_info_, was_npn_negotiated(), using_spdy(), net_log_.source()); } stream_factory_->OnPreconnectsComplete(this); // |this| may be deleted after this call. @@ -385,6 +398,13 @@ int HttpStreamFactoryImpl::Job::DoLoop(int result) { case STATE_RESOLVE_PROXY_COMPLETE: rv = DoResolveProxyComplete(rv); break; + case STATE_WAIT_FOR_JOB: + DCHECK_EQ(OK, rv); + rv = DoWaitForJob(); + break; + case STATE_WAIT_FOR_JOB_COMPLETE: + rv = DoWaitForJobComplete(rv); + break; case STATE_INIT_CONNECTION: DCHECK_EQ(OK, rv); rv = DoInitConnection(); @@ -418,18 +438,11 @@ int HttpStreamFactoryImpl::Job::DoLoop(int result) { return rv; } -int HttpStreamFactoryImpl::Job::StartInternal( - const HttpRequestInfo& request_info, - const SSLConfig& ssl_config, - const BoundNetLog& net_log) { +int HttpStreamFactoryImpl::Job::StartInternal() { CHECK_EQ(STATE_NONE, next_state_); - request_info_ = request_info; - ssl_config_ = ssl_config; - net_log_ = BoundNetLog::Make(net_log.net_log(), - NetLog::SOURCE_HTTP_STREAM_JOB); net_log_.BeginEvent(NetLog::TYPE_HTTP_STREAM_JOB, make_scoped_refptr(new NetLogStringParameter( - "url", request_info.url.GetOrigin().spec()))); + "url", request_info_.url.GetOrigin().spec()))); next_state_ = STATE_RESOLVE_PROXY; int rv = RunLoop(OK); DCHECK_EQ(ERR_IO_PENDING, rv); @@ -441,40 +454,8 @@ int HttpStreamFactoryImpl::Job::DoResolveProxy() { next_state_ = STATE_RESOLVE_PROXY_COMPLETE; - // |endpoint_| indicates the final destination endpoint. - endpoint_ = HostPortPair(request_info_.url.HostNoBrackets(), - request_info_.url.EffectiveIntPort()); - - // Extra URL we might be attempting to resolve to. - GURL alternate_endpoint_url = request_info_.url; - - // Tracks whether we are using |request_.url| or |alternate_endpoint_url|. - const GURL *curr_endpoint_url = &request_info_.url; - - alternate_endpoint_url = - HttpStreamFactory::ApplyHostMappingRules( - alternate_endpoint_url, &endpoint_); - - const HttpAlternateProtocols& alternate_protocols = - session_->alternate_protocols(); - if (HttpStreamFactory::spdy_enabled() && - alternate_protocols.HasAlternateProtocolFor(endpoint_)) { - was_alternate_protocol_available_ = true; - if (alternate_protocol_mode_ == kUnspecified) { - HttpAlternateProtocols::PortProtocolPair alternate = - alternate_protocols.GetAlternateProtocolFor(endpoint_); - if (alternate.protocol != HttpAlternateProtocols::BROKEN) { - DCHECK_LE(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol); - DCHECK_GT(HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS, - alternate.protocol); - endpoint_.set_port(alternate.port); - alternate_protocol_ = alternate.protocol; - alternate_protocol_mode_ = kUsingAlternateProtocol; - alternate_endpoint_url = UpgradeUrlToHttps(*curr_endpoint_url); - curr_endpoint_url = &alternate_endpoint_url; - } - } - } + origin_ = HostPortPair(request_info_.url.HostNoBrackets(), + request_info_.url.EffectiveIntPort()); if (request_info_.load_flags & LOAD_BYPASS_PROXY) { proxy_info_.UseDirect(); @@ -482,70 +463,73 @@ int HttpStreamFactoryImpl::Job::DoResolveProxy() { } return session_->proxy_service()->ResolveProxy( - *curr_endpoint_url, &proxy_info_, &io_callback_, &pac_request_, + request_info_.url, &proxy_info_, &io_callback_, &pac_request_, net_log_); } int HttpStreamFactoryImpl::Job::DoResolveProxyComplete(int result) { pac_request_ = NULL; - if (result != OK) - return result; - - // TODO(mbelshe): consider retrying ResolveProxy if we came here via use of - // AlternateProtocol. - - // Remove unsupported proxies from the list. - proxy_info_.RemoveProxiesWithoutScheme( - ProxyServer::SCHEME_DIRECT | - ProxyServer::SCHEME_HTTP | ProxyServer::SCHEME_HTTPS | - ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5); + if (result == OK) { + // Remove unsupported proxies from the list. + proxy_info_.RemoveProxiesWithoutScheme( + ProxyServer::SCHEME_DIRECT | + ProxyServer::SCHEME_HTTP | ProxyServer::SCHEME_HTTPS | + ProxyServer::SCHEME_SOCKS4 | ProxyServer::SCHEME_SOCKS5); + + if (proxy_info_.is_empty()) { + // No proxies/direct to choose from. This happens when we don't support + // any of the proxies in the returned list. + result = ERR_NO_SUPPORTED_PROXIES; + } + } - if (proxy_info_.is_empty()) { - // No proxies/direct to choose from. This happens when we don't support any - // of the proxies in the returned list. - return ERR_NO_SUPPORTED_PROXIES; + if (result != OK) { + if (dependent_job_) + dependent_job_->Resume(this); + return result; } - next_state_ = STATE_INIT_CONNECTION; + if (blocking_job_) + next_state_ = STATE_WAIT_FOR_JOB; + else + next_state_ = STATE_INIT_CONNECTION; return OK; } -static bool HasSpdyExclusion(const HostPortPair& endpoint) { - std::list<HostPortPair>* exclusions = - HttpStreamFactory::forced_spdy_exclusions(); - if (!exclusions) - return false; +bool HttpStreamFactoryImpl::Job::ShouldForceSpdySSL() const { + bool rv = force_spdy_always_ && force_spdy_over_ssl_; + return rv && !HttpStreamFactory::HasSpdyExclusion(origin_); +} - std::list<HostPortPair>::const_iterator it; - for (it = exclusions->begin(); it != exclusions->end(); it++) - if (it->Equals(endpoint)) - return true; - return false; +bool HttpStreamFactoryImpl::Job::ShouldForceSpdyWithoutSSL() const { + bool rv = force_spdy_always_ && !force_spdy_over_ssl_; + return rv && !HttpStreamFactory::HasSpdyExclusion(origin_); } -bool HttpStreamFactoryImpl::Job::ShouldForceSpdySSL() { - bool rv = force_spdy_always_ && force_spdy_over_ssl_; - return rv && !HasSpdyExclusion(endpoint_); +int HttpStreamFactoryImpl::Job::DoWaitForJob() { + DCHECK(blocking_job_); + next_state_ = STATE_WAIT_FOR_JOB_COMPLETE; + return ERR_IO_PENDING; } -bool HttpStreamFactoryImpl::Job::ShouldForceSpdyWithoutSSL() { - bool rv = force_spdy_always_ && !force_spdy_over_ssl_; - return rv && !HasSpdyExclusion(endpoint_); +int HttpStreamFactoryImpl::Job::DoWaitForJobComplete(int result) { + DCHECK(!blocking_job_); + DCHECK_EQ(OK, result); + next_state_ = STATE_INIT_CONNECTION; + return OK; } int HttpStreamFactoryImpl::Job::DoInitConnection() { + DCHECK(!blocking_job_); DCHECK(!connection_->is_initialized()); DCHECK(proxy_info_.proxy_server().is_valid()); next_state_ = STATE_INIT_CONNECTION_COMPLETE; - bool want_spdy_over_npn = - alternate_protocol_mode_ == kUsingAlternateProtocol && - alternate_protocol_ == HttpAlternateProtocols::NPN_SPDY_2; - using_ssl_ = request_info_.url.SchemeIs("https") || - ShouldForceSpdySSL() || want_spdy_over_npn; + using_ssl_ = request_info_.url.SchemeIs("https") || ShouldForceSpdySSL(); using_spdy_ = false; +<<<<<<< HEAD // If spdy has been turned off on-the-fly, then there may be SpdySessions // still active. But don't use them unless spdy is currently on. if (HttpStreamFactory::spdy_enabled() && !HasSpdyExclusion(endpoint_)) { @@ -668,73 +652,77 @@ int HttpStreamFactoryImpl::Job::DoInitConnection() { request_info_.priority, request_info_.referrer); } +======= + // Check first if we have a spdy session for this group. If so, then go + // straight to using that. + HostPortProxyPair spdy_session_key; + if (IsHttpsProxyAndHttpUrl()) { + spdy_session_key = + HostPortProxyPair(proxy_info_.proxy_server().host_port_pair(), + ProxyServer::Direct()); + } else { + spdy_session_key = HostPortProxyPair(origin_, proxy_info_.proxy_server()); +>>>>>>> chromium.org at r12.0.742.93 } - - // Deal with SSL - which layers on top of any given proxy. - if (using_ssl_) { - scoped_refptr<SSLSocketParams> ssl_params = - GenerateSSLParams(tcp_params, http_proxy_params, socks_params, - proxy_info_.proxy_server().scheme(), - HostPortPair::FromURL(request_info_.url), - want_spdy_over_npn); - SSLClientSocketPool* ssl_pool = NULL; - if (proxy_info_.is_direct()) - ssl_pool = session_->ssl_socket_pool(); - else - ssl_pool = session_->GetSocketPoolForSSLWithProxy(*proxy_host_port); - - if (IsPreconnecting()) { - RequestSocketsForPool(ssl_pool, connection_group, ssl_params, - num_streams_, net_log_); + if (session_->spdy_session_pool()->HasSession(spdy_session_key)) { + // If we're preconnecting, but we already have a SpdySession, we don't + // actually need to preconnect any sockets, so we're done. + if (IsPreconnecting()) return OK; - } - - return connection_->Init(connection_group, ssl_params, - request_info_.priority, &io_callback_, ssl_pool, - net_log_); + using_spdy_ = true; + next_state_ = STATE_CREATE_STREAM; + return OK; + } else if (request_ && (using_ssl_ || ShouldForceSpdyWithoutSSL())) { + // Update the spdy session key for the request that launched this job. + request_->SetSpdySessionKey(spdy_session_key); } - // Finally, get the connection started. - if (proxy_info_.is_http() || proxy_info_.is_https()) { - HttpProxyClientSocketPool* pool = - session_->GetSocketPoolForHTTPProxy(*proxy_host_port); - if (IsPreconnecting()) { - RequestSocketsForPool(pool, connection_group, http_proxy_params, - num_streams_, net_log_); - return OK; - } + // OK, there's no available SPDY session. Let |dependent_job_| resume if it's + // paused. - return connection_->Init(connection_group, http_proxy_params, - request_info_.priority, &io_callback_, - pool, net_log_); + if (dependent_job_) { + dependent_job_->Resume(this); + dependent_job_ = NULL; } - if (proxy_info_.is_socks()) { - SOCKSClientSocketPool* pool = - session_->GetSocketPoolForSOCKSProxy(*proxy_host_port); - if (IsPreconnecting()) { - RequestSocketsForPool(pool, connection_group, socks_params, - num_streams_, net_log_); - return OK; - } + if (proxy_info_.is_http() || proxy_info_.is_https()) + establishing_tunnel_ = using_ssl_; - return connection_->Init(connection_group, socks_params, - request_info_.priority, &io_callback_, pool, - net_log_); - } + bool want_spdy_over_npn = original_url_.get() ? true : false; - DCHECK(proxy_info_.is_direct()); + SSLConfig ssl_config_for_proxy = ssl_config_; + if (proxy_info_.is_https()) { + InitSSLConfig(proxy_info_.proxy_server().host_port_pair(), + &ssl_config_for_proxy); + } + if (using_ssl_) { + InitSSLConfig(origin_, &ssl_config_); + } - TCPClientSocketPool* pool = session_->tcp_socket_pool(); if (IsPreconnecting()) { - RequestSocketsForPool(pool, connection_group, tcp_params, - num_streams_, net_log_); - return OK; + return ClientSocketPoolManager::PreconnectSocketsForHttpRequest( + request_info_, + session_, + proxy_info_, + ShouldForceSpdySSL(), + want_spdy_over_npn, + ssl_config_, + ssl_config_for_proxy, + net_log_, + num_streams_); + } else { + return ClientSocketPoolManager::InitSocketHandleForHttpRequest( + request_info_, + session_, + proxy_info_, + ShouldForceSpdySSL(), + want_spdy_over_npn, + ssl_config_, + ssl_config_for_proxy, + net_log_, + connection_.get(), + &io_callback_); } - - return connection_->Init(connection_group, tcp_params, - request_info_.priority, &io_callback_, - pool, net_log_); } int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) { @@ -743,6 +731,13 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) { return OK; } + // TODO(willchan): Make this a bit more exact. Maybe there are recoverable + // errors, such as ignoring certificate errors for Alternate-Protocol. + if (result < 0 && dependent_job_) { + dependent_job_->Resume(this); + dependent_job_ = NULL; + } + // |result| may be the result of any of the stacked pools. The following // logic is used when determining how to interpret an error. // If |result| < 0: @@ -791,12 +786,11 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) { return result; } - if ((!ssl_started && result < 0 && - alternate_protocol_mode_ == kUsingAlternateProtocol) || - result == ERR_NPN_NEGOTIATION_FAILED) { + if (!ssl_started && result < 0 && original_url_.get()) { // Mark the alternate protocol as broken and fallback. - MarkBrokenAlternateProtocolAndFallback(); - return OK; + session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor( + HostPortPair::FromURL(*original_url_)); + return result; } if (result < 0 && !ssl_started) @@ -817,7 +811,8 @@ int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) { if (using_ssl_) { DCHECK(ssl_started); if (IsCertificateError(result)) { - if (using_spdy_ && request_info_.url.SchemeIs("http")) { + if (using_spdy_ && original_url_.get() && + original_url_->SchemeIs("http")) { // We ignore certificate errors for http over spdy. spdy_certificate_error_ = result; result = OK; @@ -871,7 +866,7 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() { SpdySessionPool* spdy_pool = session_->spdy_session_pool(); scoped_refptr<SpdySession> spdy_session; - HostPortProxyPair pair(endpoint_, proxy_server); + HostPortProxyPair pair(origin_, proxy_server); if (spdy_pool->HasSession(pair)) { // We have a SPDY session to the origin server. This might be a direct // connection, or it might be a SPDY session through an HTTP or HTTPS proxy. @@ -975,27 +970,30 @@ void HttpStreamFactoryImpl::Job::SetSocketMotivation() { } bool HttpStreamFactoryImpl::Job::IsHttpsProxyAndHttpUrl() { - return proxy_info_.is_https() && request_info_.url.SchemeIs("http"); + if (!proxy_info_.is_https()) + return false; + if (original_url_.get()) { + // We currently only support Alternate-Protocol where the original scheme + // is http. + DCHECK(original_url_->SchemeIs("http")); + return original_url_->SchemeIs("http"); + } + return request_info_.url.SchemeIs("http"); } -// Returns a newly create SSLSocketParams, and sets several -// fields of ssl_config_. -scoped_refptr<SSLSocketParams> HttpStreamFactoryImpl::Job::GenerateSSLParams( - scoped_refptr<TCPSocketParams> tcp_params, - scoped_refptr<HttpProxySocketParams> http_proxy_params, - scoped_refptr<SOCKSSocketParams> socks_params, - ProxyServer::Scheme proxy_scheme, - const HostPortPair& host_and_port, - bool want_spdy_over_npn) { - - if (stream_factory_->IsTLSIntolerantServer(request_info_.url)) { +// Sets several fields of ssl_config for the given origin_server based on the +// proxy info and other factors. +void HttpStreamFactoryImpl::Job::InitSSLConfig( + const HostPortPair& origin_server, + SSLConfig* ssl_config) const { + if (stream_factory_->IsTLSIntolerantServer(origin_server)) { LOG(WARNING) << "Falling back to SSLv3 because host is TLS intolerant: " - << GetHostAndPort(request_info_.url); - ssl_config_.ssl3_fallback = true; - ssl_config_.tls1_enabled = false; + << origin_server.ToString(); + ssl_config->ssl3_fallback = true; + ssl_config->tls1_enabled = false; } - if (proxy_info_.is_https() && ssl_config_.send_client_cert) { + if (proxy_info_.is_https() && ssl_config->send_client_cert) { // When connecting through an HTTPS proxy, disable TLS False Start so // that client authentication errors can be distinguished between those // originating from the proxy server (ERR_PROXY_CONNECTION_FAILED) and @@ -1004,52 +1002,17 @@ scoped_refptr<SSLSocketParams> HttpStreamFactoryImpl::Job::GenerateSSLParams( // TODO(rch): This assumes that the HTTPS proxy will only request a // client certificate during the initial handshake. // http://crbug.com/59292 - ssl_config_.false_start_enabled = false; + ssl_config->false_start_enabled = false; } UMA_HISTOGRAM_ENUMERATION("Net.ConnectionUsedSSLv3Fallback", - static_cast<int>(ssl_config_.ssl3_fallback), 2); + static_cast<int>(ssl_config->ssl3_fallback), 2); - int load_flags = request_info_.load_flags; - if (HttpStreamFactory::ignore_certificate_errors()) - load_flags |= LOAD_IGNORE_ALL_CERT_ERRORS; if (request_info_.load_flags & LOAD_VERIFY_EV_CERT) - ssl_config_.verify_ev_cert = true; - - if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_HTTP || - proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_HTTPS) { - ssl_config_.mitm_proxies_allowed = true; - } - - scoped_refptr<SSLSocketParams> ssl_params( - new SSLSocketParams(tcp_params, socks_params, http_proxy_params, - proxy_scheme, host_and_port, - ssl_config_, load_flags, - ShouldForceSpdySSL(), - want_spdy_over_npn)); - - return ssl_params; + ssl_config->verify_ev_cert = true; } -void HttpStreamFactoryImpl::Job::MarkBrokenAlternateProtocolAndFallback() { - // We have to: - // * Reset the endpoint to be the unmodified URL specified destination. - // * Mark the endpoint as broken so we don't try again. - // * Set the alternate protocol mode to kDoNotUseAlternateProtocol so we - // ignore future Alternate-Protocol headers from the HostPortPair. - // * Reset the connection and go back to STATE_INIT_CONNECTION. - - endpoint_ = HostPortPair(request_info_.url.HostNoBrackets(), - request_info_.url.EffectiveIntPort()); - - session_->mutable_alternate_protocols()->MarkBrokenAlternateProtocolFor( - endpoint_); - - alternate_protocol_mode_ = kDoNotUseAlternateProtocol; - ReturnToStateInitConnection(false /* close connection */); -} - int HttpStreamFactoryImpl::Job::ReconsiderProxyAfterError(int error) { DCHECK(!pac_request_); @@ -1129,7 +1092,7 @@ int HttpStreamFactoryImpl::Job::HandleCertificateError(int error) { ssl_socket->GetSSLInfo(&ssl_info_); // Add the bad certificate to the set of allowed certificates in the - // SSL info object. This data structure will be consulted after calling + // SSL config object. This data structure will be consulted after calling // RestartIgnoringLastError(). And the user will be asked interactively // before RestartIgnoringLastError() is ever called. SSLConfig::CertAndStatus bad_cert; diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h index b466640..a12d108 100644 --- a/net/http/http_stream_factory_impl_job.h +++ b/net/http/http_stream_factory_impl_job.h @@ -5,8 +5,8 @@ #ifndef NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_ #define NET_HTTP_HTTP_STREAM_FACTORY_IMPL_JOB_H_ -#include "base/ref_counted.h" -#include "base/scoped_ptr.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/task.h" #include "net/base/completion_callback.h" #include "net/base/net_log.h" @@ -28,38 +28,47 @@ class HttpProxySocketParams; class HttpStream; class SOCKSSocketParams; class SSLSocketParams; -class TCPSocketParams; +class TransportSocketParams; // An HttpStreamRequestImpl exists for each stream which is in progress of being // created for the StreamFactory. class HttpStreamFactoryImpl::Job { public: Job(HttpStreamFactoryImpl* stream_factory, - HttpNetworkSession* session); + HttpNetworkSession* session, + const HttpRequestInfo& request_info, + const SSLConfig& ssl_config, + const BoundNetLog& net_log); ~Job(); - // Start initiates the process of creating a new HttpStream. - // 3 parameters are passed in by reference. The caller asserts that the - // lifecycle of these parameters will remain valid until the stream is - // created, failed, or destroyed. In the first two cases, the delegate will - // be called to notify completion of the request. - void Start(Request* request, - const HttpRequestInfo& request_info, - const SSLConfig& ssl_config, - const BoundNetLog& net_log); - - int Preconnect(int num_streams, - const HttpRequestInfo& request_info, - const SSLConfig& ssl_config, - const BoundNetLog& net_log); + // Start initiates the process of creating a new HttpStream. |request| will be + // notified upon completion if the Job has not been Orphan()'d. + void Start(Request* request); + + // Preconnect will attempt to request |num_streams| sockets from the + // appropriate ClientSocketPool. + int Preconnect(int num_streams); int RestartTunnelWithProxyAuth(const string16& username, const string16& password); LoadState GetLoadState() const; + // Marks this Job as the "alternate" job, from Alternate-Protocol. Tracks the + // original url so we can mark the Alternate-Protocol as broken if + // we fail to connect. + void MarkAsAlternate(const GURL& original_url); + + // Tells |this| to wait for |job| to resume it. + void WaitFor(Job* job); + + // Tells |this| that |job| has determined it still needs to continue + // connecting, so allow |this| to continue. If this is not called, then + // |request_| is expected to cancel |this| by deleting it. + void Resume(Job* job); + + // Used to detach the Job from |request|. void Orphan(const Request* request); - bool was_alternate_protocol_available() const; bool was_npn_negotiated() const; bool using_spdy() const; const BoundNetLog& net_log() const { return net_log_; } @@ -74,15 +83,28 @@ class HttpStreamFactoryImpl::Job { bool IsOrphaned() const; private: - enum AlternateProtocolMode { - kUnspecified, // Unspecified, check HttpAlternateProtocols - kUsingAlternateProtocol, // Using an alternate protocol - kDoNotUseAlternateProtocol, // Failed to connect once, do not try again. - }; - enum State { STATE_RESOLVE_PROXY, STATE_RESOLVE_PROXY_COMPLETE, + + // Note that when Alternate-Protocol says we can connect to an alternate + // port using a different protocol, we have the choice of communicating over + // the original protocol, or speaking the alternate protocol (currently, + // only npn-spdy) over an alternate port. For a cold page load, the http + // connection that delivers the http response that has the + // Alternate-Protocol header will already be warm. So, blocking the next + // http request on establishing a new npn-spdy connection would incur extra + // latency. Even if the http connection was not reused, establishing a new + // http connection is typically faster than npn-spdy, since npn-spdy + // requires a SSL handshake. Therefore, we start both the http and the + // npn-spdy jobs in parallel. In order not to unnecessarily waste sockets, + // we have the http job block on the npn-spdy job after proxy resolution. + // The npn-spdy job will Resume() the http job if, in + // STATE_INIT_CONNECTION_COMPLETE, it detects an error or does not find an + // existing SpdySession. In that case, the http and npn-spdy jobs will race. + STATE_WAIT_FOR_JOB, + STATE_WAIT_FOR_JOB_COMPLETE, + STATE_INIT_CONNECTION, STATE_INIT_CONNECTION_COMPLETE, STATE_WAITING_USER_ACTION, @@ -110,9 +132,7 @@ class HttpStreamFactoryImpl::Job { void OnIOComplete(int result); int RunLoop(int result); int DoLoop(int result); - int StartInternal(const HttpRequestInfo& request_info, - const SSLConfig& ssl_config, - const BoundNetLog& net_log); + int StartInternal(); // Each of these methods corresponds to a State value. Those with an input // argument receive the result from the previous state. If a method returns @@ -120,6 +140,8 @@ class HttpStreamFactoryImpl::Job { // next state method as the result arg. int DoResolveProxy(); int DoResolveProxyComplete(int result); + int DoWaitForJob(); + int DoWaitForJobComplete(int result); int DoInitConnection(); int DoInitConnectionComplete(int result); int DoWaitingUserAction(int result); @@ -136,15 +158,10 @@ class HttpStreamFactoryImpl::Job { bool IsHttpsProxyAndHttpUrl(); - // Returns a newly create SSLSocketParams, and sets several - // fields of ssl_config_. - scoped_refptr<SSLSocketParams> GenerateSSLParams( - scoped_refptr<TCPSocketParams> tcp_params, - scoped_refptr<HttpProxySocketParams> http_proxy_params, - scoped_refptr<SOCKSSocketParams> socks_params, - ProxyServer::Scheme proxy_scheme, - const HostPortPair& host_and_port, - bool want_spdy_over_npn); +// Sets several fields of ssl_config for the given origin_server based on the +// proxy info and other factors. + void InitSSLConfig(const HostPortPair& origin_server, + SSLConfig* ssl_config) const; // AlternateProtocol API void MarkBrokenAlternateProtocolAndFallback(); @@ -174,31 +191,42 @@ class HttpStreamFactoryImpl::Job { void SwitchToSpdyMode(); // Should we force SPDY to run over SSL for this stream request. - bool ShouldForceSpdySSL(); + bool ShouldForceSpdySSL() const; // Should we force SPDY to run without SSL for this stream request. - bool ShouldForceSpdyWithoutSSL(); + bool ShouldForceSpdyWithoutSSL() const; // Record histograms of latency until Connect() completes. static void LogHttpConnectedMetrics(const ClientSocketHandle& handle); Request* request_; - HttpRequestInfo request_info_; + const HttpRequestInfo request_info_; ProxyInfo proxy_info_; SSLConfig ssl_config_; + const BoundNetLog net_log_; CompletionCallbackImpl<Job> io_callback_; scoped_ptr<ClientSocketHandle> connection_; HttpNetworkSession* const session_; HttpStreamFactoryImpl* const stream_factory_; - BoundNetLog net_log_; State next_state_; ProxyService::PacRequest* pac_request_; SSLInfo ssl_info_; - // The hostname and port of the endpoint. This is not necessarily the one - // specified by the URL, due to Alternate-Protocol or fixed testing ports. - HostPortPair endpoint_; + + // The origin server we're trying to reach. + HostPortPair origin_; + + // If this is a Job for an "Alternate-Protocol", then this will be non-NULL + // and will specify the original URL. + scoped_ptr<GURL> original_url_; + + // This is the Job we're dependent on. It will notify us if/when it's OK to + // proceed. + Job* blocking_job_; + + // |dependent_job_| is dependent on |this|. Notify it when it's ok to proceed. + Job* dependent_job_; // True if handling a HTTPS request, or using SPDY with SSL bool using_ssl_; @@ -218,21 +246,12 @@ class HttpStreamFactoryImpl::Job { scoped_refptr<HttpAuthController> auth_controllers_[HttpAuth::AUTH_NUM_TARGETS]; - AlternateProtocolMode alternate_protocol_mode_; - - // Only valid if |alternate_protocol_mode_| == kUsingAlternateProtocol. - HttpAlternateProtocols::Protocol alternate_protocol_; - // True when the tunnel is in the process of being established - we can't // read from the socket until the tunnel is done. bool establishing_tunnel_; scoped_ptr<HttpStream> stream_; - // True if finding the connection for this request found an alternate - // protocol was available. - bool was_alternate_protocol_available_; - // True if we negotiated NPN. bool was_npn_negotiated_; diff --git a/net/http/http_stream_factory_impl_request.cc b/net/http/http_stream_factory_impl_request.cc index b9e0cee..d8bb09f 100644 --- a/net/http/http_stream_factory_impl_request.cc +++ b/net/http/http_stream_factory_impl_request.cc @@ -21,7 +21,6 @@ HttpStreamFactoryImpl::Request::Request(const GURL& url, delegate_(delegate), net_log_(net_log), completed_(false), - was_alternate_protocol_available_(false), was_npn_negotiated_(false), using_spdy_(false) { DCHECK(factory_); @@ -63,13 +62,11 @@ void HttpStreamFactoryImpl::Request::AttachJob(Job* job) { } void HttpStreamFactoryImpl::Request::Complete( - bool was_alternate_protocol_available, bool was_npn_negotiated, bool using_spdy, const NetLog::Source& job_source) { DCHECK(!completed_); completed_ = true; - was_alternate_protocol_available_ = was_alternate_protocol_available; was_npn_negotiated_ = was_npn_negotiated; using_spdy_ = using_spdy; net_log_.AddEvent( @@ -114,10 +111,23 @@ void HttpStreamFactoryImpl::Request::OnStreamFailed( int status, const SSLConfig& used_ssl_config) { DCHECK_NE(OK, status); - if (!bound_job_.get()) - OrphanJobsExcept(job); - else + if (!bound_job_.get()) { + // Hey, we've got other jobs! Maybe one of them will succeed, let's just + // ignore this failure. + if (jobs_.size() > 1) { + jobs_.erase(job); + factory_->request_map_.erase(job); + delete job; + return; + } else { + bound_job_.reset(job); + jobs_.erase(job); + DCHECK(jobs_.empty()); + factory_->request_map_.erase(job); + } + } else { DCHECK(jobs_.empty()); + } delegate_->OnStreamFailed(status, used_ssl_config); } @@ -189,11 +199,6 @@ LoadState HttpStreamFactoryImpl::Request::GetLoadState() const { return (*jobs_.begin())->GetLoadState(); } -bool HttpStreamFactoryImpl::Request::was_alternate_protocol_available() const { - DCHECK(completed_); - return was_alternate_protocol_available_; -} - bool HttpStreamFactoryImpl::Request::was_npn_negotiated() const { DCHECK(completed_); return was_npn_negotiated_; @@ -238,14 +243,11 @@ void HttpStreamFactoryImpl::Request::OnSpdySessionReady( // Cache these values in case the job gets deleted. const SSLConfig used_ssl_config = job->ssl_config(); const ProxyInfo used_proxy_info = job->proxy_info(); - const bool was_alternate_protocol_available = - job->was_alternate_protocol_available(); const bool was_npn_negotiated = job->was_npn_negotiated(); const bool using_spdy = job->using_spdy(); const NetLog::Source source = job->net_log().source(); - Complete(was_alternate_protocol_available, - was_npn_negotiated, + Complete(was_npn_negotiated, using_spdy, source); @@ -260,7 +262,7 @@ void HttpStreamFactoryImpl::Request::OnSpdySessionReady( // |this| may be deleted after this point. factory->OnSpdySessionReady( spdy_session, direct, used_ssl_config, used_proxy_info, - was_alternate_protocol_available, was_npn_negotiated, using_spdy, source); + was_npn_negotiated, using_spdy, source); } void HttpStreamFactoryImpl::Request::OrphanJobsExcept(Job* job) { diff --git a/net/http/http_stream_factory_impl_request.h b/net/http/http_stream_factory_impl_request.h index 3c1b996..4a7ace4 100644 --- a/net/http/http_stream_factory_impl_request.h +++ b/net/http/http_stream_factory_impl_request.h @@ -6,7 +6,7 @@ #define NET_HTTP_HTTP_STREAM_FACTORY_IMPL_REQUEST_H_ #include <set> -#include "base/scoped_ptr.h" +#include "base/memory/scoped_ptr.h" #include "googleurl/src/gurl.h" #include "net/base/net_log.h" #include "net/http/http_stream_factory_impl.h" @@ -37,8 +37,7 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest { // Marks completion of the request. Must be called before OnStreamReady(). // |source| is the NetLog::Source generated by the Job that fulfilled this // request. - void Complete(bool was_alternate_protocol_available, - bool was_npn_negotiated, + void Complete(bool was_npn_negotiated, bool using_spdy, const NetLog::Source& source); @@ -83,7 +82,6 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest { virtual int RestartTunnelWithProxyAuth(const string16& username, const string16& password); virtual LoadState GetLoadState() const; - virtual bool was_alternate_protocol_available() const; virtual bool was_npn_negotiated() const; virtual bool using_spdy() const; @@ -106,7 +104,6 @@ class HttpStreamFactoryImpl::Request : public HttpStreamRequest { scoped_ptr<const HostPortProxyPair> spdy_session_key_; bool completed_; - bool was_alternate_protocol_available_; bool was_npn_negotiated_; bool using_spdy_; diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc index f316251..b37c173 100644 --- a/net/http/http_stream_factory_impl_unittest.cc +++ b/net/http/http_stream_factory_impl_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -183,8 +183,8 @@ class CapturePreconnectsSocketPool : public ParentPool { int last_num_streams_; }; -typedef CapturePreconnectsSocketPool<TCPClientSocketPool> -CapturePreconnectsTCPSocketPool; +typedef CapturePreconnectsSocketPool<TransportClientSocketPool> +CapturePreconnectsTransportSocketPool; typedef CapturePreconnectsSocketPool<HttpProxyClientSocketPool> CapturePreconnectsHttpProxySocketPool; typedef CapturePreconnectsSocketPool<SOCKSClientSocketPool> @@ -216,11 +216,11 @@ TEST(HttpStreamFactoryTest, PreconnectDirect) { SessionDependencies session_deps(ProxyService::CreateDirect()); scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); HttpNetworkSessionPeer peer(session); - CapturePreconnectsTCPSocketPool* tcp_conn_pool = - new CapturePreconnectsTCPSocketPool( + CapturePreconnectsTransportSocketPool* transport_conn_pool = + new CapturePreconnectsTransportSocketPool( session_deps.host_resolver.get(), session_deps.cert_verifier.get()); - peer.SetTCPSocketPool(tcp_conn_pool); + peer.SetTransportSocketPool(transport_conn_pool); CapturePreconnectsSSLSocketPool* ssl_conn_pool = new CapturePreconnectsSSLSocketPool( session_deps.host_resolver.get(), @@ -230,7 +230,7 @@ TEST(HttpStreamFactoryTest, PreconnectDirect) { if (kTests[i].ssl) EXPECT_EQ(kTests[i].num_streams, ssl_conn_pool->last_num_streams()); else - EXPECT_EQ(kTests[i].num_streams, tcp_conn_pool->last_num_streams()); + EXPECT_EQ(kTests[i].num_streams, transport_conn_pool->last_num_streams()); } } @@ -295,11 +295,11 @@ TEST(HttpStreamFactoryTest, PreconnectDirectWithExistingSpdySession) { scoped_refptr<SpdySession> spdy_session = session->spdy_session_pool()->Get(pair, BoundNetLog()); - CapturePreconnectsTCPSocketPool* tcp_conn_pool = - new CapturePreconnectsTCPSocketPool( + CapturePreconnectsTransportSocketPool* transport_conn_pool = + new CapturePreconnectsTransportSocketPool( session_deps.host_resolver.get(), session_deps.cert_verifier.get()); - peer.SetTCPSocketPool(tcp_conn_pool); + peer.SetTransportSocketPool(transport_conn_pool); CapturePreconnectsSSLSocketPool* ssl_conn_pool = new CapturePreconnectsSSLSocketPool( session_deps.host_resolver.get(), @@ -311,7 +311,7 @@ TEST(HttpStreamFactoryTest, PreconnectDirectWithExistingSpdySession) { if (kTests[i].ssl) EXPECT_EQ(-1, ssl_conn_pool->last_num_streams()); else - EXPECT_EQ(kTests[i].num_streams, tcp_conn_pool->last_num_streams()); + EXPECT_EQ(kTests[i].num_streams, transport_conn_pool->last_num_streams()); } } diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc index eb1ed35..0649bce 100644 --- a/net/http/http_stream_parser.cc +++ b/net/http/http_stream_parser.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -700,6 +700,10 @@ void HttpStreamParser::SetConnectionReused() { connection_->set_is_reused(true); } +bool HttpStreamParser::IsConnectionReusable() const { + return connection_->socket() && connection_->socket()->IsConnectedAndIdle(); +} + void HttpStreamParser::GetSSLInfo(SSLInfo* ssl_info) { if (request_->url.SchemeIs("https") && connection_->socket()) { SSLClientSocket* ssl_socket = diff --git a/net/http/http_stream_parser.h b/net/http/http_stream_parser.h index d9241a6..2192eff 100644 --- a/net/http/http_stream_parser.h +++ b/net/http/http_stream_parser.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -67,6 +67,8 @@ class HttpStreamParser : public ChunkCallback { void SetConnectionReused(); + bool IsConnectionReusable() const; + void GetSSLInfo(SSLInfo* ssl_info); void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info); diff --git a/net/http/http_transaction_factory.h b/net/http/http_transaction_factory.h index 0d0f642..e457828 100644 --- a/net/http/http_transaction_factory.h +++ b/net/http/http_transaction_factory.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,7 +6,7 @@ #define NET_HTTP_HTTP_TRANSACTION_FACTORY_H__ #pragma once -#include "base/scoped_ptr.h" +#include "base/memory/scoped_ptr.h" namespace net { diff --git a/net/http/http_util.cc b/net/http/http_util.cc index fed74b6..f654a99 100644 --- a/net/http/http_util.cc +++ b/net/http/http_util.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -14,12 +14,6 @@ #include "base/string_number_conversions.h" #include "base/string_piece.h" #include "base/string_util.h" -#include "net/base/load_flags.h" -#include "net/base/net_util.h" -#include "net/base/upload_data_stream.h" -#include "net/http/http_request_info.h" -#include "net/http/http_request_headers.h" -#include "net/http/http_auth_controller.h" using std::string; @@ -636,95 +630,6 @@ HttpUtil::HeadersIterator::HeadersIterator(string::const_iterator headers_begin, : lines_(headers_begin, headers_end, line_delimiter) { } -namespace { - -bool HaveAuth(const scoped_refptr<HttpAuthController> auth_controllers[], - HttpAuth::Target target) { - return auth_controllers[target].get() && - auth_controllers[target]->HaveAuth(); -} - -} // namespace - -void HttpUtil::BuildRequestHeaders(const HttpRequestInfo* request_info, - const UploadDataStream* upload_data_stream, - const scoped_refptr<HttpAuthController> - auth_controllers[], - bool should_apply_server_auth, - bool should_apply_proxy_auth, - bool using_proxy, - HttpRequestHeaders* request_headers) { - request_headers->SetHeader(HttpRequestHeaders::kHost, - GetHostAndOptionalPort(request_info->url)); - - // For compat with HTTP/1.0 servers and proxies: - if (using_proxy) { - request_headers->SetHeader(HttpRequestHeaders::kProxyConnection, - "keep-alive"); - } else { - request_headers->SetHeader(HttpRequestHeaders::kConnection, "keep-alive"); - } - - // Our consumer should have made sure that this is a safe referrer. See for - // instance WebCore::FrameLoader::HideReferrer. - if (request_info->referrer.is_valid()) { - request_headers->SetHeader(HttpRequestHeaders::kReferer, - request_info->referrer.spec()); - } - - // Add a content length header? - if (upload_data_stream) { - if (upload_data_stream->is_chunked()) { - request_headers->SetHeader( - HttpRequestHeaders::kTransferEncoding, "chunked"); - } else { - request_headers->SetHeader( - HttpRequestHeaders::kContentLength, - base::Uint64ToString(upload_data_stream->size())); - } - } else if (request_info->method == "POST" || request_info->method == "PUT" || - request_info->method == "HEAD") { - // An empty POST/PUT request still needs a content length. As for HEAD, - // IE and Safari also add a content length header. Presumably it is to - // support sending a HEAD request to an URL that only expects to be sent a - // POST or some other method that normally would have a message body. - request_headers->SetHeader(HttpRequestHeaders::kContentLength, "0"); - } - - // Honor load flags that impact proxy caches. - if (request_info->load_flags & LOAD_BYPASS_CACHE) { - request_headers->SetHeader(HttpRequestHeaders::kPragma, "no-cache"); - request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "no-cache"); - } else if (request_info->load_flags & LOAD_VALIDATE_CACHE) { - request_headers->SetHeader(HttpRequestHeaders::kCacheControl, "max-age=0"); - } - - if (should_apply_proxy_auth && - HaveAuth(auth_controllers, HttpAuth::AUTH_PROXY)) - auth_controllers[HttpAuth::AUTH_PROXY]->AddAuthorizationHeader( - request_headers); - if (should_apply_server_auth && - HaveAuth(auth_controllers, HttpAuth::AUTH_SERVER)) - auth_controllers[HttpAuth::AUTH_SERVER]->AddAuthorizationHeader( - request_headers); - - // Headers that will be stripped from request_info->extra_headers to prevent, - // e.g., plugins from overriding headers that are controlled using other - // means. Otherwise a plugin could set a referrer although sending the - // referrer is inhibited. - // TODO(jochen): check whether also other headers should be stripped. - static const char* const kExtraHeadersToBeStripped[] = { - "Referer" - }; - - HttpRequestHeaders stripped_extra_headers; - stripped_extra_headers.CopyFrom(request_info->extra_headers); - for (size_t i = 0; i < arraysize(kExtraHeadersToBeStripped); ++i) - stripped_extra_headers.RemoveHeader(kExtraHeadersToBeStripped[i]); - request_headers->MergeFrom(stripped_extra_headers); -} - - HttpUtil::HeadersIterator::~HeadersIterator() { } diff --git a/net/http/http_util.h b/net/http/http_util.h index 3da1635..91ea9c3 100644 --- a/net/http/http_util.h +++ b/net/http/http_util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,7 +9,7 @@ #include <string> #include <vector> -#include "base/ref_counted.h" +#include "base/memory/ref_counted.h" #include "base/string_tokenizer.h" #include "googleurl/src/gurl.h" #include "net/http/http_byte_range.h" @@ -20,10 +20,6 @@ namespace net { -class HttpAuthController; -struct HttpRequestInfo; -class HttpRequestHeaders; -class HttpStream; class UploadDataStream; class HttpUtil { @@ -164,19 +160,6 @@ class HttpUtil { const std::string& header_value, std::string* headers); - // Constructs |request_headers| from the information contained in - // |request_info|. The correct server and proxy auth headers will - // be populated from |auth_controllers| if |enable_server_auth| or - // |enable_proxy_auth| is true. - static void BuildRequestHeaders(const HttpRequestInfo* request_info, - const UploadDataStream* upload_data_stream, - const scoped_refptr<HttpAuthController> - auth_controllers[], - bool enable_server_auth, - bool enable_proxy_auth, - bool enable_full_url, - HttpRequestHeaders* request_headers); - // Used to iterate over the name/value pairs of HTTP headers. To iterate // over the values in a multi-value header, use ValuesIterator. // See AssembleRawHeaders for joining line continuations (this iterator diff --git a/net/http/partial_data.cc b/net/http/partial_data.cc index c1f448e..d76d689 100644 --- a/net/http/partial_data.cc +++ b/net/http/partial_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -273,6 +273,9 @@ bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers, return true; } + if (!headers->HasStrongValidators()) + return false; + int64 length_value = headers->GetContentLength(); if (length_value <= 0) return false; // We must have stored the resource length. diff --git a/net/http/url_security_manager.h b/net/http/url_security_manager.h index 119d6bd..2692252 100644 --- a/net/http/url_security_manager.h +++ b/net/http/url_security_manager.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,8 +6,8 @@ #define NET_HTTP_URL_SECURITY_MANAGER_H_ #pragma once -#include "base/scoped_ptr.h" #include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" class GURL; diff --git a/net/http/url_security_manager_win.cc b/net/http/url_security_manager_win.cc index 1770a19..858cc50 100644 --- a/net/http/url_security_manager_win.cc +++ b/net/http/url_security_manager_win.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,9 +7,9 @@ #include <urlmon.h> #pragma comment(lib, "urlmon.lib") -#include "base/scoped_comptr_win.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "base/win/scoped_comptr.h" #include "googleurl/src/gurl.h" #include "net/http/http_auth_filter.h" @@ -37,7 +37,7 @@ class URLSecurityManagerWin : public URLSecurityManager { private: bool EnsureSystemSecurityManager(); - ScopedComPtr<IInternetSecurityManager> security_manager_; + base::win::ScopedComPtr<IInternetSecurityManager> security_manager_; scoped_ptr<const HttpAuthFilter> whitelist_delegate_; DISALLOW_COPY_AND_ASSIGN(URLSecurityManagerWin); |