diff options
23 files changed, 20 insertions, 2713 deletions
diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc index 6a5b879..21e93e7 100644 --- a/chrome/browser/browser_main.cc +++ b/chrome/browser/browser_main.cc @@ -147,9 +147,9 @@ StringPiece NetResourceProvider(int key) { // Main routine for running as the Browser process. int BrowserMain(const MainFunctionParams& parameters) { CommandLine& parsed_command_line = parameters.command_line_; - sandbox::BrokerServices* broker_services = + sandbox::BrokerServices* broker_services = parameters.sandbox_info_.BrokerServices(); - + // WARNING: If we get a WM_ENDSESSION objects created on the stack here // are NOT deleted. If you need something to run during WM_ENDSESSION add it // to browser_shutdown::Shutdown or BrowserProcess::EndSession. @@ -180,13 +180,6 @@ int BrowserMain(const MainFunctionParams& parameters) { main_message_loop.set_thread_name(thread_name); bool already_running = Upgrade::IsBrowserAlreadyRunning(); -#if defined(OS_WIN) - // Make the selection of network stacks early on before any consumers try to - // issue HTTP requests. - if (parsed_command_line.HasSwitch(switches::kUseWinHttp)) - net::HttpNetworkLayer::UseWinHttp(true); -#endif - std::wstring user_data_dir; PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); BrowserInit::MessageWindow message_window(user_data_dir); diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index cc390da..046b7ea 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -315,9 +315,6 @@ const wchar_t kGearsPluginPathOverride[] = L"gears-plugin-path"; // Switch to load Gears in the renderer process. const wchar_t kGearsInRenderer[] = L"gears-in-renderer"; -// Enable winhttp HTTP stack. -const wchar_t kUseWinHttp[] = L"winhttp"; - // Enable the fastback page cache. const wchar_t kEnableFastback[] = L"enable-fastback"; @@ -346,7 +343,7 @@ const wchar_t kIncognito[] = L"incognito"; // problems on some computers during updates. const wchar_t kUseOldSafeBrowsing[] = L"old-safe-browsing"; -// Turns on the accessibility in the renderer. Off by default until +// Turns on the accessibility in the renderer. Off by default until // http://b/issue?id=1432077 is fixed. const wchar_t kEnableRendererAccessibility[] = L"enable-renderer-accessibility"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index acd84a7..e712596 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -119,8 +119,6 @@ extern const wchar_t kGearsPluginPathOverride[]; extern const wchar_t kGearsInRenderer[]; -extern const wchar_t kUseWinHttp[]; - extern const wchar_t kEnableFastback[]; extern const wchar_t kJavaScriptDebuggerPath[]; diff --git a/net/build/net.vcproj b/net/build/net.vcproj index 275d7fd..5a71089 100644 --- a/net/build/net.vcproj +++ b/net/build/net.vcproj @@ -685,14 +685,6 @@ Name="http" > <File - RelativePath="..\http\cert_status_cache.cc" - > - </File> - <File - RelativePath="..\http\cert_status_cache.h" - > - </File> - <File RelativePath="..\http\http_atom_list.h" > </File> @@ -757,14 +749,6 @@ > </File> <File - RelativePath="..\http\http_transaction_winhttp.cc" - > - </File> - <File - RelativePath="..\http\http_transaction_winhttp.h" - > - </File> - <File RelativePath="..\http\http_util.cc" > </File> @@ -852,14 +836,6 @@ RelativePath="..\http\http_vary_data.h" > </File> - <File - RelativePath="..\http\winhttp_request_throttle.cc" - > - </File> - <File - RelativePath="..\http\winhttp_request_throttle.h" - > - </File> </Filter> <Filter Name="disk_cache" diff --git a/net/build/net_unittests.vcproj b/net/build/net_unittests.vcproj index 0180e11..c28bc20 100644 --- a/net/build/net_unittests.vcproj +++ b/net/build/net_unittests.vcproj @@ -271,10 +271,6 @@ > </File> <File - RelativePath="..\http\http_transaction_winhttp_unittest.cc" - > - </File> - <File RelativePath="..\http\http_util_unittest.cc" > </File> @@ -282,10 +278,6 @@ RelativePath="..\http\http_vary_data_unittest.cc" > </File> - <File - RelativePath="..\http\winhttp_request_throttle_unittest.cc" - > - </File> </Filter> <Filter Name="base" diff --git a/net/http/cert_status_cache.cc b/net/http/cert_status_cache.cc deleted file mode 100644 index 12e5723..0000000 --- a/net/http/cert_status_cache.cc +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2006-2008 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/base/cert_status_flags.h" -#include "net/http/cert_status_cache.h" - -namespace net { - -CertStatusCache::CertStatusCache() { -} - -CertStatusCache::~CertStatusCache() { - for (HostMap::iterator iter = fingerprint_to_bad_hosts_.begin(); - iter != fingerprint_to_bad_hosts_.end(); ++iter) { - delete iter->second; - } -} - -int CertStatusCache::GetCertStatus(const X509Certificate& cert, - const std::string& host) const { - StatusMap::const_iterator iter = - fingerprint_to_cert_status_.find(cert.fingerprint()); - if (iter != fingerprint_to_cert_status_.end()) { - int cert_status = iter->second; - - // We get the CERT_STATUS_COMMON_NAME_INVALID error based on the host. - HostMap::const_iterator fp_iter = - fingerprint_to_bad_hosts_.find(cert.fingerprint()); - if (fp_iter != fingerprint_to_bad_hosts_.end()) { - StringSet* bad_hosts = fp_iter->second; - StringSet::const_iterator host_iter = bad_hosts->find(host); - if (host_iter != bad_hosts->end()) - cert_status |= net::CERT_STATUS_COMMON_NAME_INVALID; - } - - return cert_status; - } - return 0; // The cert has never had errors. -} - -void CertStatusCache::SetCertStatus(const X509Certificate& cert, - const std::string& host, - int status) { - // We store the CERT_STATUS_COMMON_NAME_INVALID status separately as it is - // host related. - fingerprint_to_cert_status_[cert.fingerprint()] = - status & ~net::CERT_STATUS_COMMON_NAME_INVALID; - - if ((status & net::CERT_STATUS_COMMON_NAME_INVALID) != 0) { - StringSet* bad_hosts; - HostMap::const_iterator iter = - fingerprint_to_bad_hosts_.find(cert.fingerprint()); - if (iter == fingerprint_to_bad_hosts_.end()) { - bad_hosts = new StringSet; - fingerprint_to_bad_hosts_[cert.fingerprint()] = bad_hosts; - } else { - bad_hosts = iter->second; - } - bad_hosts->insert(host); - } -} - -} - diff --git a/net/http/cert_status_cache.h b/net/http/cert_status_cache.h deleted file mode 100644 index eb0a5c3..0000000 --- a/net/http/cert_status_cache.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2006-2008 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. - -#ifndef NET_HTTP_CERT_STATUS_CACHE_H -#define NET_HTTP_CERT_STATUS_CACHE_H - -#include <vector> -#include <map> - -#include "net/base/x509_certificate.h" - -// This class is used to remember the status of certificates, as WinHTTP -// does not report errors once it has been told to ignore them. -// It only exists because of the WinHTTP bug. -// IMPORTANT: this class is not thread-safe. - -namespace net { - -class CertStatusCache { - public: - CertStatusCache(); - ~CertStatusCache(); - - int GetCertStatus(const X509Certificate& cert, - const std::string& host_name) const; - void SetCertStatus(const X509Certificate& cert, - const std::string& host_name, - int status); - - private: - typedef std::map<X509Certificate::Fingerprint, int, - X509Certificate::FingerprintLessThan> StatusMap; - typedef std::set<std::string> StringSet; - typedef std::map<X509Certificate::Fingerprint, StringSet*, - X509Certificate::FingerprintLessThan> HostMap; - - StatusMap fingerprint_to_cert_status_; - - // We keep a map for each cert to the list of host names that have been marked - // with the CN invalid error, as that error is host name specific. - HostMap fingerprint_to_bad_hosts_; - - DISALLOW_EVIL_CONSTRUCTORS(CertStatusCache); -}; - -} // namespace net - -#endif // NET_HTTP_CERT_STATUS_CACHE_H - diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc index 2b84682..23f53f7 100644 --- a/net/http/http_network_layer.cc +++ b/net/http/http_network_layer.cc @@ -8,38 +8,19 @@ #include "net/base/client_socket_factory.h" #include "net/http/http_network_session.h" #include "net/http/http_network_transaction.h" -#if defined(OS_WIN) -#include "net/http/http_transaction_winhttp.h" -#endif namespace net { //----------------------------------------------------------------------------- -#if defined(OS_WIN) -// static -bool HttpNetworkLayer::use_winhttp_ = false; -#endif - // static HttpTransactionFactory* HttpNetworkLayer::CreateFactory( ProxyService* proxy_service) { DCHECK(proxy_service); -#if defined(OS_WIN) - if (use_winhttp_) - return new HttpTransactionWinHttp::Factory(proxy_service); -#endif return new HttpNetworkLayer(proxy_service); } -#if defined(OS_WIN) -// static -void HttpNetworkLayer::UseWinHttp(bool value) { - use_winhttp_ = value; -} -#endif - //----------------------------------------------------------------------------- HttpNetworkLayer::HttpNetworkLayer(ProxyService* proxy_service) diff --git a/net/http/http_network_layer.h b/net/http/http_network_layer.h index 5364642..8424b2f 100644 --- a/net/http/http_network_layer.h +++ b/net/http/http_network_layer.h @@ -25,21 +25,12 @@ class HttpNetworkLayer : public HttpTransactionFactory { // and allows other implementations to be substituted. static HttpTransactionFactory* CreateFactory(ProxyService* proxy_service); -#if defined(OS_WIN) - // If value is true, then WinHTTP will be used. - static void UseWinHttp(bool value); -#endif - // HttpTransactionFactory methods: virtual HttpTransaction* CreateTransaction(); virtual HttpCache* GetCache(); virtual void Suspend(bool suspend); private: -#if defined(OS_WIN) - static bool use_winhttp_; -#endif - // The proxy service being used for the session. ProxyService* proxy_service_; diff --git a/net/http/http_transaction_winhttp.cc b/net/http/http_transaction_winhttp.cc deleted file mode 100644 index 06cd391..0000000 --- a/net/http/http_transaction_winhttp.cc +++ /dev/null @@ -1,1827 +0,0 @@ -// Copyright (c) 2006-2008 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_transaction_winhttp.h" - -#include <winhttp.h> - -#include "base/lock.h" -#include "base/memory_debug.h" -#include "base/message_loop.h" -#include "base/string_piece.h" -#include "base/string_util.h" -#include "base/sys_string_conversions.h" -#include "googleurl/src/gurl.h" -#include "net/base/auth_cache.h" -#include "net/base/cert_status_flags.h" -#include "net/base/dns_resolution_observer.h" -#include "net/base/load_flags.h" -#include "net/base/net_errors.h" -#include "net/base/net_util.h" -#include "net/base/ssl_config_service.h" -#include "net/base/upload_data_stream.h" -#include "net/http/cert_status_cache.h" -#include "net/http/http_request_info.h" -#include "net/http/winhttp_request_throttle.h" -#include "net/proxy/proxy_resolver_winhttp.h" - -#pragma comment(lib, "winhttp.lib") -#pragma warning(disable: 4355) - -using base::Time; - -namespace net { - -static int TranslateOSError(DWORD error) { - switch (error) { - case ERROR_SUCCESS: - return OK; - case ERROR_FILE_NOT_FOUND: - return ERR_FILE_NOT_FOUND; - case ERROR_HANDLE_EOF: // TODO(wtc): return OK? - return ERR_CONNECTION_CLOSED; - case ERROR_INVALID_HANDLE: - return ERR_INVALID_HANDLE; - case ERROR_INVALID_PARAMETER: - return ERR_INVALID_ARGUMENT; - - case ERROR_WINHTTP_CANNOT_CONNECT: - return ERR_CONNECTION_FAILED; - case ERROR_WINHTTP_TIMEOUT: - return ERR_TIMED_OUT; - case ERROR_WINHTTP_INVALID_URL: - return ERR_INVALID_URL; - case ERROR_WINHTTP_NAME_NOT_RESOLVED: - return ERR_NAME_NOT_RESOLVED; - case ERROR_WINHTTP_OPERATION_CANCELLED: - return ERR_ABORTED; - case ERROR_WINHTTP_SECURE_CHANNEL_ERROR: - case ERROR_WINHTTP_SECURE_FAILURE: - case SEC_E_ILLEGAL_MESSAGE: - return ERR_SSL_PROTOCOL_ERROR; - case SEC_E_ALGORITHM_MISMATCH: - return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; - case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED: - return ERR_SSL_CLIENT_AUTH_CERT_NEEDED; - case ERROR_WINHTTP_UNRECOGNIZED_SCHEME: - return ERR_UNKNOWN_URL_SCHEME; - case ERROR_WINHTTP_INVALID_SERVER_RESPONSE: - return ERR_INVALID_RESPONSE; - - // SSL certificate errors - case ERROR_WINHTTP_SECURE_CERT_CN_INVALID: - return ERR_CERT_COMMON_NAME_INVALID; - case ERROR_WINHTTP_SECURE_CERT_DATE_INVALID: - return ERR_CERT_DATE_INVALID; - case ERROR_WINHTTP_SECURE_INVALID_CA: - return ERR_CERT_AUTHORITY_INVALID; - case ERROR_WINHTTP_SECURE_CERT_REV_FAILED: - return ERR_CERT_UNABLE_TO_CHECK_REVOCATION; - case ERROR_WINHTTP_SECURE_CERT_REVOKED: - return ERR_CERT_REVOKED; - case ERROR_WINHTTP_SECURE_INVALID_CERT: - return ERR_CERT_INVALID; - - default: - DCHECK(error != ERROR_IO_PENDING); // WinHTTP doesn't use this error. - LOG(WARNING) << "Unknown error " << error - << " mapped to net::ERR_FAILED"; - return ERR_FAILED; - } -} - -static int TranslateLastOSError() { - return TranslateOSError(GetLastError()); -} - -// Clear certificate errors that we want to ignore. -static DWORD FilterSecureFailure(DWORD status, int load_flags) { - if (load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID) - status &= ~WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID; - if (load_flags & LOAD_IGNORE_CERT_DATE_INVALID) - status &= ~WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID; - if (load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID) - status &= ~WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA; - if (load_flags & LOAD_IGNORE_CERT_WRONG_USAGE) - status &= ~WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE; - return status; -} - -static DWORD MapSecureFailureToError(DWORD status) { - // A certificate may have multiple errors. We report the most - // serious error. - - // Unrecoverable errors - if (status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR) - return ERROR_WINHTTP_SECURE_CHANNEL_ERROR; - if (status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT) - return ERROR_WINHTTP_SECURE_INVALID_CERT; - if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED) - return ERROR_WINHTTP_SECURE_CERT_REVOKED; - - // Recoverable errors - if (status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA) - return ERROR_WINHTTP_SECURE_INVALID_CA; - if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID) - return ERROR_WINHTTP_SECURE_CERT_CN_INVALID; - if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID) - return ERROR_WINHTTP_SECURE_CERT_DATE_INVALID; - if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE) - return ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE; - - // Unknown status. Give it the benefit of the doubt. - if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED) - return ERROR_WINHTTP_SECURE_CERT_REV_FAILED; - - // Map a status of 0 to the generic secure failure error. We have seen a - // case where WinHttp doesn't notify us of a secure failure (so status is 0) - // before notifying us of a request error with ERROR_WINHTTP_SECURE_FAILURE. - // (WinInet fails with ERROR_INTERNET_SECURITY_CHANNEL_ERROR in that case.) - return ERROR_WINHTTP_SECURE_FAILURE; -} - -static int MapSecureFailureToCertStatus(DWORD status) { - int cert_status = 0; - - if (status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT) - cert_status |= CERT_STATUS_INVALID; - if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED) - cert_status |= CERT_STATUS_REVOKED; - if (status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA) - cert_status |= CERT_STATUS_AUTHORITY_INVALID; - if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID) - cert_status |= CERT_STATUS_COMMON_NAME_INVALID; - if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID) - cert_status |= CERT_STATUS_DATE_INVALID; - if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED) - cert_status |= CERT_STATUS_UNABLE_TO_CHECK_REVOCATION; - - return cert_status; - // TODO(jcampan): what about ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE? -} - -// Session -------------------------------------------------------------------- - -class HttpTransactionWinHttp::Session - : public base::RefCounted<HttpTransactionWinHttp::Session> { - public: - enum { - // By default WinHTTP enables only SSL3 and TLS1. - SECURE_PROTOCOLS_SSL3_TLS1 = WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 | - WINHTTP_FLAG_SECURE_PROTOCOL_TLS1 - }; - - explicit Session(ProxyService* proxy_service); - - // Opens the primary WinHttp session handle. - bool Init(const std::string& user_agent); - - // Opens the alternative WinHttp session handle for TLS-intolerant servers. - bool InitNoTLS(const std::string& user_agent); - - void AddRefBySessionCallback(); - - void ReleaseBySessionCallback(); - - // The primary WinHttp session handle. - HINTERNET internet() { return internet_; } - - // An alternative WinHttp session handle. It is not opened until we have - // encountered a TLS-intolerant server and used for those servers only. - // TLS is disabled in this session. - HINTERNET internet_no_tls() { return internet_no_tls_; } - - // The message loop of the thread where the session was created. - MessageLoop* message_loop() { return message_loop_; } - - ProxyService* proxy_service() { return proxy_service_; } - - // Gets the HTTP authentication cache for the session. - AuthCache* auth_cache() { return &auth_cache_; } - - HANDLE handle_closing_event() const { return handle_closing_event_; } - - CertStatusCache* cert_status_cache() { return &cert_status_cache_; } - - bool rev_checking_enabled() const { return rev_checking_enabled_; } - - bool tls_enabled() const { - return (secure_protocols_ & WINHTTP_FLAG_SECURE_PROTOCOL_TLS1) != 0; - } - - bool ShouldIgnoreCertRev(const std::string& origin) const { - OriginSet::const_iterator pos = ignore_cert_rev_servers_.find(origin); - return pos != ignore_cert_rev_servers_.end(); - } - - void IgnoreCertRev(const std::string& origin) { - ignore_cert_rev_servers_.insert(origin); - } - - WinHttpRequestThrottle* request_throttle() { - return &request_throttle_; - } - - private: - friend class base::RefCounted<HttpTransactionWinHttp::Session>; - - ~Session(); - - // Called by the destructor only. - void WaitUntilCallbacksAllDone(); - - HINTERNET OpenWinHttpSession(const std::string& user_agent); - - // Get the SSL configuration settings and save them in rev_checking_enabled_ - // and secure_protocols_. - void GetSSLConfig(); - - HINTERNET internet_; - HINTERNET internet_no_tls_; - MessageLoop* message_loop_; - ProxyService* proxy_service_; - AuthCache auth_cache_; - - // This event object is used when destroying a transaction. It is given - // to the transaction's session callback if WinHTTP still has the caller's - // data (request info or read buffer) and we need to wait until WinHTTP is - // done with the data. - HANDLE handle_closing_event_; - - // The following members ensure a clean destruction of the Session object. - // The Session destructor waits until all the request handles have been - // terminated by WinHTTP, at which point no more status callbacks will - // reference the MessageLoop of the Session. - // - // quit_event_ is the event object used for this wait. - // - // lock_ protects session_callback_ref_count_ and quitting_. - // - // session_callback_ref_count_ is the number of SessionCallback objects - // that may reference the MessageLoop of the Session. - // - // The boolean quitting_ is true when the Session object is being - // destructed. - HANDLE quit_event_; - Lock lock_; - int session_callback_ref_count_; - bool quitting_; - - // We use a cache to store the certificate error as we cannot always rely on - // WinHTTP to provide us the SSL error once we restarted a connection asking - // to ignored errors. - CertStatusCache cert_status_cache_; - - // SSL settings - bool rev_checking_enabled_; - DWORD secure_protocols_; - - // The servers for which certificate revocation should be ignored. - // - // WinHTTP verifies each certificate only once and caches the certificate - // verification results, so if we ever ignore certificate revocation for a - // server, we cannot enable revocation checking again for that server for - // the rest of the session. - // - // If we honor changes to the rev_checking_enabled system setting during - // the session, we will have to remember all the servers we have visited - // while the rev_checking_enabled setting is false. This will consume a - // lot of memory. So we now require the users to restart Chrome for a - // rev_checking_enabled change to take effect, just like IE does. - typedef std::set<std::string> OriginSet; - OriginSet ignore_cert_rev_servers_; - - WinHttpRequestThrottle request_throttle_; -}; - -HttpTransactionWinHttp::Session::Session(ProxyService* proxy_service) - : internet_(NULL), - internet_no_tls_(NULL), - proxy_service_(proxy_service), - session_callback_ref_count_(0), - quitting_(false) { - GetSSLConfig(); - - // Save the current message loop for callback notifications. - message_loop_ = MessageLoop::current(); - - handle_closing_event_ = CreateEvent(NULL, - FALSE, // auto-reset - FALSE, // initially nonsignaled - NULL); // unnamed - - quit_event_ = CreateEvent(NULL, - FALSE, // auto-reset - FALSE, // initially nonsignaled - NULL); // unnamed -} - -HttpTransactionWinHttp::Session::~Session() { - if (internet_) { - WinHttpCloseHandle(internet_); - if (internet_no_tls_) - WinHttpCloseHandle(internet_no_tls_); - - // Ensure that all status callbacks that may reference the MessageLoop - // of this thread are done before we can allow the current thread to exit. - WaitUntilCallbacksAllDone(); - } - - if (handle_closing_event_) - CloseHandle(handle_closing_event_); - if (quit_event_) - CloseHandle(quit_event_); -} - -bool HttpTransactionWinHttp::Session::Init(const std::string& user_agent) { - DCHECK(!internet_); - - internet_ = OpenWinHttpSession(user_agent); - - if (!internet_) - return false; - - if (secure_protocols_ != SECURE_PROTOCOLS_SSL3_TLS1) { - BOOL rv = WinHttpSetOption(internet_, WINHTTP_OPTION_SECURE_PROTOCOLS, - &secure_protocols_, sizeof(secure_protocols_)); - DCHECK(rv); - } - - return true; -} - -bool HttpTransactionWinHttp::Session::InitNoTLS( - const std::string& user_agent) { - DCHECK(tls_enabled()); - DCHECK(internet_); - DCHECK(!internet_no_tls_); - - internet_no_tls_ = OpenWinHttpSession(user_agent); - - if (!internet_no_tls_) - return false; - - DWORD protocols = secure_protocols_ & ~WINHTTP_FLAG_SECURE_PROTOCOL_TLS1; - BOOL rv = WinHttpSetOption(internet_no_tls_, - WINHTTP_OPTION_SECURE_PROTOCOLS, - &protocols, sizeof(protocols)); - DCHECK(rv); - - return true; -} - -void HttpTransactionWinHttp::Session::AddRefBySessionCallback() { - AutoLock lock(lock_); - session_callback_ref_count_++; -} - -void HttpTransactionWinHttp::Session::ReleaseBySessionCallback() { - bool need_to_signal; - { - AutoLock lock(lock_); - session_callback_ref_count_--; - need_to_signal = (quitting_ && session_callback_ref_count_ == 0); - } - if (need_to_signal) - SetEvent(quit_event_); -} - -// This is called by the Session destructor only. By now the transaction -// factory and all the transactions have been destructed. This means that -// new transactions can't be created, and existing transactions can't be -// started, which in turn implies that session_callback_ref_count_ cannot -// increase. We wait until session_callback_ref_count_ drops to 0. -void HttpTransactionWinHttp::Session::WaitUntilCallbacksAllDone() { - bool need_to_wait; - { - AutoLock lock(lock_); - quitting_ = true; - need_to_wait = (session_callback_ref_count_ != 0); - } - if (need_to_wait) - WaitForSingleObject(quit_event_, INFINITE); - DCHECK(session_callback_ref_count_ == 0); -} - -HINTERNET HttpTransactionWinHttp::Session::OpenWinHttpSession( - const std::string& user_agent) { - // Proxy config will be set explicitly for each request. - // - // Although UA string will also be set explicitly for each request, HTTP - // CONNECT requests use the UA string of the session handle, so we have to - // pass a UA string to WinHttpOpen. - HINTERNET internet = WinHttpOpen(ASCIIToWide(user_agent).c_str(), - WINHTTP_ACCESS_TYPE_NO_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - WINHTTP_FLAG_ASYNC); - if (!internet) - return internet; - - // Use a 90-second timeout (1.5 times the default) for connect. Disable - // name resolution, send, and receive timeouts. We expect our consumer to - // apply timeouts or provide controls for users to stop requests that are - // taking too long. - BOOL rv = WinHttpSetTimeouts(internet, 0, 90000, 0, 0); - DCHECK(rv); - - return internet; -} - -void HttpTransactionWinHttp::Session::GetSSLConfig() { - SSLConfig ssl_config; - SSLConfigService::GetSSLConfigNow(&ssl_config); - rev_checking_enabled_ = ssl_config.rev_checking_enabled; - secure_protocols_ = 0; - if (ssl_config.ssl2_enabled) - secure_protocols_ |= WINHTTP_FLAG_SECURE_PROTOCOL_SSL2; - if (ssl_config.ssl3_enabled) - secure_protocols_ |= WINHTTP_FLAG_SECURE_PROTOCOL_SSL3; - if (ssl_config.tls1_enabled) - secure_protocols_ |= WINHTTP_FLAG_SECURE_PROTOCOL_TLS1; -} - -// SessionCallback ------------------------------------------------------------ - -class HttpTransactionWinHttp::SessionCallback - : public base::RefCountedThreadSafe<HttpTransactionWinHttp::SessionCallback> { - public: - SessionCallback(HttpTransactionWinHttp* trans, Session* session) - : trans_(trans), - session_(session), - load_state_(LOAD_STATE_IDLE), - handle_closing_event_(NULL), - bytes_available_(0), - read_buf_(NULL), - read_buf_len_(0), - secure_failure_(0), - connection_was_opened_(false), - request_was_probably_sent_(false), - response_was_received_(false), - response_is_empty_(true) { - } - - // Called when the associated trans_ has to reopen its connection and - // request handles to recover from certain SSL errors. Resets the members - // that may have been modified at that point. - void ResetForNewRequest() { - secure_failure_ = 0; - connection_was_opened_ = false; - } - - void DropTransaction() { - trans_ = NULL; - } - - void Notify(DWORD status, DWORD_PTR result, DWORD error) { - DWORD secure_failure = 0; - if (status == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) { - switch (error) { - // WinHttp sends this error code in two interesting cases: 1) when a - // response header is malformed, and 2) when a response is empty. In - // the latter case, we want to actually resend the request if the - // request was sent over a reused "keep-alive" connection. This is a - // risky thing to do since it is possible that the server did receive - // our request, but it is unfortunately required to support HTTP keep- - // alive connections properly, and other browsers all do this too. - case ERROR_WINHTTP_INVALID_SERVER_RESPONSE: - if (empty_response_was_received() && !connection_was_opened_) - error = ERROR_WINHTTP_RESEND_REQUEST; - break; - case ERROR_WINHTTP_SECURE_FAILURE: - secure_failure = secure_failure_; - break; - } - } else if (status == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE) { - secure_failure = secure_failure_; - } - session_->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, - &HttpTransactionWinHttp::SessionCallback::OnNotify, - status, result, error, secure_failure)); - } - - // Calls WinHttpReadData and returns its return value. - BOOL ReadData(HINTERNET request_handle); - - void OnHandleClosing() { - if (handle_closing_event_) - SetEvent(handle_closing_event_); - session_->ReleaseBySessionCallback(); - Release(); - } - - // Modified from any thread. - void set_load_state(LoadState state) { - load_state_ = state; - } - LoadState load_state() const { - return load_state_; - } - - int bytes_available() const { return bytes_available_; } - void set_bytes_available(int n) { bytes_available_ = n; } - void reduce_bytes_available(int n) { bytes_available_ -= n; } - - char* read_buf() const { return read_buf_; } - void set_read_buf(char* buf) { read_buf_ = buf; } - - int read_buf_len() const { return read_buf_len_; } - void set_read_buf_len(int buf_len) { read_buf_len_ = buf_len; } - - // Tells this SessionCallback to signal this event when receiving the - // handle closing status callback. - void set_handle_closing_event(HANDLE event) { - handle_closing_event_ = event; - } - - void set_secure_failure(DWORD flags) { secure_failure_ = flags; } - - void did_open_connection() { - connection_was_opened_ = true; - } - - void did_start_sending_request() { - request_was_probably_sent_ = true; - } - bool request_was_probably_sent() const { - return request_was_probably_sent_; - } - - void did_receive_bytes(DWORD count) { - response_was_received_ = true; - if (count) - response_is_empty_ = false; - } - - private: - friend base::RefCountedThreadSafe<HttpTransactionWinHttp::SessionCallback>; - ~SessionCallback() {} - - void OnNotify(DWORD status, - DWORD_PTR result, - DWORD error, - DWORD secure_failure) { - if (trans_) - trans_->HandleStatusCallback(status, result, error, secure_failure); - - // Balances the AddRefs made by the transaction object after an async - // WinHTTP call. - Release(); - } - - bool empty_response_was_received() const { - return response_was_received_ && response_is_empty_; - } - - HttpTransactionWinHttp* trans_; - - // Session is reference-counted, but this is a plain pointer. The - // reference on the Session owned by SessionCallback is managed using - // Session::AddRefBySessionCallback and Session::ReleaseBySessionCallback. - Session* session_; - - // Modified from any thread. - volatile LoadState load_state_; - - // Amount of data available reported by WinHttpQueryDataAvailable that - // haven't been consumed by WinHttpReadData. - int bytes_available_; - - // Caller's read buffer and buffer size, to be passed to WinHttpReadData. - // These are used by the IO thread and the thread WinHTTP uses to make - // status callbacks, but not at the same time. - char* read_buf_; - int read_buf_len_; - - // If not null, we set this event on receiving the handle closing callback. - HANDLE handle_closing_event_; - - // The secure connection failure flags reported by the - // WINHTTP_CALLBACK_STATUS_SECURE_FAILURE status callback. - DWORD secure_failure_; - - // True if a connection was opened for this request. - bool connection_was_opened_; - - // True if the request may have been sent to the server (and therefore we - // should not restart the request). - bool request_was_probably_sent_; - - // True if any response was received. - bool response_was_received_; - - // True if we have an empty response (no headers, no status line, nothing). - bool response_is_empty_; -}; - -BOOL HttpTransactionWinHttp::SessionCallback::ReadData( - HINTERNET request_handle) { - DCHECK(bytes_available_ >= 0); - char* buf = read_buf_; - read_buf_ = NULL; - int bytes_to_read = std::min(bytes_available_, read_buf_len_); - read_buf_len_ = 0; - if (!bytes_to_read) - bytes_to_read = 1; - - // Because of how WinHTTP fills memory when used asynchronously, Purify isn't - // able to detect that it's been initialized, so it scans for 0xcd in the - // buffer and reports UMRs (uninitialized memory reads) for those individual - // bytes. We override that to avoid the false error reports. - // See http://b/issue?id=1173916. - base::MemoryDebug::MarkAsInitialized(buf, bytes_to_read); - return WinHttpReadData(request_handle, buf, bytes_to_read, NULL); -} - -// static -void HttpTransactionWinHttp::StatusCallback(HINTERNET handle, - DWORD_PTR context, - DWORD status, - LPVOID status_info, - DWORD status_info_len) { - SessionCallback* callback = reinterpret_cast<SessionCallback*>(context); - - switch (status) { - case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING: - if (callback) - callback->OnHandleClosing(); - break; - case WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER: - callback->set_load_state(LOAD_STATE_CONNECTING); - break; - case WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER: - callback->did_open_connection(); - break; - case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: - callback->set_load_state(LOAD_STATE_SENDING_REQUEST); - callback->did_start_sending_request(); - break; - case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE: - callback->set_load_state(LOAD_STATE_WAITING_FOR_RESPONSE); - break; - case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED: - callback->did_receive_bytes(*static_cast<DWORD*>(status_info)); - break; - case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE: - DCHECK(callback->bytes_available() == 0); - DCHECK(status_info_len == sizeof(DWORD)); - callback->set_bytes_available(static_cast<DWORD*>(status_info)[0]); - if (!callback->ReadData(handle)) - callback->Notify(WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, - API_READ_DATA, GetLastError()); - break; - case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: - callback->Notify(status, status_info_len, 0); - break; - case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: - DCHECK(status_info_len == sizeof(DWORD)); - callback->Notify(status, static_cast<DWORD*>(status_info)[0], 0); - break; - case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: - callback->Notify(status, TRUE, 0); - break; - case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: - callback->Notify(status, TRUE, 0); - break; - case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR: { - WINHTTP_ASYNC_RESULT* result = - static_cast<WINHTTP_ASYNC_RESULT*>(status_info); - callback->Notify(status, result->dwResult, result->dwError); - if (API_SEND_REQUEST == result->dwResult && - ERROR_WINHTTP_NAME_NOT_RESOLVED == result->dwError) - DidFinishDnsResolutionWithStatus(false, - GURL(), // null referrer URL. - reinterpret_cast<void*>(context)); - break; - } - // This status callback provides the detailed reason for a secure - // failure. We map that to an error code and save it for later use. - case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: { - DCHECK(status_info_len == sizeof(DWORD)); - DWORD* status_ptr = static_cast<DWORD*>(status_info); - callback->set_secure_failure(*status_ptr); - break; - } - // Looking up the IP address of a server name. The status_info - // parameter contains a pointer to the server name being resolved. - case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME: { - callback->set_load_state(LOAD_STATE_RESOLVING_HOST); - std::wstring wname(static_cast<wchar_t*>(status_info), - status_info_len - 1); - DidStartDnsResolution(WideToASCII(wname), - reinterpret_cast<void*>(context)); - break; - } - // Successfully found the IP address of the server. - case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED: - DidFinishDnsResolutionWithStatus(true, - GURL(), // null referrer URL. - reinterpret_cast<void*>(context)); - break; - } -} - -// Factory -------------------------------------------------------------------- - -HttpTransactionWinHttp::Factory::~Factory() { - if (session_) - session_->Release(); -} - -HttpTransaction* HttpTransactionWinHttp::Factory::CreateTransaction() { - if (is_suspended_) - return NULL; - - if (!session_) { - session_ = new Session(proxy_service_); - session_->AddRef(); - } - return new HttpTransactionWinHttp(session_, proxy_service_->proxy_info()); -} - -HttpCache* HttpTransactionWinHttp::Factory::GetCache() { - return NULL; -} - -void HttpTransactionWinHttp::Factory::Suspend(bool suspend) { - is_suspended_ = suspend; - - if (is_suspended_ && session_) { - session_->Release(); - session_ = NULL; - } -} - -// Transaction ---------------------------------------------------------------- - -HttpTransactionWinHttp::HttpTransactionWinHttp(Session* session, - const ProxyInfo* info) - : session_(session), - request_(NULL), - load_flags_(0), - last_error_(ERROR_SUCCESS), - content_length_remaining_(-1), - pac_request_(NULL), - proxy_callback_(this, &HttpTransactionWinHttp::OnProxyInfoAvailable), - callback_(NULL), - upload_progress_(0), - connect_handle_(NULL), - request_handle_(NULL), - is_https_(false), - is_tls_intolerant_(false), - rev_checking_enabled_(false), - have_proxy_info_(false), - need_to_wait_for_handle_closing_(false), - request_submitted_(false), - used_embedded_credentials_(false) { - session->AddRef(); - session_callback_ = new SessionCallback(this, session); - if (info) { - proxy_info_.Use(*info); - have_proxy_info_ = true; - } -} - -HttpTransactionWinHttp::~HttpTransactionWinHttp() { - if (pac_request_) - session_->proxy_service()->CancelPacRequest(pac_request_); - - if (request_handle_) { - if (need_to_wait_for_handle_closing_) { - session_callback_->set_handle_closing_event( - session_->handle_closing_event()); - } - WinHttpCloseHandle(request_handle_); - if (need_to_wait_for_handle_closing_) - WaitForSingleObject(session_->handle_closing_event(), INFINITE); - } - if (connect_handle_) - WinHttpCloseHandle(connect_handle_); - - if (request_submitted_) { - session_->request_throttle()->RemoveRequest(connect_peer_, - request_handle_); - } - - if (session_callback_) { - session_callback_->DropTransaction(); - session_callback_ = NULL; // Release() reference as side effect. - } - if (session_) - session_->Release(); -} - -int HttpTransactionWinHttp::Start(const HttpRequestInfo* request_info, - CompletionCallback* callback) { - DCHECK(request_info); - DCHECK(callback); - - // ensure that we only have one asynchronous call at a time. - DCHECK(!callback_); - - LOG(INFO) << request_info->method << ": " << request_info->url; - - request_ = request_info; - load_flags_ = request_info->load_flags; - - int rv = OK; - if (!have_proxy_info_) { - // Resolve proxy info. - rv = session_->proxy_service()->ResolveProxy(request_->url, - &proxy_info_, - &proxy_callback_, - &pac_request_); - if (rv == ERR_IO_PENDING) { - session_callback_->set_load_state( - LOAD_STATE_RESOLVING_PROXY_FOR_URL); - } - } - - if (rv == OK) - rv = DidResolveProxy(); // calls OpenRequest and SendRequest - - if (rv == ERR_IO_PENDING) { - session_callback_->AddRef(); // balanced when callback runs or from - // OnProxyInfoAvailable. - callback_ = callback; - } - - return rv; -} - -int HttpTransactionWinHttp::RestartIgnoringLastError( - CompletionCallback* callback) { - int flags = load_flags_; - - // Depending on the error, we make different adjustments to our load flags. - // We DCHECK that we shouldn't already have ignored this error. - switch (last_error_) { - case ERROR_WINHTTP_SECURE_CERT_CN_INVALID: - DCHECK(!(flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)); - flags |= LOAD_IGNORE_CERT_COMMON_NAME_INVALID; - break; - case ERROR_WINHTTP_SECURE_CERT_DATE_INVALID: - DCHECK(!(flags & LOAD_IGNORE_CERT_DATE_INVALID)); - flags |= LOAD_IGNORE_CERT_DATE_INVALID; - break; - case ERROR_WINHTTP_SECURE_INVALID_CA: - DCHECK(!(flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)); - flags |= LOAD_IGNORE_CERT_AUTHORITY_INVALID; - break; - case ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE: - DCHECK(!(flags & LOAD_IGNORE_CERT_WRONG_USAGE)); - flags |= LOAD_IGNORE_CERT_WRONG_USAGE; - break; - case ERROR_WINHTTP_SECURE_CERT_REV_FAILED: { - DCHECK(!(flags & LOAD_IGNORE_CERT_REVOCATION)); - flags |= LOAD_IGNORE_CERT_REVOCATION; - // WinHTTP doesn't have a SECURITY_FLAG_IGNORE_CERT_REV_FAILED flag - // and doesn't let us undo WINHTTP_ENABLE_SSL_REVOCATION. The only - // way to ignore this error is to open a new request without enabling - // WINHTTP_ENABLE_SSL_REVOCATION. - if (!ReopenRequest()) - return TranslateLastOSError(); - break; - } - // We can't instruct WinHttp to recover from these errors. No choice - // but to cancel the request. - case ERROR_WINHTTP_SECURE_CHANNEL_ERROR: - case ERROR_WINHTTP_SECURE_INVALID_CERT: - case ERROR_WINHTTP_SECURE_CERT_REVOKED: - // We don't knows how to continue from here. - default: - LOG(ERROR) << "Unable to restart the HTTP transaction ignoring " - "the error " << last_error_; - return ERR_ABORTED; - } - - // Update the load flags to ignore the specified error. - load_flags_ = flags; - - return Restart(callback); -} - -int HttpTransactionWinHttp::RestartWithAuth( - const std::wstring& username, - const std::wstring& password, - CompletionCallback* callback) { - DCHECK(proxy_auth_ && proxy_auth_->state == AUTH_STATE_NEED_AUTH || - server_auth_ && server_auth_->state == AUTH_STATE_NEED_AUTH); - - // Proxy gets set first, then WWW. - AuthData* auth = - proxy_auth_ && proxy_auth_->state == AUTH_STATE_NEED_AUTH ? - proxy_auth_ : server_auth_; - - if (auth) { - auth->state = AUTH_STATE_HAVE_AUTH; - auth->username = username; - auth->password = password; - } - - return Restart(callback); -} - -// The code common to RestartIgnoringLastError and RestartWithAuth. -int HttpTransactionWinHttp::Restart(CompletionCallback* callback) { - DCHECK(callback); - - // ensure that we only have one asynchronous call at a time. - DCHECK(!callback_); - - int rv = RestartInternal(); - if (rv != ERR_IO_PENDING) - return rv; - - session_callback_->AddRef(); // balanced when callback runs. - - callback_ = callback; - return ERR_IO_PENDING; -} - -// If HttpTransactionWinHttp needs to restart itself after handling an error, -// it calls this method. This method leaves callback_ unchanged. The caller -// is responsible for calling session_callback_->AddRef() if this method -// returns ERR_IO_PENDING. -int HttpTransactionWinHttp::RestartInternal() { - content_length_remaining_ = -1; - upload_progress_ = 0; - - return SendRequest(); -} - -// We use WinHttpQueryDataAvailable rather than pure async read to trade -// a better latency for a decreased throughput. We'll make more IO calls, -// and thus use more CPU for a given transaction by using -// WinHttpQueryDataAvailable, but it allows us to get a faster response -// time to the app for data, which is more important. -int HttpTransactionWinHttp::Read(char* buf, int buf_len, - CompletionCallback* callback) { - DCHECK(buf); - DCHECK(buf_len > 0); - DCHECK(callback); - - DCHECK(!callback_); - DCHECK(request_handle_); - - // If we have already received the full response, then we know we are done. - if (content_length_remaining_ == 0) { - LogTransactionMetrics(); - return 0; - } - - session_callback_->set_read_buf(buf); - session_callback_->set_read_buf_len(buf_len); - - // We must consume all the available data reported by the previous - // WinHttpQueryDataAvailable call before we can call - // WinHttpQueryDataAvailable again. - BOOL ok; - if (session_callback_->bytes_available()) { - ok = session_callback_->ReadData(request_handle_); - } else { - ok = WinHttpQueryDataAvailable(request_handle_, NULL); - } - if (!ok) - return TranslateLastOSError(); - - session_callback_->set_load_state(LOAD_STATE_READING_RESPONSE); - session_callback_->AddRef(); // balanced when callback runs. - need_to_wait_for_handle_closing_ = true; - - callback_ = callback; - return ERR_IO_PENDING; -} - -const HttpResponseInfo* HttpTransactionWinHttp::GetResponseInfo() const { - return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL; -} - -LoadState HttpTransactionWinHttp::GetLoadState() const { - return session_callback_->load_state(); -} - -uint64 HttpTransactionWinHttp::GetUploadProgress() const { - return upload_progress_; -} - -void HttpTransactionWinHttp::DoCallback(int rv) { - DCHECK(rv != ERR_IO_PENDING); - DCHECK(callback_); - - // since Run may result in Read being called, clear callback_ up front. - CompletionCallback* c = callback_; - callback_ = NULL; - c->Run(rv); -} - -bool HttpTransactionWinHttp::OpenRequest() { - DCHECK(!connect_handle_); - DCHECK(!request_handle_); - - const GURL& url = request_->url; - const std::string& scheme = url.scheme(); - - // Flags passed to WinHttpOpenRequest. Disable any conversion WinHttp - // might perform on our URL string. We handle the escaping ourselves. - DWORD open_flags = WINHTTP_FLAG_ESCAPE_DISABLE | - WINHTTP_FLAG_ESCAPE_DISABLE_QUERY | - WINHTTP_FLAG_NULL_CODEPAGE; - - // We should only be dealing with HTTP at this point: - DCHECK(LowerCaseEqualsASCII(scheme, "http") || - LowerCaseEqualsASCII(scheme, "https")); - - int in_port = url.IntPort(); - DCHECK(in_port != url_parse::PORT_INVALID) << - "Valid URLs should have valid ports"; - - // Map to port numbers that Windows expects. - INTERNET_PORT port = in_port; - if (LowerCaseEqualsASCII(scheme, "https")) { - is_https_ = true; - open_flags |= WINHTTP_FLAG_SECURE; - if (in_port == url_parse::PORT_UNSPECIFIED) - port = INTERNET_DEFAULT_HTTPS_PORT; - } else { - if (in_port == url_parse::PORT_UNSPECIFIED) - port = INTERNET_DEFAULT_HTTP_PORT; - } - - const std::string& host = url.host(); - - // Use the primary session handle unless we are talking to a TLS-intolerant - // server. - // - // Since the SSL protocol versions enabled are an option of a session - // handle, supporting TLS-intolerant servers unfortunately requires opening - // an alternative session in which TLS 1.0 is disabled. - if (!session_->internet() && !session_->Init(request_->user_agent)) { - DLOG(ERROR) << "unable to create the internet"; - return false; - } - HINTERNET internet = session_->internet(); - if (is_tls_intolerant_) { - if (!session_->internet_no_tls() && - !session_->InitNoTLS(request_->user_agent)) { - DLOG(ERROR) << "unable to create the no-TLS alternative internet"; - return false; - } - internet = session_->internet_no_tls(); - } - - // This function operates synchronously. - connect_handle_ = - WinHttpConnect(internet, ASCIIToWide(host).c_str(), port, 0); - if (!connect_handle_) { - DLOG(ERROR) << "WinHttpConnect failed: " << GetLastError(); - return false; - } - - std::string request_path = url.PathForRequest(); - - // This function operates synchronously. - request_handle_ = - WinHttpOpenRequest(connect_handle_, - ASCIIToWide(request_->method).c_str(), - ASCIIToWide(request_path).c_str(), - NULL, // use HTTP/1.1 - WINHTTP_NO_REFERER, // none - WINHTTP_DEFAULT_ACCEPT_TYPES, // none - open_flags); - if (!request_handle_) { - DLOG(ERROR) << "WinHttpOpenRequest failed: " << GetLastError(); - return false; - } - - // TODO(darin): we may wish to prune-back the set of notifications we receive - WINHTTP_STATUS_CALLBACK old_callback = WinHttpSetStatusCallback( - request_handle_, StatusCallback, - WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, NULL); - DCHECK(old_callback == NULL); - if (old_callback == WINHTTP_INVALID_STATUS_CALLBACK) { - DLOG(ERROR) << "WinHttpSetStatusCallback failed:" << GetLastError(); - return false; - } - - DWORD_PTR ctx = reinterpret_cast<DWORD_PTR>(session_callback_.get()); - if (!WinHttpSetOption(request_handle_, WINHTTP_OPTION_CONTEXT_VALUE, - &ctx, sizeof(ctx))) { - DLOG(ERROR) << "WinHttpSetOption context value failed:" << GetLastError(); - return false; - } - - // We just associated a status callback context value with the request - // handle. - session_callback_->AddRef(); // balanced in OnHandleClosing - session_->AddRefBySessionCallback(); - - // We have our own cookie and redirect management. - DWORD options = WINHTTP_DISABLE_COOKIES | - WINHTTP_DISABLE_REDIRECTS; - - if (!WinHttpSetOption(request_handle_, WINHTTP_OPTION_DISABLE_FEATURE, - &options, sizeof(options))) { - DLOG(ERROR) << "WinHttpSetOption disable feature failed:" << GetLastError(); - return false; - } - - // Disable auto-login for Negotiate and NTLM auth methods. - DWORD security_level = WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH; - if (!WinHttpSetOption(request_handle_, WINHTTP_OPTION_AUTOLOGON_POLICY, - &security_level, sizeof(security_level))) { - DLOG(ERROR) << "WinHttpSetOption autologon failed: " << GetLastError(); - return false; - } - - // Add request headers. WinHttp is known to convert the headers to bytes - // using the system charset converter, so we use the same converter to map - // our request headers to UTF-16 before handing the data to WinHttp. - std::wstring request_headers = base::SysNativeMBToWide(GetRequestHeaders()); - - DWORD len = static_cast<DWORD>(request_headers.size()); - if (!WinHttpAddRequestHeaders(request_handle_, - request_headers.c_str(), - len, - WINHTTP_ADDREQ_FLAG_ADD | - WINHTTP_ADDREQ_FLAG_REPLACE)) { - DLOG(ERROR) << "WinHttpAddRequestHeaders failed: " << GetLastError(); - return false; - } - - return true; -} - -int HttpTransactionWinHttp::SendRequest() { - DCHECK(request_handle_); - - // Apply any authentication (username/password) we might have. - ApplyAuth(); - - // Apply any proxy info. - proxy_info_.Apply(request_handle_); - - // Check SSL server certificate revocation. - if (is_https_) { - bool ignore_cert_rev = (load_flags_ & LOAD_IGNORE_CERT_REVOCATION) != 0; - GURL origin = request_->url.GetOrigin(); - const std::string& origin_spec = origin.spec(); - if (ignore_cert_rev) - session_->IgnoreCertRev(origin_spec); - else if (session_->ShouldIgnoreCertRev(origin_spec)) - ignore_cert_rev = true; - - if (session_->rev_checking_enabled() && !ignore_cert_rev) { - DWORD options = WINHTTP_ENABLE_SSL_REVOCATION; - if (!WinHttpSetOption(request_handle_, WINHTTP_OPTION_ENABLE_FEATURE, - &options, sizeof(options))) { - DLOG(ERROR) << "WinHttpSetOption failed: " << GetLastError(); - return TranslateLastOSError(); - } - rev_checking_enabled_ = true; - } - } - - const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID | - LOAD_IGNORE_CERT_DATE_INVALID | - LOAD_IGNORE_CERT_AUTHORITY_INVALID | - LOAD_IGNORE_CERT_WRONG_USAGE; - - if (load_flags_ & kCertFlags) { - DWORD security_flags; - DWORD length = sizeof(security_flags); - - if (!WinHttpQueryOption(request_handle_, - WINHTTP_OPTION_SECURITY_FLAGS, - &security_flags, - &length)) { - NOTREACHED() << "WinHttpQueryOption failed."; - return TranslateLastOSError(); - } - - // On Vista, WinHttpSetOption() fails with an incorrect parameter error. - // WinHttpQueryOption() sets an undocumented flag (0x01000000, which seems - // to be a query-only flag) in security_flags that causes this error. To - // work-around it, we only keep the documented error flags. - security_flags &= (SECURITY_FLAG_IGNORE_UNKNOWN_CA | - SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | - SECURITY_FLAG_IGNORE_CERT_CN_INVALID | - SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE); - - if (load_flags_ & LOAD_IGNORE_CERT_COMMON_NAME_INVALID) - security_flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID; - - if (load_flags_ & LOAD_IGNORE_CERT_DATE_INVALID) - security_flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; - - if (load_flags_ & LOAD_IGNORE_CERT_AUTHORITY_INVALID) - security_flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA; - - if (load_flags_ & LOAD_IGNORE_CERT_WRONG_USAGE) - security_flags |= SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE; - - if (!WinHttpSetOption(request_handle_, - WINHTTP_OPTION_SECURITY_FLAGS, - &security_flags, - sizeof(security_flags))) { - NOTREACHED() << "WinHttpSetOption failed."; - return TranslateLastOSError(); - } - } - - response_.request_time = Time::Now(); - response_.was_cached = false; - - DWORD total_size = 0; - if (request_->upload_data) { - upload_stream_.reset(new UploadDataStream(request_->upload_data)); - uint64 upload_len = upload_stream_->size(); - if (upload_len == 0) { - upload_stream_.reset(); - } else { - // TODO(darin): no way to support >4GB uploads w/ WinHttp? - if (upload_len > static_cast<uint64>(DWORD(-1))) { - NOTREACHED() << "upload length is too large"; - return ERR_FILE_TOO_BIG; - } - - total_size = static_cast<DWORD>(upload_len); - } - } - - if (request_submitted_) { - request_submitted_ = false; - session_->request_throttle()->NotifyRequestDone(connect_peer_); - } - if (proxy_info_.is_direct()) - connect_peer_ = request_->url.GetOrigin().spec(); - else - connect_peer_ = proxy_info_.proxy_server(); - DWORD_PTR ctx = reinterpret_cast<DWORD_PTR>(session_callback_.get()); - if (!session_->request_throttle()->SubmitRequest(connect_peer_, - request_handle_, - total_size, ctx)) { - last_error_ = GetLastError(); - DLOG(ERROR) << "WinHttpSendRequest failed: " << last_error_; - return TranslateOSError(last_error_); - } - - request_submitted_ = true; - return ERR_IO_PENDING; -} - -// Called after certain failures of SendRequest to reset the members opened -// or modified in OpenRequest and SendRequest and call OpenRequest again. -bool HttpTransactionWinHttp::ReopenRequest() { - DCHECK(connect_handle_); - DCHECK(request_handle_); - - session_callback_->set_handle_closing_event( - session_->handle_closing_event()); - WinHttpCloseHandle(request_handle_); - WaitForSingleObject(session_->handle_closing_event(), INFINITE); - request_handle_ = NULL; - WinHttpCloseHandle(connect_handle_); - connect_handle_ = NULL; - session_callback_->ResetForNewRequest(); - - // Don't need to reset is_https_, rev_checking_enabled_, and - // response_.request_time. - - return OpenRequest(); -} - -int HttpTransactionWinHttp::DidResolveProxy() { - // We may already have a request handle if we are changing proxy config. - if (!(request_handle_ ? ReopenRequest() : OpenRequest())) - return TranslateLastOSError(); - - return SendRequest(); -} - -int HttpTransactionWinHttp::DidReceiveError(DWORD error, - DWORD secure_failure) { - DCHECK(error != ERROR_SUCCESS); - - session_callback_->set_load_state(LOAD_STATE_IDLE); - need_to_wait_for_handle_closing_ = false; - - int rv; - - if (error == ERROR_WINHTTP_RESEND_REQUEST) - return RestartInternal(); - - if (error == ERROR_WINHTTP_NAME_NOT_RESOLVED || - error == ERROR_WINHTTP_CANNOT_CONNECT || - error == ERROR_WINHTTP_TIMEOUT) { - // These errors may have been caused by a proxy configuration error, or - // rather they may go away by trying a different proxy config! If we have - // an explicit proxy config, then we just have to report an error. - if (!have_proxy_info_) { - rv = session_->proxy_service()->ReconsiderProxyAfterError( - request_->url, &proxy_info_, &proxy_callback_, &pac_request_); - if (rv == OK) // got new proxy info to try - return DidResolveProxy(); - if (rv == ERR_IO_PENDING) // waiting to resolve proxy info - return rv; - // else, fall through and just report an error. - } - } - - if (error == ERROR_WINHTTP_SECURE_FAILURE) { - DWORD filtered_secure_failure = FilterSecureFailure(secure_failure, - load_flags_); - // If load_flags_ ignores all the errors in secure_failure, we shouldn't - // get the ERROR_WINHTTP_SECURE_FAILURE error. - DCHECK(filtered_secure_failure || !secure_failure); - error = MapSecureFailureToError(filtered_secure_failure); - } - - last_error_ = error; - rv = TranslateOSError(error); - - if ((rv == ERR_SSL_PROTOCOL_ERROR || - rv == ERR_SSL_VERSION_OR_CIPHER_MISMATCH) && - !session_callback_->request_was_probably_sent() && - session_->tls_enabled() && !is_tls_intolerant_) { - // The server might be TLS intolerant. Or it might be an SSL 3.0 server - // that chose a TLS-only cipher suite, which we handle in the same way. - // Downgrade to SSL 3.0 and retry. - is_tls_intolerant_ = true; - if (!ReopenRequest()) - return TranslateLastOSError(); - return RestartInternal(); - } - if (rv == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) { - // TODO(wtc): Bug 1230409: We don't support SSL client authentication yet. - // For now we set a null client certificate, which works on XP SP3, Vista - // and later. On XP SP2 and below, this fails with ERROR_INVALID_PARAMETER - // (87). This allows us to access servers that request but do not require - // client certificates. - if (WinHttpSetOption(request_handle_, - WINHTTP_OPTION_CLIENT_CERT_CONTEXT, - WINHTTP_NO_CLIENT_CERT_CONTEXT, 0)) - return RestartInternal(); - } - if (IsCertificateError(rv)) { - response_.ssl_info.cert = GetServerCertificate(); - response_.ssl_info.cert_status = - MapSecureFailureToCertStatus(secure_failure); - CertStatusCache* cert_status_cache = session_->cert_status_cache(); - cert_status_cache->SetCertStatus(*response_.ssl_info.cert, - request_->url.host(), - response_.ssl_info.cert_status); - } - - return rv; -} - -int HttpTransactionWinHttp::DidSendRequest() { - BOOL ok; - if (upload_stream_.get() && upload_stream_->buf_len() > 0) { - // write upload data - DWORD buf_len = static_cast<DWORD>(upload_stream_->buf_len()); - ok = WinHttpWriteData(request_handle_, - upload_stream_->buf(), - buf_len, - NULL); - if (ok) - need_to_wait_for_handle_closing_ = true; - } else { - upload_stream_.reset(); - need_to_wait_for_handle_closing_ = false; - - // begin receiving the response - ok = WinHttpReceiveResponse(request_handle_, NULL); - } - return ok ? ERR_IO_PENDING : TranslateLastOSError(); -} - -int HttpTransactionWinHttp::DidWriteData(DWORD num_bytes) { - DCHECK(upload_stream_.get()); - DCHECK(num_bytes > 0); - - upload_stream_->DidConsume(num_bytes); - upload_progress_ = upload_stream_->position(); - - // OK, we are ready to start receiving the response. The code in - // DidSendRequest does exactly what we want! - return DidSendRequest(); -} - -int HttpTransactionWinHttp::DidReadData(DWORD num_bytes) { - int rv = static_cast<int>(num_bytes); - DCHECK(rv >= 0); - - session_callback_->set_load_state(LOAD_STATE_IDLE); - session_callback_->reduce_bytes_available(rv); - need_to_wait_for_handle_closing_ = false; - - if (content_length_remaining_ > 0) { - content_length_remaining_ -= rv; - - // HTTP/1.0 servers are known to send more data than they report in their - // Content-Length header (in the non-keepalive case). IE and Moz both - // tolerate this situation, and therefore so must we. - if (content_length_remaining_ < 0) - content_length_remaining_ = 0; - } - - // We have read the entire response. Mark the request done to unblock a - // queued request. - if (rv == 0) { - LogTransactionMetrics(); - DCHECK(request_submitted_); - request_submitted_ = false; - session_->request_throttle()->NotifyRequestDone(connect_peer_); - } - - return rv; -} - -void HttpTransactionWinHttp::LogTransactionMetrics() const { - base::TimeDelta duration = base::Time::Now() - response_.request_time; - if (60 < duration.InMinutes()) - return; - UMA_HISTOGRAM_LONG_TIMES(L"Net.Transaction_Latency_WinHTTP", duration); -} - -int HttpTransactionWinHttp::DidReceiveHeaders() { - session_callback_->set_load_state(LOAD_STATE_IDLE); - - DWORD size = 0; - if (!WinHttpQueryHeaders(request_handle_, - WINHTTP_QUERY_RAW_HEADERS, - WINHTTP_HEADER_NAME_BY_INDEX, - NULL, - &size, - WINHTTP_NO_HEADER_INDEX)) { - DWORD error = GetLastError(); - if (error != ERROR_INSUFFICIENT_BUFFER) { - DLOG(ERROR) << "WinHttpQueryHeaders failed: " << GetLastError(); - return TranslateLastOSError(); - } - // OK, size should tell us how much to allocate... - DCHECK(size > 0); - } - - std::wstring raw_headers; - - // 'size' is the number of bytes rather than the number of characters. - DCHECK(size % 2 == 0); - if (!WinHttpQueryHeaders(request_handle_, - WINHTTP_QUERY_RAW_HEADERS, - WINHTTP_HEADER_NAME_BY_INDEX, - WriteInto(&raw_headers, size/2 + 1), - &size, - WINHTTP_NO_HEADER_INDEX)) { - DLOG(ERROR) << "WinHttpQueryHeaders failed: " << GetLastError(); - return TranslateLastOSError(); - } - - response_.response_time = Time::Now(); - - // From experimentation, it appears that WinHttp translates non-ASCII bytes - // found in the response headers to UTF-16 assuming that they are encoded - // using the default system charset. We attempt to undo that here. - response_.headers = - new HttpResponseHeaders(base::SysWideToNativeMB(raw_headers)); - - // WinHTTP truncates a response longer than 2GB. Perhaps it stores the - // response's content length in a signed 32-bit integer. We fail rather - // than reading a truncated response. - if (response_.headers->GetContentLength() > 0x80000000) - return ERR_FILE_TOO_BIG; - - response_.vary_data.Init(*request_, *response_.headers); - int rv = PopulateAuthChallenge(); - if (rv != OK) - return rv; - - // Unfortunately, WinHttp does not close the connection when a non-keepalive - // response is _not_ followed by the server closing the connection. So, we - // attempt to hack around this bug. - if (!response_.headers->IsKeepAlive()) - content_length_remaining_ = response_.headers->GetContentLength(); - - return OK; -} - -// Populates response_.auth_challenge with the authentication challenge info. -int HttpTransactionWinHttp::PopulateAuthChallenge() { - DCHECK(response_.headers); - - int status = response_.headers->response_code(); - if (status != 401 && status != 407) - return OK; - - scoped_refptr<AuthChallengeInfo> auth_info = new AuthChallengeInfo; - - auth_info->is_proxy = (status == 407); - - if (auth_info->is_proxy) { - // TODO(wtc): get the proxy server host from proxy_info_. - // TODO(wtc): internationalize? - auth_info->host = L"proxy"; - } else { - auth_info->host = ASCIIToWide(request_->url.host()); - } - - // Here we're checking only the first *-Authenticate header. When a server - // responds with multiple methods, we use the first. - // TODO(wtc): Bug 1124614: look at all the authentication methods and pick - // the best one that we support. failover to other authentication methods. - std::string header_value; - std::string header_name = auth_info->is_proxy ? - "Proxy-Authenticate" : "WWW-Authenticate"; - if (!response_.headers->EnumerateHeader(NULL, header_name, &header_value)) - return OK; - - // TODO(darin): Need to support RFC 2047 encoded realm strings. For now, we - // limit our support to ASCII and "native code page" realm strings. - std::wstring auth_header = base::SysNativeMBToWide(header_value); - - // auth_header is a string which looks like: - // Digest realm="The Awesome Site", domain="/page.html", ... - std::wstring::const_iterator space = find(auth_header.begin(), - auth_header.end(), L' '); - auth_info->scheme.assign(auth_header.begin(), space); - auth_info->realm = GetHeaderParamValue(auth_header, L"realm"); - - // Now auth_info has been fully populated. Before we swap it with - // response_.auth_challenge, update the auth cache key and remove any - // presumably incorrect auth data in the auth cache. - std::string* auth_cache_key; - AuthData* auth; - if (auth_info->is_proxy) { - if (!proxy_auth_) - proxy_auth_ = new AuthData; - auth = proxy_auth_; - auth_cache_key = &proxy_auth_cache_key_; - } else { - if (!server_auth_) - server_auth_ = new AuthData; - auth = server_auth_; - auth_cache_key = &server_auth_cache_key_; - } - *auth_cache_key = AuthCache::HttpKey(request_->url, *auth_info); - DCHECK(!auth_cache_key->empty()); - auth->scheme = auth_info->scheme; - if (auth->state == AUTH_STATE_HAVE_AUTH) { - // Remove the cache entry for the credentials we just failed on. - // Note: we require the username/password to match before removing - // since the entry in the cache may be newer than what we used last time. - AuthData* cached_auth = session_->auth_cache()->Lookup(*auth_cache_key); - if (cached_auth && cached_auth->username == auth->username && - cached_auth->password == auth->password) - session_->auth_cache()->Remove(*auth_cache_key); - auth->state = AUTH_STATE_NEED_AUTH; - } - DCHECK(auth->state == AUTH_STATE_NEED_AUTH); - - // Try to use the username/password embedded in the URL first. - // (By checking !used_embedded_credentials_, we make sure that this - // is only done once for the transaction.) - if (!auth_info->is_proxy && request_->url.has_username() && - !used_embedded_credentials_) { - // TODO(wtc) It may be necessary to unescape the username and password - // after extracting them from the URL. We should be careful about - // embedded nulls in that case. - used_embedded_credentials_ = true; - auth->state = AUTH_STATE_HAVE_AUTH; - auth->username = ASCIIToWide(request_->url.username()); - auth->password = ASCIIToWide(request_->url.password()); - return RestartInternal(); - } - - // Check the auth cache for an entry. - AuthData* cached_auth = session_->auth_cache()->Lookup(*auth_cache_key); - if (cached_auth) { - auth->state = AUTH_STATE_HAVE_AUTH; - auth->username = cached_auth->username; - auth->password = cached_auth->password; - return RestartInternal(); - } - - response_.auth_challenge.swap(auth_info); - return OK; -} - -static DWORD StringToAuthScheme(const std::wstring& scheme) { - if (LowerCaseEqualsASCII(scheme, "basic")) - return WINHTTP_AUTH_SCHEME_BASIC; - if (LowerCaseEqualsASCII(scheme, "digest")) - return WINHTTP_AUTH_SCHEME_DIGEST; - if (LowerCaseEqualsASCII(scheme, "ntlm")) - return WINHTTP_AUTH_SCHEME_NTLM; - if (LowerCaseEqualsASCII(scheme, "negotiate")) - return WINHTTP_AUTH_SCHEME_NEGOTIATE; - if (LowerCaseEqualsASCII(scheme, "passport1.4")) - return WINHTTP_AUTH_SCHEME_PASSPORT; - return 0; -} - -// Applies authentication credentials to request_handle_. -void HttpTransactionWinHttp::ApplyAuth() { - DWORD auth_scheme; - BOOL rv; - if (proxy_auth_ && proxy_auth_->state == AUTH_STATE_HAVE_AUTH) { - // Add auth data to cache. - DCHECK(!proxy_auth_cache_key_.empty()); - session_->auth_cache()->Add(proxy_auth_cache_key_, proxy_auth_); - auth_scheme = StringToAuthScheme(proxy_auth_->scheme); - if (auth_scheme == 0) - return; - - rv = WinHttpSetCredentials(request_handle_, - WINHTTP_AUTH_TARGET_PROXY, - auth_scheme, - proxy_auth_->username.c_str(), - proxy_auth_->password.c_str(), - NULL); - } - - if (server_auth_ && server_auth_->state == AUTH_STATE_HAVE_AUTH) { - // Add auth data to cache. - DCHECK(!server_auth_cache_key_.empty()); - session_->auth_cache()->Add(server_auth_cache_key_, server_auth_); - auth_scheme = StringToAuthScheme(server_auth_->scheme); - if (auth_scheme == 0) - return; - - rv = WinHttpSetCredentials(request_handle_, - WINHTTP_AUTH_TARGET_SERVER, - auth_scheme, - server_auth_->username.c_str(), - server_auth_->password.c_str(), - NULL); - } -} - -void HttpTransactionWinHttp::OnProxyInfoAvailable(int result) { - if (result != OK) { - DLOG(WARNING) << "failed to get proxy info: " << result; - proxy_info_.UseDirect(); - } - - // Balances extra reference taken when proxy resolution was initiated. - session_callback_->Release(); - - pac_request_ = NULL; - - // Since OnProxyInfoAvailable is always called asynchronously (via the - // message loop), we need to trap any errors and pass them to the consumer - // via their completion callback. - - int rv = DidResolveProxy(); - if (rv == ERR_IO_PENDING) { - session_callback_->AddRef(); // balanced when callback runs. - } else { - DoCallback(rv); - } -} - -std::string HttpTransactionWinHttp::GetRequestHeaders() const { - std::string headers; - - if (!request_->user_agent.empty()) - headers += "User-Agent: " + request_->user_agent + "\r\n"; - - // Our consumer should have made sure that this is a safe referrer. See for - // instance WebCore::FrameLoader::HideReferrer. - if (request_->referrer.is_valid()) - headers += "Referer: " + request_->referrer.spec() + "\r\n"; - - // IE and Safari do this. 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. - if (request_->method == "HEAD") - headers += "Content-Length: 0\r\n"; - - // Honor load flags that impact proxy caches. - if (request_->load_flags & LOAD_BYPASS_CACHE) { - headers += "Pragma: no-cache\r\nCache-Control: no-cache\r\n"; - } else if (request_->load_flags & LOAD_VALIDATE_CACHE) { - headers += "Cache-Control: max-age=0\r\n"; - } - - // TODO(darin): Prune out duplicate headers? - headers += request_->extra_headers; - - return headers; -} - -// Retrieves the SSL server certificate associated with the transaction. -// The caller is responsible for freeing the certificate. -X509Certificate* HttpTransactionWinHttp::GetServerCertificate() const { - DCHECK(is_https_); - PCCERT_CONTEXT cert_context = NULL; - DWORD length = sizeof(cert_context); - if (!WinHttpQueryOption(request_handle_, - WINHTTP_OPTION_SERVER_CERT_CONTEXT, - &cert_context, - &length)) { - return NULL; - } - // cert_context may be NULL here even though WinHttpQueryOption succeeded. - // For example, a proxy server may return a 404 error page to report the - // DNS resolution failure of the server's hostname. - if (!cert_context) - return NULL; - return X509Certificate::CreateFromHandle(cert_context); -} - -// Retrieves the security strength, in bits, of the SSL cipher suite -// associated with the transaction. -int HttpTransactionWinHttp::GetSecurityBits() const { - DCHECK(is_https_); - DWORD key_bits = 0; - DWORD length = sizeof(key_bits); - if (!WinHttpQueryOption(request_handle_, - WINHTTP_OPTION_SECURITY_KEY_BITNESS, - &key_bits, - &length)) { - return -1; - } - return key_bits; -} - -void HttpTransactionWinHttp::PopulateSSLInfo(DWORD secure_failure) { - if (is_https_) { - response_.ssl_info.cert = GetServerCertificate(); - response_.ssl_info.security_bits = GetSecurityBits(); - // If there is no cert (such as when the proxy server makes up a - // 404 response to report a server name resolution error), don't set - // the cert status. - if (!response_.ssl_info.cert) - return; - response_.ssl_info.cert_status = - MapSecureFailureToCertStatus(secure_failure); - // WinHTTP does not always return a cert status once we ignored errors - // for a cert. (Our experiments showed that WinHTTP reliably returns a - // cert status only when there are unignored errors or when we resend a - // request with the errors ignored.) So we have to remember what the - // last status was for a cert. Note that if the cert status changes - // from error to OK, we won't know that. If we have never stored our - // status in the CertStatusCache (meaning no errors so far), then it is - // OK (0). - CertStatusCache* cert_status_cache = session_->cert_status_cache(); - if (net::IsCertStatusError(response_.ssl_info.cert_status)) { - cert_status_cache->SetCertStatus(*response_.ssl_info.cert, - request_->url.host(), - response_.ssl_info.cert_status); - } else { - response_.ssl_info.cert_status |= - cert_status_cache->GetCertStatus(*response_.ssl_info.cert, - request_->url.host()) & - net::CERT_STATUS_ALL_ERRORS; - } - - if (rev_checking_enabled_) - response_.ssl_info.cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; - } else { - // If this is not https, we should not get a cert status. - DCHECK(!secure_failure); - } -} - -void HttpTransactionWinHttp::HandleStatusCallback(DWORD status, - DWORD_PTR result, - DWORD error, - DWORD secure_failure) { - int rv; - - switch (status) { - case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR: - rv = DidReceiveError(error, secure_failure); - break; - case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: - PopulateSSLInfo(secure_failure); - rv = DidSendRequest(); - break; - case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: - rv = DidWriteData(static_cast<DWORD>(result)); - break; - case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: - rv = DidReceiveHeaders(); - break; - case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: - rv = DidReadData(static_cast<DWORD>(result)); - break; - default: - NOTREACHED() << "unexpected status code"; - rv = ERR_UNEXPECTED; - break; - } - - if (rv == ERR_IO_PENDING) { - session_callback_->AddRef(); // balanced when callback runs. - } else if (callback_) { - DoCallback(rv); - } -} - -} // namespace net - diff --git a/net/http/http_transaction_winhttp.h b/net/http/http_transaction_winhttp.h deleted file mode 100644 index 27ad730..0000000 --- a/net/http/http_transaction_winhttp.h +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) 2006-2008 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. - -#ifndef NET_HTTP_HTTP_TRANSACTION_WINHTTP_H__ -#define NET_HTTP_HTTP_TRANSACTION_WINHTTP_H__ - -#include <windows.h> -#include <winhttp.h> - -#include <string> - -#include "base/ref_counted.h" -#include "net/base/completion_callback.h" -#include "net/http/http_response_info.h" -#include "net/http/http_transaction.h" -#include "net/http/http_transaction_factory.h" -#include "net/proxy/proxy_service.h" - -namespace net { - -class UploadDataStream; - -class HttpTransactionWinHttp : public HttpTransaction { - class Session; // Represents a WinHttp session handle. - class SessionCallback; - public: - // Instantiate this class, and use it to create HttpTransaction objects. - class Factory : public HttpTransactionFactory { - public: - explicit Factory(ProxyService* proxy_service) - : session_(NULL), proxy_service_(proxy_service), is_suspended_(false) { - DCHECK(proxy_service); - } - ~Factory(); - - virtual HttpTransaction* CreateTransaction(); - virtual HttpCache* GetCache(); - virtual void Suspend(bool suspend); - - private: - Session* session_; - ProxyService* proxy_service_; - bool is_suspended_; - DISALLOW_EVIL_CONSTRUCTORS(Factory); - }; - - virtual ~HttpTransactionWinHttp(); - - // HttpTransaction methods: - virtual int Start(const HttpRequestInfo*, CompletionCallback*); - virtual int RestartIgnoringLastError(CompletionCallback*); - virtual int RestartWithAuth(const std::wstring&, - const std::wstring&, - CompletionCallback*); - virtual int Read(char*, int, CompletionCallback*); - virtual const HttpResponseInfo* GetResponseInfo() const; - virtual LoadState GetLoadState() const; - virtual uint64 GetUploadProgress() const; - - static void CALLBACK StatusCallback(HINTERNET handle, - DWORD_PTR context, - DWORD status, - LPVOID status_info, - DWORD status_info_len); - - // Called via the message loop in response to a WinHttp status callback. - void HandleStatusCallback(DWORD status, - DWORD_PTR result, - DWORD error, - DWORD secure_failure); - - private: - friend class Factory; - - // Methods ------------------------------------------------------------------ - - HttpTransactionWinHttp(Session* session, const ProxyInfo* info); - - void DoCallback(int rv); - int ResolveProxy(); - bool OpenRequest(); - int SendRequest(); - bool ReopenRequest(); - int Restart(CompletionCallback* callback); - int RestartInternal(); - int DidResolveProxy(); - int DidReceiveError(DWORD error, DWORD secure_failure); - int DidSendRequest(); - int DidWriteData(DWORD num_bytes); - int DidReadData(DWORD num_bytes); - void LogTransactionMetrics() const; - int DidReceiveHeaders(); - - int PopulateAuthChallenge(); - void ApplyAuth(); - - std::string GetRequestHeaders() const; - X509Certificate* GetServerCertificate() const; - int GetSecurityBits() const; - void PopulateSSLInfo(DWORD secure_failure); - - void OnProxyInfoAvailable(int result); - - // Variables ---------------------------------------------------------------- - - Session* session_; - const HttpRequestInfo* request_; - - // A copy of request_->load_flags that we can modify in - // RestartIgnoringLastError. - int load_flags_; - - // Optional auth data for proxy and origin server. - scoped_refptr<AuthData> proxy_auth_; - scoped_refptr<AuthData> server_auth_; - - // The key for looking up the auth data in the auth cache, consisting - // of the scheme, host, and port of the request URL and the realm in - // the auth challenge. - std::string proxy_auth_cache_key_; - std::string server_auth_cache_key_; - - // The peer of the connection. For a direct connection, this is the - // destination server. If we use a proxy, this is the proxy. - std::string connect_peer_; - - // The last error from SendRequest that occurred. Used by - // RestartIgnoringLastError to adjust load_flags_ to ignore this error. - DWORD last_error_; - - // This value is non-negative when we are streaming a response over a - // non-keepalive connection. We decrement this value as we receive data to - // allow us to discover end-of-file. This is used to workaround a bug in - // WinHttp (see bug 1063336). - int64 content_length_remaining_; - - ProxyInfo proxy_info_; - ProxyService::PacRequest* pac_request_; - CompletionCallbackImpl<HttpTransactionWinHttp> proxy_callback_; - - HttpResponseInfo response_; - CompletionCallback* callback_; - HINTERNET connect_handle_; - HINTERNET request_handle_; - scoped_refptr<SessionCallback> session_callback_; - scoped_ptr<UploadDataStream> upload_stream_; - uint64 upload_progress_; - - // True if the URL's scheme is https. - bool is_https_; - - // True if the SSL server doesn't support TLS but also cannot correctly - // negotiate with a TLS-enabled client to use SSL 3.0. The workaround is - // for the client to downgrade to SSL 3.0 and retry the SSL handshake. - bool is_tls_intolerant_; - - // True if revocation checking of the SSL server certificate is enabled. - bool rev_checking_enabled_; - - // A flag to indicate whether or not we already have proxy information. - // If false, we will attempt to resolve proxy information from the proxy - // service. This flag is set to true if proxy information is supplied by - // a client. - bool have_proxy_info_; - - // If WinHTTP is still using our caller's data (upload data or read buffer), - // we need to wait for the HANDLE_CLOSING status notification after we close - // the request handle. - // - // There are only five WinHTTP functions that work asynchronously (listed in - // the order in which they're called): - // WinHttpSendRequest, WinHttpWriteData, WinHttpReceiveResponse, - // WinHttpQueryDataAvailable, WinHttpReadData. - // WinHTTP is using our caller's data during the two time intervals: - // - From the first WinHttpWriteData call to the completion of the last - // WinHttpWriteData call. (We may call WinHttpWriteData multiple times.) - // - From the WinHttpReadData call to its completion. - // We set need_to_wait_for_handle_closing_ to true at the beginning of these - // time intervals and set it to false at the end. We're not sandwiching the - // intervals as tightly as possible. (To do that, we'd need to give WinHTTP - // worker threads access to the need_to_wait_for_handle_closing_ flag and - // worry about thread synchronization issues.) - bool need_to_wait_for_handle_closing_; - - // True if we have called WinHttpRequestThrottle::SubmitRequest but haven't - // called WinHttpRequestThrottle::NotifyRequestDone. - bool request_submitted_; - - // True if we have used the username/password embedded in the URL. - bool used_embedded_credentials_; - - DISALLOW_EVIL_CONSTRUCTORS(HttpTransactionWinHttp); -}; - -} // namespace net - -#endif // NET_HTTP_HTTP_TRANSACTION_WINHTTP_H__ - diff --git a/net/http/http_transaction_winhttp_unittest.cc b/net/http/http_transaction_winhttp_unittest.cc deleted file mode 100644 index e24c8d8..0000000 --- a/net/http/http_transaction_winhttp_unittest.cc +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2006-2008 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_transaction_winhttp.h" -#include "net/http/http_transaction_unittest.h" -#include "testing/gtest/include/gtest/gtest.h" - -TEST(HttpTransactionWinHttp, CreateAndDestroy) { - scoped_ptr<net::ProxyService> proxy_service(net::ProxyService::CreateNull()); - net::HttpTransactionWinHttp::Factory factory(proxy_service.get()); - - scoped_ptr<net::HttpTransaction> trans(factory.CreateTransaction()); -} - -TEST(HttpTransactionWinHttp, Suspend) { - scoped_ptr<net::ProxyService> proxy_service(net::ProxyService::CreateNull()); - net::HttpTransactionWinHttp::Factory factory(proxy_service.get()); - - scoped_ptr<net::HttpTransaction> trans(factory.CreateTransaction()); - trans.reset(); - - factory.Suspend(true); - - trans.reset(factory.CreateTransaction()); - ASSERT_TRUE(trans == NULL); - - factory.Suspend(false); - - trans.reset(factory.CreateTransaction()); -} - -TEST(HttpTransactionWinHttp, GoogleGET) { - scoped_ptr<net::ProxyService> proxy_service(net::ProxyService::CreateNull()); - net::HttpTransactionWinHttp::Factory factory(proxy_service.get()); - TestCompletionCallback callback; - - scoped_ptr<net::HttpTransaction> trans(factory.CreateTransaction()); - - net::HttpRequestInfo request_info; - request_info.url = GURL("http://www.google.com/"); - request_info.method = "GET"; - request_info.user_agent = "Foo/1.0"; - request_info.load_flags = net::LOAD_NORMAL; - - int rv = trans->Start(&request_info, &callback); - if (rv == net::ERR_IO_PENDING) - rv = callback.WaitForResult(); - EXPECT_EQ(net::OK, rv); - - std::string contents; - rv = ReadTransaction(trans.get(), &contents); - EXPECT_EQ(net::OK, rv); -} - diff --git a/net/http/winhttp_request_throttle.cc b/net/http/winhttp_request_throttle.cc deleted file mode 100644 index 79415b3..0000000 --- a/net/http/winhttp_request_throttle.cc +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2006-2008 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/winhttp_request_throttle.h" - -#include "base/logging.h" -#include "net/http/http_transaction_winhttp.h" - -namespace { - -// The arguments to a WinHttpSendRequest call. -struct SendRequestArgs { - SendRequestArgs() : request_handle(NULL), total_size(0), context(0) {} - - SendRequestArgs(HINTERNET handle, DWORD size, DWORD_PTR context_value) - : request_handle(handle), total_size(size), context(context_value) {} - - HINTERNET request_handle; - DWORD total_size; - DWORD_PTR context; -}; - -} // namespace - -namespace net { - -// Per-server queue for WinHttpSendRequest calls. -class WinHttpRequestThrottle::RequestQueue { - public: - RequestQueue() {} - - // Adds |args| to the end of the queue. - void PushBack(const SendRequestArgs& args) { queue_.push_back(args); } - - // If the queue is not empty, pops the first entry off the queue, saves it - // in |*args|, and returns true. If the queue is empty, returns false. - bool GetFront(SendRequestArgs* args); - - // If the queue has an entry containing |request_handle|, removes it and - // returns true. Otherwise, returns false. - bool Remove(HINTERNET request_handle); - - bool empty() const { return queue_.empty(); } - - private: - std::list<SendRequestArgs> queue_; - - DISALLOW_EVIL_CONSTRUCTORS(RequestQueue); -}; - -bool WinHttpRequestThrottle::RequestQueue::GetFront(SendRequestArgs* args) { - if (queue_.empty()) - return false; - *args = queue_.front(); - queue_.pop_front(); - return true; -} - -bool WinHttpRequestThrottle::RequestQueue::Remove(HINTERNET request_handle) { - std::list<SendRequestArgs>::iterator it; - for (it = queue_.begin(); it != queue_.end(); ++it) { - if (it->request_handle == request_handle) { - queue_.erase(it); - return true; - } - } - return false; -} - -WinHttpRequestThrottle::~WinHttpRequestThrottle() { -#ifndef NDEBUG - ThrottleMap::const_iterator throttle_iter = throttles_.begin(); - for (; throttle_iter != throttles_.end(); ++throttle_iter) { - const PerServerThrottle& throttle = throttle_iter->second; - DCHECK(throttle.num_requests == 0); - DCHECK(!throttle.request_queue.get() || throttle.request_queue->empty()); - } -#endif -} - -BOOL WinHttpRequestThrottle::SubmitRequest(const std::string &server, - HINTERNET request_handle, - DWORD total_size, - DWORD_PTR context) { - PerServerThrottle& throttle = throttles_[server]; - DCHECK(throttle.num_requests >= 0 && - throttle.num_requests <= kMaxConnectionsPerServer); - if (throttle.num_requests >= kMaxConnectionsPerServer) { - if (!throttle.request_queue.get()) - throttle.request_queue.reset(new RequestQueue); - SendRequestArgs args(request_handle, total_size, context); - throttle.request_queue->PushBack(args); - return TRUE; - } - - BOOL ok = SendRequest(request_handle, total_size, context, false); - if (ok) - throttle.num_requests += 1; - return ok; -} - -void WinHttpRequestThrottle::NotifyRequestDone(const std::string& server) { - PerServerThrottle& throttle = throttles_[server]; - DCHECK(throttle.num_requests > 0 && - throttle.num_requests <= kMaxConnectionsPerServer); - throttle.num_requests -= 1; - SendRequestArgs args; - if (throttle.request_queue.get() && - throttle.request_queue->GetFront(&args)) { - throttle.num_requests += 1; - SendRequest(args.request_handle, args.total_size, args.context, true); - } - if (throttles_.size() > static_cast<size_t>(kGarbageCollectionThreshold)) - GarbageCollect(); -} - -void WinHttpRequestThrottle::RemoveRequest(const std::string& server, - HINTERNET request_handle) { - PerServerThrottle& throttle = throttles_[server]; - if (throttle.request_queue.get() && - throttle.request_queue->Remove(request_handle)) - return; - NotifyRequestDone(server); -} - -BOOL WinHttpRequestThrottle::SendRequest(HINTERNET request_handle, - DWORD total_size, - DWORD_PTR context, - bool report_async_error) { - BOOL ok = WinHttpSendRequest(request_handle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - WINHTTP_NO_REQUEST_DATA, - 0, - total_size, - context); - if (!ok && report_async_error) { - WINHTTP_ASYNC_RESULT async_result = { API_SEND_REQUEST, GetLastError() }; - HttpTransactionWinHttp::StatusCallback( - request_handle, context, - WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, - &async_result, sizeof(async_result)); - } - return ok; -} - -WinHttpRequestThrottle::PerServerThrottle::PerServerThrottle() - : num_requests(0) { -} - -WinHttpRequestThrottle::PerServerThrottle::~PerServerThrottle() { -} - -// static -const int WinHttpRequestThrottle::kMaxConnectionsPerServer = 6; - -// static -const int WinHttpRequestThrottle::kGarbageCollectionThreshold = 64; - -void WinHttpRequestThrottle::GarbageCollect() { - ThrottleMap::iterator throttle_iter = throttles_.begin(); - while (throttle_iter != throttles_.end()) { - PerServerThrottle& throttle = throttle_iter->second; - if (throttle.num_requests == 0 && - (!throttle.request_queue.get() || throttle.request_queue->empty())) { - // Erase the current item but keep the iterator valid. - throttles_.erase(throttle_iter++); - } else { - ++throttle_iter; - } - } -} - -} // namespace net - diff --git a/net/http/winhttp_request_throttle.h b/net/http/winhttp_request_throttle.h deleted file mode 100644 index fc20c11..0000000 --- a/net/http/winhttp_request_throttle.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2006-2008 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. - -#ifndef NET_HTTP_WINHTTP_REQUEST_THROTTLE_H_ -#define NET_HTTP_WINHTTP_REQUEST_THROTTLE_H_ - -#include <windows.h> -#include <winhttp.h> - -#include <map> -#include <string> - -#include "base/basictypes.h" -#include "base/linked_ptr.h" -#include "testing/gtest/include/gtest/gtest_prod.h" - -namespace net { - -// The WinHttpRequestThrottle class regulates the rate at which we call -// WinHttpSendRequest, ensuring that at any time there are at most 6 WinHTTP -// requests in progress for each server or proxy. -// -// The throttling is intended to cause WinHTTP to maintain at most 6 -// persistent HTTP connections with each server or proxy. This works well in -// most cases, except when making HTTPS requests via a proxy, in which case -// WinHTTP may open much more than 6 connections to the proxy in spite of our -// rate limiting. -// -// Because we identify a server by its hostname rather than its IP address, -// we also can't distinguish between two different hostnames that resolve to -// the same IP address. -// -// Although WinHTTP has the WINHTTP_OPTION_MAX_CONNS_PER_SERVER option to -// limit the number of connections allowed per server, we can't use it -// because it has two serious bugs: -// 1. It causes WinHTTP to not close idle persistent connections, leaving -// many connections in the CLOSE_WAIT state. This may cause system -// crashes (Blue Screen of Death) when VPN is used. -// 2. It causes WinHTTP to crash intermittently in -// HTTP_REQUEST_HANDLE_OBJECT::OpenProxyTunnel_Fsm() if a proxy is used. -// Therefore, we have to resort to throttling our WinHTTP requests to achieve -// the same effect. -// -// Note on thread safety: The WinHttpRequestThrottle class is only used by -// the IO thread, so it doesn't need to be protected with a lock. The -// drawback is that the time we mark a request done is only approximate. -// We do that in the HttpTransactionWinHttp destructor, rather than in the -// WinHTTP status callback upon receiving HANDLE_CLOSING. -class WinHttpRequestThrottle { - public: - WinHttpRequestThrottle() {} - - virtual ~WinHttpRequestThrottle(); - - // Intended to be a near drop-in replacement of WinHttpSendRequest. - BOOL SubmitRequest(const std::string& server, - HINTERNET request_handle, - DWORD total_size, - DWORD_PTR context); - - // Called when a request failed or completed successfully. - void NotifyRequestDone(const std::string& server); - - // Called from the HttpTransactionWinHttp destructor. - void RemoveRequest(const std::string& server, - HINTERNET request_handle); - - protected: - // Unit tests can stub out this method in a derived class. - virtual BOOL SendRequest(HINTERNET request_handle, - DWORD total_size, - DWORD_PTR context, - bool report_async_error); - - private: - FRIEND_TEST(WinHttpRequestThrottleTest, GarbageCollect); - - class RequestQueue; - - struct PerServerThrottle { - PerServerThrottle(); - ~PerServerThrottle(); - - int num_requests; // Number of requests in progress - linked_ptr<RequestQueue> request_queue; // Requests waiting to be sent - }; - - typedef std::map<std::string, PerServerThrottle> ThrottleMap; - - static const int kMaxConnectionsPerServer; - static const int kGarbageCollectionThreshold; - - void GarbageCollect(); - - ThrottleMap throttles_; - - DISALLOW_EVIL_CONSTRUCTORS(WinHttpRequestThrottle); -}; - -} // namespace net - -#endif // NET_HTTP_WINHTTP_REQUEST_THROTTLE_H_ - diff --git a/net/http/winhttp_request_throttle_unittest.cc b/net/http/winhttp_request_throttle_unittest.cc deleted file mode 100644 index 7ba0022..0000000 --- a/net/http/winhttp_request_throttle_unittest.cc +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2006-2008 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/string_util.h" -#include "net/http/winhttp_request_throttle.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -// Converts an int i to an HINTERNET (void *) request handle. -HINTERNET RequestHandle(int i) { - return reinterpret_cast<HINTERNET>(static_cast<intptr_t>(i)); -} - -class MockRequestThrottle : public net::WinHttpRequestThrottle { - public: - MockRequestThrottle() : last_sent_request_(NULL) { } - - // The request handle of the last sent request. This allows us to determine - // whether a submitted request was sent or queued. - HINTERNET last_sent_request() const { return last_sent_request_; } - - protected: - virtual BOOL SendRequest(HINTERNET request_handle, - DWORD total_size, - DWORD_PTR context, - bool report_async_error) { - last_sent_request_ = request_handle; - return TRUE; - } - - private: - HINTERNET last_sent_request_; - - DISALLOW_EVIL_CONSTRUCTORS(MockRequestThrottle); -}; - -} // namespace - -namespace net { - -TEST(WinHttpRequestThrottleTest, OneServer) { - MockRequestThrottle throttle; - std::string server("http://www.foo.com"); - HINTERNET request_handle; - - // Submit 20 requests to the request throttle. - // Expected outcome: 6 requests should be in progress, and requests 7-20 - // should be queued. - for (int i = 1; i <= 20; i++) { - request_handle = RequestHandle(i); - EXPECT_TRUE(throttle.SubmitRequest(server, request_handle, 0, 0)); - if (i <= 6) - EXPECT_EQ(request_handle, throttle.last_sent_request()); - else - EXPECT_EQ(RequestHandle(6), throttle.last_sent_request()); - } - - // Notify the request throttle of the completion of 10 requests. - // Expected outcome: 6 requests should be in progress, and requests 17-20 - // should be queued. - for (int j = 0; j < 10; j++) { - throttle.NotifyRequestDone(server); - EXPECT_EQ(RequestHandle(7 + j), throttle.last_sent_request()); - } - - // Remove request 17, which is queued. - // Expected outcome: Requests 18-20 should remain queued. - request_handle = RequestHandle(17); - throttle.RemoveRequest(server, request_handle); - EXPECT_EQ(RequestHandle(16), throttle.last_sent_request()); - - // Remove request 16, which is in progress. - // Expected outcome: The request throttle should send request 18. - // Requests 19-20 should remained queued. - request_handle = RequestHandle(16); - throttle.RemoveRequest(server, request_handle); - EXPECT_EQ(RequestHandle(18), throttle.last_sent_request()); - - // Notify the request throttle of the completion of the remaining - // 8 requests. - for (int j = 0; j < 8; j++) { - throttle.NotifyRequestDone(server); - if (j < 2) - EXPECT_EQ(RequestHandle(19 + j), throttle.last_sent_request()); - else - EXPECT_EQ(RequestHandle(20), throttle.last_sent_request()); - } -} - -// Submit requests to a large number (> 64) of servers to force the garbage -// collection of idle PerServerThrottles. -TEST(WinHttpRequestThrottleTest, GarbageCollect) { - MockRequestThrottle throttle; - for (int i = 0; i < 150; i++) { - std::string server("http://www.foo"); - server.append(IntToString(i)); - server.append(".com"); - throttle.SubmitRequest(server, RequestHandle(1), 0, 0); - throttle.NotifyRequestDone(server); - if (i < 64) - EXPECT_EQ(i + 1, throttle.throttles_.size()); - else if (i < 129) - EXPECT_EQ(i - 64, throttle.throttles_.size()); - else - EXPECT_EQ(i - 129, throttle.throttles_.size()); - } -} - -} // namespace net - diff --git a/net/net.xcodeproj/project.pbxproj b/net/net.xcodeproj/project.pbxproj index d085c9f..d183dd9 100644 --- a/net/net.xcodeproj/project.pbxproj +++ b/net/net.xcodeproj/project.pbxproj @@ -141,7 +141,6 @@ 82113A1D0E8434EE00E3848F /* x509_certificate_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 82113A1C0E8434EE00E3848F /* x509_certificate_unittest.cc */; }; 82113A280E84360200E3848F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 82113A270E84360200E3848F /* Security.framework */; }; 82113BBD0E892E5800E3848F /* x509_certificate.cc in Sources */ = {isa = PBXBuildFile; fileRef = 82113BBC0E892E5800E3848F /* x509_certificate.cc */; }; - 821F207B0E5CD342003C7E38 /* cert_status_cache.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED33610E5A194700A747DB /* cert_status_cache.cc */; }; 821F207F0E5CD3C6003C7E38 /* http_vary_data.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED33520E5A194700A747DB /* http_vary_data.cc */; }; 821F20A30E5CD407003C7E38 /* mime_sniffer_proxy.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED33A60E5A198600A747DB /* mime_sniffer_proxy.cc */; }; 821F20A50E5CD414003C7E38 /* url_request_view_cache_job.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BED33A90E5A198600A747DB /* url_request_view_cache_job.cc */; }; @@ -626,12 +625,10 @@ 7BED33570E5A194700A747DB /* http_chunked_decoder_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_chunked_decoder_unittest.cc; sourceTree = "<group>"; }; 7BED33580E5A194700A747DB /* http_util_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_util_unittest.cc; sourceTree = "<group>"; }; 7BED33590E5A194700A747DB /* http_network_transaction_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_network_transaction_unittest.cc; sourceTree = "<group>"; }; - 7BED335A0E5A194700A747DB /* cert_status_cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cert_status_cache.h; sourceTree = "<group>"; }; 7BED335C0E5A194700A747DB /* http_network_layer_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_network_layer_unittest.cc; sourceTree = "<group>"; }; 7BED335D0E5A194700A747DB /* http_network_transaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http_network_transaction.h; sourceTree = "<group>"; }; 7BED335E0E5A194700A747DB /* http_chunked_decoder.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_chunked_decoder.cc; sourceTree = "<group>"; }; 7BED33600E5A194700A747DB /* http_atom_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http_atom_list.h; sourceTree = "<group>"; }; - 7BED33610E5A194700A747DB /* cert_status_cache.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cert_status_cache.cc; sourceTree = "<group>"; }; 7BED33620E5A194700A747DB /* http_network_layer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_network_layer.cc; sourceTree = "<group>"; }; 7BED33630E5A194700A747DB /* http_request_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http_request_info.h; sourceTree = "<group>"; }; 7BED33640E5A194700A747DB /* http_chunked_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http_chunked_decoder.h; sourceTree = "<group>"; }; @@ -1068,8 +1065,6 @@ 7BED33390E5A193400A747DB /* http */ = { isa = PBXGroup; children = ( - 7BED33610E5A194700A747DB /* cert_status_cache.cc */, - 7BED335A0E5A194700A747DB /* cert_status_cache.h */, 7BED33600E5A194700A747DB /* http_atom_list.h */, 0435A4650E8DD69C00E4DF08 /* http_auth.cc */, 0435A4670E8DD6B300E4DF08 /* http_auth.h */, @@ -1473,7 +1468,6 @@ 7B8503FC0E5B2DA200730B43 /* block_files.cc in Sources */, 7BA0172F0E5A244D00044150 /* bzip2_filter.cc in Sources */, 7B8504050E5B2DBD00730B43 /* cache_util_posix.cc in Sources */, - 821F207B0E5CD342003C7E38 /* cert_status_cache.cc in Sources */, E4CE9C0D0E8BFFFA00D5378C /* client_socket_factory.cc in Sources */, 7B8504080E5B2DD800730B43 /* client_socket_handle.cc in Sources */, 7B8504090E5B2DD800730B43 /* client_socket_pool.cc in Sources */, diff --git a/net/net_lib.scons b/net/net_lib.scons index 20d2e6b..af94a53 100644 --- a/net/net_lib.scons +++ b/net/net_lib.scons @@ -153,8 +153,6 @@ input_files = ChromeFileList([ 'url_request/url_request_view_cache_job.h', ]), MSVSFilter('http', [ - 'http/cert_status_cache.cc', - 'http/cert_status_cache.h', 'http/http_atom_list.h', 'http/http_cache.cc', 'http/http_cache.h', @@ -171,8 +169,6 @@ input_files = ChromeFileList([ 'http/http_response_info.h', 'http/http_transaction.h', 'http/http_transaction_factory.h', - 'http/http_transaction_winhttp.cc', - 'http/http_transaction_winhttp.h', 'http/http_util.cc', 'http/http_util.h', 'http/http_auth.cc', @@ -195,8 +191,6 @@ input_files = ChromeFileList([ 'http/http_auth_handler_digest.h', 'http/http_vary_data.cc', 'http/http_vary_data.h', - 'http/winhttp_request_throttle.cc', - 'http/winhttp_request_throttle.h', ]), MSVSFilter('disk_cache', [ 'disk_cache/addr.h', @@ -268,8 +262,6 @@ if env.Bit('posix'): # TODO(port): delete files from this list as they get ported. input_files.Remove( 'base/ssl_config_service.cc', - 'http/http_transaction_winhttp.cc', - 'http/winhttp_request_throttle.cc', 'url_request/url_request_ftp_job.cc', ) diff --git a/net/net_unittests.scons b/net/net_unittests.scons index 17c75ef..fdbdf89 100644 --- a/net/net_unittests.scons +++ b/net/net_unittests.scons @@ -68,10 +68,8 @@ input_files = ChromeFileList([ 'http/http_response_headers_unittest.cc', 'http/http_transaction_unittest.cc', 'http/http_transaction_unittest.h', - 'http/http_transaction_winhttp_unittest.cc', 'http/http_util_unittest.cc', 'http/http_vary_data_unittest.cc', - 'http/winhttp_request_throttle_unittest.cc', ]), MSVSFilter('base', [ 'base/auth_cache_unittest.cc', @@ -117,8 +115,6 @@ if not env.Bit('windows'): input_files.Remove( 'base/wininet_util_unittest.cc', 'build/precompiled_net$OBJSUFFIX', - 'http/http_transaction_winhttp_unittest.cc', - 'http/winhttp_request_throttle_unittest.cc', ) if env.Bit('linux'): diff --git a/net/proxy/proxy_service.cc b/net/proxy/proxy_service.cc index 7f51f52..06141f6 100644 --- a/net/proxy/proxy_service.cc +++ b/net/proxy/proxy_service.cc @@ -19,7 +19,6 @@ #include "net/base/net_errors.h" #include "net/proxy/proxy_config_service_fixed.h" #if defined(OS_WIN) -#include "net/http/http_transaction_winhttp.h" #include "net/proxy/proxy_config_service_win.h" #include "net/proxy/proxy_resolver_winhttp.h" #elif defined(OS_MACOSX) diff --git a/webkit/tools/layout_tests/run_webkit_tests.py b/webkit/tools/layout_tests/run_webkit_tests.py index 49a82b0..c70642e 100755 --- a/webkit/tools/layout_tests/run_webkit_tests.py +++ b/webkit/tools/layout_tests/run_webkit_tests.py @@ -347,9 +347,6 @@ class TestRunner: if self._options.gp_fault_error_box: shell_args.append('--gp-fault-error-box') - if self._options.winhttp: - shell_args.append('--winhttp') - # larger timeout if page heap is enabled. if self._options.time_out_ms: shell_args.append('--time-out-ms=' + self._options.time_out_ms) @@ -771,9 +768,6 @@ if '__main__' == __name__: "of test_shell; option is split on whitespace " "before running. (example: " "--wrapper='valgrind --smc-check=all')") - option_parser.add_option("", "--winhttp", action="store_true", - default=False, - help="Use WinHTTP stack") option_parser.add_option("", "--test-list", action="append", help="read list of tests to run from file", metavar="FILE") diff --git a/webkit/tools/test_shell/test_shell_switches.cc b/webkit/tools/test_shell/test_shell_switches.cc index 54e7af3..bf66faf 100644 --- a/webkit/tools/test_shell/test_shell_switches.cc +++ b/webkit/tools/test_shell/test_shell_switches.cc @@ -45,16 +45,13 @@ const wchar_t kDumpStatsTable[] = L"stats"; // Use a specified cache directory. const wchar_t kCacheDir[] = L"cache-dir"; -// When being run through a memory profiler, trigger memory in use dumps at +// When being run through a memory profiler, trigger memory in use dumps at // startup and just prior to shutdown. const wchar_t kDebugMemoryInUse[] = L"debug-memory-in-use"; // Enable cookies on the file:// scheme. --layout-tests also enables this. const wchar_t kEnableFileCookies[] = L"enable-file-cookies"; -// Enable the winhttp network stack. -const wchar_t kUseWinHttp[] = L"winhttp"; - // Enable tracing events (see base/trace_event.h) const wchar_t kEnableTracing[] = L"enable-tracing"; diff --git a/webkit/tools/test_shell/test_shell_switches.h b/webkit/tools/test_shell/test_shell_switches.h index 22bc982..ce10d3f 100644 --- a/webkit/tools/test_shell/test_shell_switches.h +++ b/webkit/tools/test_shell/test_shell_switches.h @@ -25,7 +25,6 @@ extern const wchar_t kDumpStatsTable[]; extern const wchar_t kCacheDir[]; extern const wchar_t kDebugMemoryInUse[]; extern const wchar_t kEnableFileCookies[]; -extern const wchar_t kUseWinHttp[]; extern const wchar_t kEnableTracing[]; extern const wchar_t kAllowScriptsToCloseWindows[]; extern const wchar_t kCheckLayoutTestSystemDeps[]; diff --git a/webkit/tools/test_shell/test_shell_win.cc b/webkit/tools/test_shell/test_shell_win.cc index d0dc942..1dec4db 100644 --- a/webkit/tools/test_shell/test_shell_win.cc +++ b/webkit/tools/test_shell/test_shell_win.cc @@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "webkit/tools/test_shell/test_shell.h" + #include <windows.h> #include <atlbase.h> #include <commdlg.h> #include <objbase.h> #include <shlwapi.h> -#include <wininet.h> - -#include "webkit/tools/test_shell/test_shell.h" +#include <wininet.h> // For INTERNET_MAX_URL_LENGTH #include "base/command_line.h" #include "base/memory_debug.h" @@ -143,11 +143,6 @@ void TestShell::InitializeTestShell(bool layout_test_mode) { } CommandLine parsed_command_line; - // Make the selection of network stacks early on before any consumers try to - // issue HTTP requests. - if (parsed_command_line.HasSwitch(test_shell::kUseWinHttp)) - net::HttpNetworkLayer::UseWinHttp(true); - if (parsed_command_line.HasSwitch(test_shell::kCrashDumps)) { std::wstring dir( parsed_command_line.GetSwitchValue(test_shell::kCrashDumps)); @@ -223,7 +218,7 @@ bool TestShell::RunFileTest(const char *filename, const TestParams& params) { static_cast<TestShell*>(win_util::GetWindowUserData(hwnd)); shell->ResetTestController(); - // ResetTestController may have closed the window we were holding on to. + // ResetTestController may have closed the window we were holding on to. // Grab the first window again. hwnd = *(TestShell::windowList()->begin()); shell = static_cast<TestShell*>(win_util::GetWindowUserData(hwnd)); @@ -272,7 +267,8 @@ bool TestShell::RunFileTest(const char *filename, const TestParams& params) { // which we handle here. if (!should_dump_as_text) { // Plain text pages should be dumped as text - std::wstring mime_type = webFrame->GetDataSource()->GetResponseMimeType(); + std::wstring mime_type = + webFrame->GetDataSource()->GetResponseMimeType(); should_dump_as_text = (mime_type == L"text/plain"); } if (should_dump_as_text) { @@ -297,7 +293,7 @@ bool TestShell::RunFileTest(const char *filename, const TestParams& params) { printf("%s", WideToUTF8(bfDump).c_str()); } } - + if (params.dump_pixels && !should_dump_as_text) { // Image output: we write the image data to the file given on the // command line (for the dump pixels argument), and the MD5 sum to @@ -342,8 +338,8 @@ std::string TestShell::RewriteLocalUrl(const std::string& url) { // TestShell implementation void TestShell::PlatformCleanUp() { - // When the window is destroyed, tell the Edit field to forget about us, - // otherwise we will crash. + // When the window is destroyed, tell the Edit field to forget about us, + // otherwise we will crash. win_util::SetWindowProc(m_editWnd, default_edit_wnd_proc_); win_util::SetWindowUserData(m_editWnd, NULL); } @@ -358,7 +354,7 @@ bool TestShell::Initialize(const std::wstring& startingURL) { HWND hwnd; int x = 0; - + hwnd = CreateWindow(L"BUTTON", L"Back", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , x, 0, BUTTON_WIDTH, URLBAR_HEIGHT, @@ -386,7 +382,7 @@ bool TestShell::Initialize(const std::wstring& startingURL) { // this control is positioned by ResizeSubViews m_editWnd = CreateWindow(L"EDIT", 0, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | - ES_AUTOVSCROLL | ES_AUTOHSCROLL, + ES_AUTOVSCROLL | ES_AUTOHSCROLL, x, 0, 0, 0, m_mainWnd, 0, instance_handle_, 0); default_edit_wnd_proc_ = @@ -398,7 +394,7 @@ bool TestShell::Initialize(const std::wstring& startingURL) { WebViewHost::Create(m_mainWnd, delegate_.get(), *TestShell::web_prefs_)); webView()->SetUseEditorDelegate(true); delegate_->RegisterDragDrop(); - + // Load our initial content. if (!startingURL.empty()) LoadURL(startingURL.c_str()); @@ -456,8 +452,8 @@ void TestShell::WaitTestFinished() { // Create a watchdog thread which just sets a timer and // kills the process if it times out. This catches really - // bad hangs where the shell isn't coming back to the - // message loop. If the watchdog is what catches a + // bad hangs where the shell isn't coming back to the + // message loop. If the watchdog is what catches a // timeout, it can't do anything except terminate the test // shell, which is unfortunate. finished_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -481,7 +477,7 @@ void TestShell::WaitTestFinished() { SetEvent(finished_event_); // Wait to join the watchdog thread. (up to 1s, then quit) - WaitForSingleObject(thread_handle, 1000); + WaitForSingleObject(thread_handle, 1000); } void TestShell::InteractiveSetFocus(WebWidgetHost* host, bool enable) { @@ -649,7 +645,7 @@ LRESULT CALLBACK TestShell::EditWndProc(HWND hwnd, UINT message, case WM_CHAR: if (wParam == VK_RETURN) { wchar_t strPtr[MAX_URL_LENGTH + 1]; // Leave room for adding a NULL; - *((LPWORD)strPtr) = MAX_URL_LENGTH; + *((LPWORD)strPtr) = MAX_URL_LENGTH; LRESULT strLen = SendMessage(hwnd, EM_GETLINE, 0, (LPARAM)strPtr); if (strLen > 0) { strPtr[strLen] = 0; // EM_GETLINE doesn't NULL terminate. |