diff options
author | joi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-25 21:11:53 +0000 |
---|---|---|
committer | joi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-03-25 21:11:53 +0000 |
commit | 227b0e8d0e0f62dc2ee2a50aca77de83ff394278 (patch) | |
tree | e185402e8a1da224dc3ac55ebd0fa295ce07a5ad | |
parent | 76c551c6fe7dcfc664b9261eaec812a1966d1984 (diff) | |
download | chromium_src-227b0e8d0e0f62dc2ee2a50aca77de83ff394278.zip chromium_src-227b0e8d0e0f62dc2ee2a50aca77de83ff394278.tar.gz chromium_src-227b0e8d0e0f62dc2ee2a50aca77de83ff394278.tar.bz2 |
Support enabling/disabling the URL request throttler via the about:net-internals page:
- Add a new tab to the about:net-internals page.
- Add a preference item to persist user's choice.
- Remove the command line switch --disable-enforced-throttling.
- Make throttling feature off by default for now.
This is 95% based on yzshen@chromium.org's patch
http://codereview.chromium.org/6286001/ which was never landed. The
changes that have been made from that patch are mostly cosmetic, apart
from updating it to match the codebase (the patch was prepared ~2
months ago) and responding to eroman@'s initial round of code review
comments.
BUG=66062
TEST=Make sure the checkbox on about:net-internals > HTTP Throttling is checked.
(1) Type in the addresss bar a URL which is expected to return 5XX.
(2) Keep clicking the "reload" button.
(3) After a few clicks, Chrome displays an error page explaining why a net::ERR_TEMPORARILY_THROTTLED error occurs.
Make sure the checkbox on about:net-internals > HTTP Throttling is unchecked.
Following step (1) and (2) described above won't result in a net::ERR_TEMPORARILY_THROTTLED error page.
Review URL: http://codereview.chromium.org/6677085
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@79455 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/app/generated_resources.grd | 9 | ||||
-rw-r--r-- | chrome/browser/browser_main.cc | 4 | ||||
-rw-r--r-- | chrome/browser/net/net_pref_observer.cc | 33 | ||||
-rw-r--r-- | chrome/browser/net/net_pref_observer.h | 6 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/httpthrottlingview.js | 34 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/index.html | 22 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/main.css | 11 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/main.js | 31 | ||||
-rw-r--r-- | chrome/browser/ui/webui/net_internals_ui.cc | 81 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 6 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 | ||||
-rw-r--r-- | chrome/common/pref_names.cc | 3 | ||||
-rw-r--r-- | chrome/common/pref_names.h | 1 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.cc | 10 | ||||
-rw-r--r-- | net/url_request/url_request_throttler_entry.cc | 14 | ||||
-rw-r--r-- | net/url_request/url_request_throttler_manager.cc | 26 | ||||
-rw-r--r-- | net/url_request/url_request_throttler_manager.h | 14 | ||||
-rw-r--r-- | net/url_request/url_request_throttler_unittest.cc | 2 |
18 files changed, 266 insertions, 42 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 2717ec4..2eb87d1 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -6276,9 +6276,14 @@ Keep your key file in a safe place. You will need it to create new versions of y </message> <message name="IDS_ERRORPAGES_SUMMARY_TEMPORARILY_THROTTLED" desc="Summary in the error page when we temporarily stop sending requests to a server in order to avoid DDoS."> - It is likely that the server hosting the webpage has been overloaded or encountered an error. In order to avoid causing too much traffic and making the situation worse, <ph name="PRODUCT_NAME"><span jscontent="productName"></span><ex>Google Chrome</ex></ph> has temporarily stopped allowing requests to the server. + It is likely that the server hosting the webpage has been overloaded or encountered an error. In order to avoid causing + too much traffic and making the situation worse, + <ph name="PRODUCT_NAME"><span jscontent="productName"></span><ex>Google Chrome</ex></ph> has temporarily + stopped allowing requests to the server. <ph name="LINE_BREAK"><br /><br /></ph> - If you think this behavior is undesirable, for example, you are debugging your own website, you could disable it by relaunching <ph name="PRODUCT_NAME"><span jscontent="productName"></span><ex>Google Chrome</ex></ph> with the command line flag <ph name="COMMAND_LINE_FLAG"><strong>--disable-enforced-throttling</strong></ph>. + If you think this behavior is undesirable, for example, you are debugging your own website, please + visit the <ph name="NET_INTERNALS_PAGE"><strong>chrome://net-internals/#httpThrottling</strong></ph> page, + where you can find more information or disable the feature. </message> <message name="IDS_ERRORPAGES_DETAILS_TEMPORARILY_THROTTLED" desc="The error message displayed when we temporarily stop sending requests to a server in order to avoid DDoS."> Requests to the server have been temporarily throttled. diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc index 66b13d7..b4db556 100644 --- a/chrome/browser/browser_main.cc +++ b/chrome/browser/browser_main.cc @@ -626,8 +626,8 @@ void InitializeNetworkOptions(const CommandLine& parsed_command_line) { net::SpdySessionPool::set_max_sessions_per_domain(value); } - net::URLRequestThrottlerManager::GetInstance()->InitializeOptions( - parsed_command_line.HasSwitch(switches::kDisableEnforcedThrottling)); + net::URLRequestThrottlerManager::GetInstance()->set_enable_thread_checks( + true); SetDnsCertProvenanceCheckerFactory(CreateChromeDnsCertProvenanceChecker); } diff --git a/chrome/browser/net/net_pref_observer.cc b/chrome/browser/net/net_pref_observer.cc index 48a051c..75dd11a 100644 --- a/chrome/browser/net/net_pref_observer.cc +++ b/chrome/browser/net/net_pref_observer.cc @@ -4,20 +4,35 @@ #include "chrome/browser/net/net_pref_observer.h" +#include "base/task.h" #include "chrome/browser/net/predictor_api.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/common/pref_names.h" #include "content/browser/browser_thread.h" #include "content/common/notification_type.h" +#include "content/common/notification_details.h" #include "net/http/http_stream_factory.h" +#include "net/url_request/url_request_throttler_manager.h" + +namespace { + +// Function (for NewRunnableFunction) to call the set_enforce_throttling +// member on the URLRequestThrottlerManager singleton. +void SetEnforceThrottlingOnThrottlerManager(bool enforce) { + net::URLRequestThrottlerManager::GetInstance()->set_enforce_throttling( + enforce); +} + +} NetPrefObserver::NetPrefObserver(PrefService* prefs) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); dns_prefetching_enabled_.Init(prefs::kDnsPrefetchingEnabled, prefs, this); spdy_disabled_.Init(prefs::kDisableSpdy, prefs, this); + http_throttling_enabled_.Init(prefs::kHttpThrottlingEnabled, prefs, this); - ApplySettings(); + ApplySettings(NULL); } NetPrefObserver::~NetPrefObserver() { @@ -27,16 +42,28 @@ NetPrefObserver::~NetPrefObserver() { void NetPrefObserver::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { - ApplySettings(); + DCHECK_EQ(type.value, NotificationType::PREF_CHANGED); + + std::string* pref_name = Details<std::string>(details).ptr(); + ApplySettings(pref_name); } -void NetPrefObserver::ApplySettings() { +void NetPrefObserver::ApplySettings(const std::string* pref_name) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + chrome_browser_net::EnablePredictor(*dns_prefetching_enabled_); net::HttpStreamFactory::set_spdy_enabled(!*spdy_disabled_); + + if (!pref_name || *pref_name == prefs::kHttpThrottlingEnabled) { + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + NewRunnableFunction(SetEnforceThrottlingOnThrottlerManager, + *http_throttling_enabled_)); + } } // static void NetPrefObserver::RegisterPrefs(PrefService* prefs) { prefs->RegisterBooleanPref(prefs::kDisableSpdy, false); + prefs->RegisterBooleanPref(prefs::kHttpThrottlingEnabled, false); } diff --git a/chrome/browser/net/net_pref_observer.h b/chrome/browser/net/net_pref_observer.h index b5954231..a1fd2bd 100644 --- a/chrome/browser/net/net_pref_observer.h +++ b/chrome/browser/net/net_pref_observer.h @@ -6,6 +6,8 @@ #define CHROME_BROWSER_NET_NET_PREF_OBSERVER_H_ #pragma once +#include <string> + #include "base/basictypes.h" #include "chrome/browser/prefs/pref_member.h" #include "content/common/notification_observer.h" @@ -26,10 +28,12 @@ class NetPrefObserver : public NotificationObserver { static void RegisterPrefs(PrefService* prefs); private: - void ApplySettings(); + // If |pref_name| is NULL, all monitored preferences will be applied. + void ApplySettings(const std::string* pref_name); BooleanPrefMember dns_prefetching_enabled_; BooleanPrefMember spdy_disabled_; + BooleanPrefMember http_throttling_enabled_; DISALLOW_COPY_AND_ASSIGN(NetPrefObserver); }; diff --git a/chrome/browser/resources/net_internals/httpthrottlingview.js b/chrome/browser/resources/net_internals/httpthrottlingview.js new file mode 100644 index 0000000..4cc8305 --- /dev/null +++ b/chrome/browser/resources/net_internals/httpthrottlingview.js @@ -0,0 +1,34 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * This view displays information related to HTTP throttling. + * @constructor + */ +function HttpThrottlingView(mainBoxId, enableCheckboxId) { + DivView.call(this, mainBoxId); + + this.enableCheckbox_ = document.getElementById(enableCheckboxId); + this.enableCheckbox_.onclick = this.onEnableCheckboxClicked_.bind(this); + + g_browser.addHttpThrottlingObserver(this); +} + +inherits(HttpThrottlingView, DivView); + +/** + * Gets informed that HTTP throttling has been enabled/disabled. + * @param {boolean} enabled HTTP throttling has been enabled. + */ +HttpThrottlingView.prototype.onHttpThrottlingEnabledPrefChanged = function( + enabled) { + this.enableCheckbox_.checked = enabled; +}; + +/** + * Handler for the onclick event of the checkbox. + */ +HttpThrottlingView.prototype.onEnableCheckboxClicked_ = function() { + g_browser.enableHttpThrottling(this.enableCheckbox_.checked); +};
\ No newline at end of file diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html index c18da47..32b0518 100644 --- a/chrome/browser/resources/net_internals/index.html +++ b/chrome/browser/resources/net_internals/index.html @@ -1,7 +1,7 @@ <!DOCTYPE HTML> <head i18n-values="dir:textdirection;"> <!-- -Copyright (c) 2010 The Chromium Authors. All rights reserved. +Copyright (c) 2011 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> @@ -30,6 +30,7 @@ found in the LICENSE file. <script src="socketsview.js"></script> <script src="spdyview.js"></script> <script src="serviceprovidersview.js"></script> + <script src="httpthrottlingview.js"></script> </head> <body onload="onLoaded()"> <!-- Tab switcher for main categories. --> @@ -42,6 +43,7 @@ found in the LICENSE file. <li><a href="#sockets" id=socketsTab>Sockets</a></li> <li><a href="#spdy" id=spdyTab>SPDY</a></li> <li><a href="#httpCache" id=httpCacheTab>HTTP Cache</a></li> + <li><a href="#httpThrottling" id=httpThrottlingTab>HTTP Throttling</a></li> <!-- Tab is only shown on Windows --> <li><a href="#serviceProviders" id=serviceProvidersTab style="display: none;">SPIs</a></li> <li><a href="#tests" id=testTab>Tests</a></li> @@ -181,6 +183,24 @@ found in the LICENSE file. <h4>Statistics</h4> <div id=httpCacheStats>Nothing loaded yet.</div> </div> + <div id=httpThrottlingTabContent> + <p> + In order to prevent Distributed Denial of Service (DDoS) attacks from + being perpetrated by web pages and extensions that run within Chrome, the + HTTP throttling mechanism keeps track of errors requesting a given URL + (minus the query parameters), and after a few 5xx errors in a row, starts + exponentially increasing an interval during which requests to the + given URL are disallowed. + </p><p> + You may enable or disable the feature below. Please let us know if the + feature is causing problems for your web site. More details and contact + information at + <a href="http://dev.chromium.org/throttling">http://dev.chromium.org/throttling</a>. + </p> + <p><input id=enableHttpThrottlingCheckbox type=checkbox /> + Throttle HTTP requests if the server has been overloaded or encountered an error. + </p> + </div> <!-- Only shown on Windows --> <div id=serviceProvidersTabContent style="display: none;"> <h4>Layered Service Providers</h4> diff --git a/chrome/browser/resources/net_internals/main.css b/chrome/browser/resources/net_internals/main.css index 46a10c5..f7c575c 100644 --- a/chrome/browser/resources/net_internals/main.css +++ b/chrome/browser/resources/net_internals/main.css @@ -1,5 +1,5 @@ /* -Copyright (c) 2010 The Chromium Authors. All rights reserved. +Copyright (c) 2011 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ @@ -162,7 +162,8 @@ body { #spdyTabContent, #serviceProvidersTabContent, #testTabContent, -#hstsTabContent { +#hstsTabContent, +#httpThrottlingTabContent { overflow: auto; padding: 10px; } @@ -183,8 +184,8 @@ table.styledTable, .styledTable th, .styledTable td { border: 1px solid #777; - padding-right: 4px; - padding-left: 4px; + padding-right: 4px; + padding-left: 4px; } .styledTable th { @@ -195,7 +196,7 @@ table.styledTable, background: rgb(255,217,217); } -/* +/* * This is the box in the top right of the Data tab which shows how many * events have been captured so far. */ diff --git a/chrome/browser/resources/net_internals/main.js b/chrome/browser/resources/net_internals/main.js index 561770b..979ac96 100644 --- a/chrome/browser/resources/net_internals/main.js +++ b/chrome/browser/resources/net_internals/main.js @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -120,6 +120,9 @@ function onLoaded() { 'namespaceProvidersTbody'); } + var httpThrottlingView = new HttpThrottlingView( + 'httpThrottlingTabContent', 'enableHttpThrottlingCheckbox'); + // Create a view which lets you tab between the different sub-views. var categoryTabSwitcher = new TabSwitcherView('categoryTabHandles'); g_browser.setTabSwitcher(categoryTabSwitcher); @@ -136,6 +139,7 @@ function onLoaded() { categoryTabSwitcher.addTab('serviceProvidersTab', serviceView, false); categoryTabSwitcher.addTab('testTab', testView, false); categoryTabSwitcher.addTab('hstsTab', hstsView, false); + categoryTabSwitcher.addTab('httpThrottlingTab', httpThrottlingView, false); // Build a map from the anchor name of each tab handle to its "tab ID". // We will consider navigations to the #hash as a switch tab request. @@ -178,6 +182,7 @@ function BrowserBridge() { this.logObservers_ = []; this.connectionTestsObservers_ = []; this.hstsObservers_ = []; + this.httpThrottlingObservers_ = []; this.pollableDataHelpers_ = {}; this.pollableDataHelpers_.proxySettings = @@ -352,7 +357,11 @@ BrowserBridge.prototype.enableIPv6 = function() { BrowserBridge.prototype.setLogLevel = function(logLevel) { chrome.send('setLogLevel', ['' + logLevel]); -} +}; + +BrowserBridge.prototype.enableHttpThrottling = function(enable) { + chrome.send('enableHttpThrottling', [enable]); +}; BrowserBridge.prototype.loadLogFile = function() { chrome.send('loadLogFile'); @@ -502,6 +511,14 @@ BrowserBridge.prototype.receivedHttpCacheInfo = function(info) { this.pollableDataHelpers_.httpCacheInfo.update(info); }; +BrowserBridge.prototype.receivedHttpThrottlingEnabledPrefChanged = function( + enabled) { + for (var i = 0; i < this.httpThrottlingObservers_.length; ++i) { + this.httpThrottlingObservers_[i].onHttpThrottlingEnabledPrefChanged( + enabled); + } +}; + BrowserBridge.prototype.loadedLogFile = function(logFileContents) { var match; // Replace carriage returns with linebreaks and then split around linebreaks. @@ -730,6 +747,16 @@ BrowserBridge.prototype.addHSTSObserver = function(observer) { }; /** + * Adds a listener for HTTP throttling-related events. |observer| will be called + * back when HTTP throttling is enabled/disabled, through: + * + * observer.onHttpThrottlingEnabledPrefChanged(enabled); + */ +BrowserBridge.prototype.addHttpThrottlingObserver = function(observer) { + this.httpThrottlingObservers_.push(observer); +}; + +/** * The browser gives us times in terms of "time ticks" in milliseconds. * This function converts the tick count to a Date() object. * diff --git a/chrome/browser/ui/webui/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals_ui.cc index a440a39..641012c 100644 --- a/chrome/browser/ui/webui/net_internals_ui.cc +++ b/chrome/browser/ui/webui/net_internals_ui.cc @@ -26,6 +26,7 @@ #include "chrome/browser/net/passive_log_collector.h" #include "chrome/browser/net/url_fixer_upper.h" #include "chrome/browser/platform_util.h" +#include "chrome/browser/prefs/pref_member.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/shell_dialogs.h" #include "chrome/browser/ui/webui/chrome_url_data_manager.h" @@ -33,10 +34,12 @@ #include "chrome/common/chrome_version_info.h" #include "chrome/common/jstemplate_builder.h" #include "chrome/common/net/url_request_context_getter.h" +#include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "content/browser/browser_thread.h" #include "content/browser/tab_contents/tab_contents.h" #include "content/browser/tab_contents/tab_contents_view.h" +#include "content/common/notification_details.h" #include "grit/generated_resources.h" #include "grit/net_internals_resources.h" #include "net/base/escape.h" @@ -136,14 +139,15 @@ class NetInternalsHTMLSource : public ChromeURLDataManager::DataSource { // this class's methods are expected to run on the UI thread. // // Since the network code we want to run lives on the IO thread, we proxy -// everything over to NetInternalsMessageHandler::IOThreadImpl, which runs -// on the IO thread. +// almost everything over to NetInternalsMessageHandler::IOThreadImpl, which +// runs on the IO thread. // // TODO(eroman): Can we start on the IO thread to begin with? class NetInternalsMessageHandler : public WebUIMessageHandler, public SelectFileDialog::Listener, - public base::SupportsWeakPtr<NetInternalsMessageHandler> { + public base::SupportsWeakPtr<NetInternalsMessageHandler>, + public NotificationObserver { public: NetInternalsMessageHandler(); virtual ~NetInternalsMessageHandler(); @@ -157,6 +161,15 @@ class NetInternalsMessageHandler void CallJavascriptFunction(const std::wstring& function_name, const Value* value); + // NotificationObserver implementation. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + // Javascript message handlers. + void OnRendererReady(const ListValue* list); + void OnEnableHttpThrottling(const ListValue* list); + // SelectFileDialog::Listener implementation virtual void FileSelected(const FilePath& path, int index, void* params); virtual void FileSelectionCanceled(void* params); @@ -188,6 +201,14 @@ class NetInternalsMessageHandler const FilePath path_; }; + // The pref member about whether HTTP throttling is enabled, which needs to + // be accessed on the UI thread. + BooleanPrefMember http_throttling_enabled_; + + // OnRendererReady invokes this callback to do the part of message handling + // that needs to happen on the IO thread. + scoped_ptr<WebUI::MessageCallback> renderer_ready_io_callback_; + // This is the "real" message handler, which lives on the IO thread. scoped_refptr<IOThreadImpl> proxy_; @@ -340,7 +361,7 @@ class NetInternalsMessageHandler::IOThreadImpl scoped_ptr<ListValue> pending_entries_; }; -// Helper class for a WebUI::MessageCallback which when excuted calls +// Helper class for a WebUI::MessageCallback which when executed calls // instance->*method(value) on the IO thread. class NetInternalsMessageHandler::IOThreadImpl::CallbackHelper : public WebUI::MessageCallback { @@ -449,8 +470,16 @@ NetInternalsMessageHandler::~NetInternalsMessageHandler() { WebUIMessageHandler* NetInternalsMessageHandler::Attach(WebUI* web_ui) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + PrefService* pref_service = web_ui->GetProfile()->GetPrefs(); + http_throttling_enabled_.Init(prefs::kHttpThrottlingEnabled, pref_service, + this); + proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread(), web_ui->GetProfile()->GetRequestContext()); + renderer_ready_io_callback_.reset( + proxy_->CreateCallback(&IOThreadImpl::OnRendererReady)); + WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui); return result; } @@ -487,7 +516,7 @@ void NetInternalsMessageHandler::RegisterMessages() { web_ui_->RegisterMessageCallback( "notifyReady", - proxy_->CreateCallback(&IOThreadImpl::OnRendererReady)); + NewCallback(this, &NetInternalsMessageHandler::OnRendererReady)); web_ui_->RegisterMessageCallback( "getProxySettings", proxy_->CreateCallback(&IOThreadImpl::OnGetProxySettings)); @@ -546,6 +575,10 @@ void NetInternalsMessageHandler::RegisterMessages() { web_ui_->RegisterMessageCallback( "setLogLevel", proxy_->CreateCallback(&IOThreadImpl::OnSetLogLevel)); + + web_ui_->RegisterMessageCallback( + "enableHttpThrottling", + NewCallback(this, &NetInternalsMessageHandler::OnEnableHttpThrottling)); } void NetInternalsMessageHandler::CallJavascriptFunction( @@ -559,6 +592,44 @@ void NetInternalsMessageHandler::CallJavascriptFunction( } } +void NetInternalsMessageHandler::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK_EQ(type.value, NotificationType::PREF_CHANGED); + + std::string* pref_name = Details<std::string>(details).ptr(); + if (*pref_name == prefs::kHttpThrottlingEnabled) { + scoped_ptr<Value> enabled( + Value::CreateBooleanValue(*http_throttling_enabled_)); + + CallJavascriptFunction( + L"g_browser.receivedHttpThrottlingEnabledPrefChanged", enabled.get()); + } +} + +void NetInternalsMessageHandler::OnRendererReady(const ListValue* list) { + CHECK(renderer_ready_io_callback_.get()); + renderer_ready_io_callback_->Run(list); + + scoped_ptr<Value> enabled( + Value::CreateBooleanValue(*http_throttling_enabled_)); + CallJavascriptFunction( + L"g_browser.receivedHttpThrottlingEnabledPrefChanged", enabled.get()); +} + +void NetInternalsMessageHandler::OnEnableHttpThrottling(const ListValue* list) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + bool enable = false; + if (!list->GetBoolean(0, &enable)) { + NOTREACHED(); + return; + } + + http_throttling_enabled_.SetValue(enable); +} + //////////////////////////////////////////////////////////////////////////////// // // NetInternalsMessageHandler::ReadLogFileTask diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index b7c237e..7fcece0 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -209,12 +209,6 @@ const char kDisableDevTools[] = "disable-dev-tools"; // Disables device orientation events. const char kDisableDeviceOrientation[] = "disable-device-orientation"; -// By default, if the URL request throttler finds that a server is overloaded or -// encounters an error, it rejects requests to the server for a period of time, -// which is determined by an exponential back-off algorithm. This switch -// disables such behavior. -const char kDisableEnforcedThrottling[] = "disable-enforced-throttling"; - // Disable extensions. const char kDisableExtensions[] = "disable-extensions"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 4604e0e..d667e19 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -71,7 +71,6 @@ extern const char kDisableConnectBackupJobs[]; extern const char kDisableCustomJumpList[]; extern const char kDisableDevTools[]; extern const char kDisableDeviceOrientation[]; -extern const char kDisableEnforcedThrottling[]; extern const char kDisableExtensionsFileAccessCheck[]; extern const char kDisableExtensions[]; extern const char kDisableFlashSandbox[]; diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 04d2e0a..9b4c1f7 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -674,6 +674,9 @@ const char kEnableTranslate[] = "translate.enabled"; const char kPinnedTabs[] = "pinned_tabs"; +// Boolean that is true when HTTP throttling is enabled. +const char kHttpThrottlingEnabled[] = "http_throttling.enabled"; + // Integer that specifies the policy refresh rate for user policy in // milliseconds. Not all values are meaningful, so it is clamped to a sane // range by the cloud policy subsystem. diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 1550df6..1ae19e6 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -240,6 +240,7 @@ extern const char kAutofillPersonalDataManagerFirstRun[]; extern const char kUseVerticalTabs[]; extern const char kEnableTranslate[]; extern const char kPinnedTabs[]; +extern const char kHttpThrottlingEnabled[]; extern const char kPolicyUserPolicyRefreshRate[]; extern const char kPolicyDevicePolicyRefreshRate[]; diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 111146c..a51e239 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc @@ -317,8 +317,14 @@ void URLRequestHttpJob::StartTransaction() { rv = request_->context()->http_transaction_factory()->CreateTransaction( &transaction_); if (rv == OK) { - rv = transaction_->Start( - &request_info_, &start_callback_, request_->net_log()); + if (!URLRequestThrottlerManager::GetInstance()->enforce_throttling() || + !throttling_entry_->IsDuringExponentialBackoff()) { + rv = transaction_->Start( + &request_info_, &start_callback_, request_->net_log()); + } else { + // Special error code for the exponential back-off module. + rv = ERR_TEMPORARILY_THROTTLED; + } // Make sure the context is alive for the duration of the // transaction. context_ = request_->context(); diff --git a/net/url_request/url_request_throttler_entry.cc b/net/url_request/url_request_throttler_entry.cc index 05b2af2..0fdef2b 100644 --- a/net/url_request/url_request_throttler_entry.cc +++ b/net/url_request/url_request_throttler_entry.cc @@ -58,6 +58,20 @@ URLRequestThrottlerEntry::URLRequestThrottlerEntry( } bool URLRequestThrottlerEntry::IsEntryOutdated() const { + // This function is called by the URLRequestThrottlerManager to determine + // whether entries should be discarded from its url_entries_ map. We + // want to ensure that it does not remove entries from the map while there + // are clients (objects other than the manager) holding references to + // the entry, otherwise separate clients could end up holding separate + // entries for a request to the same URL, which is undesirable. Therefore, + // if an entry has more than one reference (the map will always hold one), + // it should not be considered outdated. + // + // TODO(joi): Once the manager is not a Singleton, revisit whether + // refcounting is needed at all. + if (!HasOneRef()) + return false; + // If there are send events in the sliding window period, we still need this // entry. if (!send_log_.empty() && diff --git a/net/url_request/url_request_throttler_manager.cc b/net/url_request/url_request_throttler_manager.cc index 635c716..de8b817 100644 --- a/net/url_request/url_request_throttler_manager.cc +++ b/net/url_request/url_request_throttler_manager.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -18,7 +18,7 @@ URLRequestThrottlerManager* URLRequestThrottlerManager::GetInstance() { scoped_refptr<URLRequestThrottlerEntryInterface> URLRequestThrottlerManager::RegisterRequestUrl(const GURL &url) { - DCHECK(being_tested_ || CalledOnValidThread()); + DCHECK(!enable_thread_checks_ || CalledOnValidThread()); // Normalize the url. std::string url_id = GetIdFromUrl(url); @@ -52,15 +52,27 @@ void URLRequestThrottlerManager::EraseEntryForTests(const GURL& url) { url_entries_.erase(url_id); } -void URLRequestThrottlerManager::InitializeOptions(bool enforce_throttling) { - enforce_throttling_ = enforce_throttling; - being_tested_ = false; +void URLRequestThrottlerManager::set_enable_thread_checks(bool enable) { + enable_thread_checks_ = enable; } +bool URLRequestThrottlerManager::enable_thread_checks() const { + return enable_thread_checks_; +} + +void URLRequestThrottlerManager::set_enforce_throttling(bool enforce) { + enforce_throttling_ = enforce; +} + +bool URLRequestThrottlerManager::enforce_throttling() { + return enforce_throttling_; +} + +// TODO(joi): Turn throttling on by default when appropriate. URLRequestThrottlerManager::URLRequestThrottlerManager() : requests_since_last_gc_(0), - enforce_throttling_(true), - being_tested_(true) { + enforce_throttling_(false), + enable_thread_checks_(false) { // Construction/destruction is on main thread (because BrowserMain // retrieves an instance to call InitializeOptions), but is from then on // used on I/O thread. diff --git a/net/url_request/url_request_throttler_manager.h b/net/url_request/url_request_throttler_manager.h index c48e917..d65b20f 100644 --- a/net/url_request/url_request_throttler_manager.h +++ b/net/url_request/url_request_throttler_manager.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -53,9 +53,15 @@ class URLRequestThrottlerManager : public base::NonThreadSafe { // It is only used by unit tests. void EraseEntryForTests(const GURL& url); - void InitializeOptions(bool enforce_throttling); + // Turns threading model verification on or off. Any code that correctly + // uses the network stack should preferably call this function to enable + // verification of correct adherence to the network stack threading model. + void set_enable_thread_checks(bool enable); + bool enable_thread_checks() const; - bool enforce_throttling() const { return enforce_throttling_; } + // Whether throttling is enabled or not. + void set_enforce_throttling(bool enforce); + bool enforce_throttling(); protected: URLRequestThrottlerManager(); @@ -113,7 +119,7 @@ class URLRequestThrottlerManager : public base::NonThreadSafe { // // TODO(joi): See if we can fix the offending unit tests and remove this // workaround. - bool being_tested_; + bool enable_thread_checks_; DISALLOW_COPY_AND_ASSIGN(URLRequestThrottlerManager); }; diff --git a/net/url_request/url_request_throttler_unittest.cc b/net/url_request/url_request_throttler_unittest.cc index 5ca56b9..9e33587 100644 --- a/net/url_request/url_request_throttler_unittest.cc +++ b/net/url_request/url_request_throttler_unittest.cc @@ -33,7 +33,7 @@ class MockBackoffEntry : public BackoffEntry { return fake_now_; } - void SetFakeNow(TimeTicks now) { + void SetFakeNow(const TimeTicks& now) { fake_now_ = now; } |