summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-30 20:18:22 +0000
committertburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-30 20:18:22 +0000
commit5a07c19cb57f297222a4bf036f2995b194223b2d (patch)
tree1a465cd26a6516730864793af195663390e7e7df
parent109acb8db570f1a9958b70f5284699ea0c18b036 (diff)
downloadchromium_src-5a07c19cb57f297222a4bf036f2995b194223b2d.zip
chromium_src-5a07c19cb57f297222a4bf036f2995b194223b2d.tar.gz
chromium_src-5a07c19cb57f297222a4bf036f2995b194223b2d.tar.bz2
Adding histograms showing fraction of page load times spent in the disk cache, for full and partial page loads.
R=mmenke@chromium.org, jam@chromium.org, willchan@chromium.org, brettw@chromium.org BUG=139210 Review URL: https://chromiumcodereview.appspot.com/10736066 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149007 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/api/web_request/web_request_api_unittest.cc6
-rw-r--r--chrome/browser/io_thread.cc5
-rw-r--r--chrome/browser/io_thread.h2
-rw-r--r--chrome/browser/net/cache_stats.cc342
-rw-r--r--chrome/browser/net/cache_stats.h127
-rw-r--r--chrome/browser/net/chrome_fraudulent_certificate_reporter_unittest.cc11
-rw-r--r--chrome/browser/net/chrome_network_delegate.cc14
-rw-r--r--chrome/browser/net/chrome_network_delegate.h12
-rw-r--r--chrome/browser/net/chrome_url_request_context.cc12
-rw-r--r--chrome/browser/net/chrome_url_request_context.h14
-rw-r--r--chrome/browser/profiles/off_the_record_profile_io_data.cc6
-rw-r--r--chrome/browser/profiles/off_the_record_profile_io_data.h3
-rw-r--r--chrome/browser/profiles/profile_impl_io_data.cc10
-rw-r--r--chrome/browser/profiles/profile_impl_io_data.h2
-rw-r--r--chrome/browser/profiles/profile_io_data.cc20
-rw-r--r--chrome/browser/profiles/profile_io_data.h15
-rw-r--r--chrome/browser/ui/tab_contents/tab_contents.cc3
-rw-r--r--chrome/browser/ui/tab_contents/tab_contents.h5
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--content/shell/shell_network_delegate.cc5
-rw-r--r--content/shell/shell_network_delegate.h2
-rw-r--r--net/base/network_delegate.cc6
-rw-r--r--net/base/network_delegate.h20
-rw-r--r--net/http/http_cache.cc7
-rw-r--r--net/http/http_cache.h3
-rw-r--r--net/http/http_cache_transaction.cc86
-rw-r--r--net/http/http_cache_transaction.h7
-rw-r--r--net/http/http_cache_unittest.cc165
-rw-r--r--net/http/http_network_layer.cc3
-rw-r--r--net/http/http_network_layer.h5
-rw-r--r--net/http/http_network_layer_unittest.cc10
-rw-r--r--net/http/http_transaction_delegate.h23
-rw-r--r--net/http/http_transaction_factory.h7
-rw-r--r--net/http/http_transaction_unittest.cc5
-rw-r--r--net/http/http_transaction_unittest.h5
-rw-r--r--net/net.gyp1
-rw-r--r--net/proxy/network_delegate_error_observer_unittest.cc3
-rw-r--r--net/proxy/proxy_script_fetcher_impl_unittest.cc4
-rw-r--r--net/tools/fetch/fetch_client.cc2
-rw-r--r--net/url_request/url_request_context_builder.cc4
-rw-r--r--net/url_request/url_request_http_job.cc47
-rw-r--r--net/url_request/url_request_http_job.h6
-rw-r--r--net/url_request/url_request_job.cc1
-rw-r--r--net/url_request/url_request_job.h3
-rw-r--r--net/url_request/url_request_test_util.cc4
-rw-r--r--net/url_request/url_request_test_util.h2
-rw-r--r--net/websockets/websocket_job_spdy2_unittest.cc3
-rw-r--r--net/websockets/websocket_job_spdy3_unittest.cc3
-rw-r--r--webkit/tools/test_shell/simple_resource_loader_bridge.cc4
49 files changed, 940 insertions, 117 deletions
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index 756566a..175926a 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -127,7 +127,8 @@ class ExtensionWebRequestTest : public testing::Test {
prefs::kEnableReferrers, profile_.GetTestingPrefService(), NULL);
network_delegate_.reset(new ChromeNetworkDelegate(
event_router_.get(), NULL, NULL, &profile_,
- CookieSettings::Factory::GetForProfile(&profile_), &enable_referrers_));
+ CookieSettings::Factory::GetForProfile(&profile_), &enable_referrers_,
+ NULL));
context_.reset(new TestURLRequestContext(true));
context_->set_network_delegate(network_delegate_.get());
context_->Init();
@@ -441,7 +442,8 @@ class ExtensionWebRequestHeaderModificationTest :
prefs::kEnableReferrers, profile_.GetTestingPrefService(), NULL);
network_delegate_.reset(new ChromeNetworkDelegate(
event_router_.get(), NULL, NULL, &profile_,
- CookieSettings::Factory::GetForProfile(&profile_), &enable_referrers_));
+ CookieSettings::Factory::GetForProfile(&profile_), &enable_referrers_,
+ NULL));
context_.reset(new TestURLRequestContext(true));
host_resolver_.reset(new net::MockHostResolver());
host_resolver_->rules()->AddSimulatedFailure("doesnotexist");
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 6aad7d2..5ada21b 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -21,6 +21,7 @@
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/event_router_forwarder.h"
+#include "chrome/browser/net/cache_stats.h"
#include "chrome/browser/net/chrome_net_log.h"
#include "chrome/browser/net/chrome_network_delegate.h"
#include "chrome/browser/net/chrome_url_request_context.h"
@@ -402,7 +403,8 @@ void IOThread::Init() {
NULL,
NULL,
NULL,
- &system_enable_referrers_);
+ &system_enable_referrers_,
+ NULL);
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableExtensionsHttpThrottling)) {
network_delegate->NeverThrottleRequests();
@@ -426,6 +428,7 @@ void IOThread::Init() {
new net::ServerBoundCertService(
new net::DefaultServerBoundCertStore(NULL),
base::WorkerPool::GetTaskRunner(true)));
+ globals_->cache_stats.reset(new chrome_browser_net::CacheStats());
net::HttpNetworkSession::Params session_params;
session_params.host_resolver = globals_->host_resolver.get();
session_params.cert_verifier = globals_->cert_verifier.get();
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index e4e4faf..aa9cc0c 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -24,6 +24,7 @@ class PrefService;
class SystemURLRequestContextGetter;
namespace chrome_browser_net {
+class CacheStats;
class HttpPipeliningCompatibilityClient;
}
@@ -111,6 +112,7 @@ class IOThread : public content::BrowserThreadDelegate {
extension_event_router_forwarder;
scoped_ptr<chrome_browser_net::HttpPipeliningCompatibilityClient>
http_pipelining_compatibility_client;
+ scoped_ptr<chrome_browser_net::CacheStats> cache_stats;
};
// |net_log| must either outlive the IOThread or be NULL.
diff --git a/chrome/browser/net/cache_stats.cc b/chrome/browser/net/cache_stats.cc
new file mode 100644
index 0000000..68cb96f
--- /dev/null
+++ b/chrome/browser/net/cache_stats.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2012 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 "chrome/browser/net/cache_stats.h"
+
+#include "base/metrics/histogram.h"
+#include "base/stl_util.h"
+#include "base/string_number_conversions.h"
+#include "base/timer.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/io_thread.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/tab_contents/tab_contents.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
+#include "net/url_request/url_request.h"
+
+using content::BrowserThread;
+using content::RenderViewHost;
+using content::ResourceRequestInfo;
+
+#if defined(COMPILER_GCC)
+
+namespace BASE_HASH_NAMESPACE {
+template <>
+struct hash<const net::URLRequest*> {
+ std::size_t operator()(const net::URLRequest* value) const {
+ return reinterpret_cast<std::size_t>(value);
+ }
+};
+}
+
+#endif
+
+namespace {
+
+bool GetRenderView(const net::URLRequest& request,
+ int* process_id, int* route_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request);
+ if (!info)
+ return false;
+ return info->GetAssociatedRenderView(process_id, route_id);
+}
+
+void CallCacheStatsTabEventOnIOThread(
+ std::pair<int, int> render_view_id,
+ chrome_browser_net::CacheStats::TabEvent event,
+ IOThread* io_thread) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (io_thread)
+ io_thread->globals()->cache_stats->OnTabEvent(render_view_id, event);
+}
+
+// Times after a load has started at which stats are collected.
+const int kStatsCollectionTimesMs[] = {
+ 500,
+ 1000,
+ 2000,
+ 3000,
+ 4000,
+ 5000,
+ 7500,
+ 10000,
+ 15000,
+ 20000
+};
+
+static int kTabLoadStatsAutoCleanupTimeoutSeconds = 30;
+
+} // namespace
+
+namespace chrome_browser_net {
+
+// Helper struct keeping stats about the page load progress & cache usage
+// stats during the pageload so far for a given RenderView, identified
+// by a pair of process id and route id.
+struct CacheStats::TabLoadStats {
+ TabLoadStats(std::pair<int, int> render_view_id, CacheStats* owner)
+ : render_view_id(render_view_id),
+ num_active(0),
+ spinner_started(false),
+ next_timer_index(0),
+ timer(false, false) {
+ // Initialize the timer to do an automatic cleanup. If a pageload is
+ // started for the TabLoadStats within that timeframe, CacheStats
+ // will start using the timer, thereby cancelling the cleanup.
+ // Once CacheStats starts the timer, the object is guaranteed to be
+ // destroyed eventually, so there is no more need for automatic cleanup at
+ // that point.
+ timer.Start(FROM_HERE,
+ base::TimeDelta::FromSeconds(
+ kTabLoadStatsAutoCleanupTimeoutSeconds),
+ base::Bind(&CacheStats::RemoveTabLoadStats,
+ base::Unretained(owner),
+ render_view_id));
+ }
+
+ std::pair<int, int> render_view_id;
+ int num_active;
+ bool spinner_started;
+ base::TimeTicks load_start_time;
+ base::TimeTicks cache_start_time;
+ base::TimeDelta cache_total_time;
+ int next_timer_index;
+ base::Timer timer;
+ // URLRequest's for which there are outstanding cache transactions.
+ base::hash_set<const net::URLRequest*> active_requests;
+};
+
+CacheStatsTabHelper::CacheStatsTabHelper(TabContents* tab)
+ : content::WebContentsObserver(tab->web_contents()),
+ cache_stats_(NULL) {
+ is_otr_profile_ = tab->profile()->IsOffTheRecord();
+}
+
+CacheStatsTabHelper::~CacheStatsTabHelper() {
+}
+
+void CacheStatsTabHelper::DidStartProvisionalLoadForFrame(
+ int64 frame_id,
+ bool is_main_frame,
+ const GURL& validated_url,
+ bool is_error_page,
+ content::RenderViewHost* render_view_host) {
+ if (!is_main_frame)
+ return;
+ if (!validated_url.SchemeIs("http"))
+ return;
+ NotifyCacheStats(CacheStats::SPINNER_START, render_view_host);
+}
+
+void CacheStatsTabHelper::DidStopLoading(RenderViewHost* render_view_host) {
+ NotifyCacheStats(CacheStats::SPINNER_STOP, render_view_host);
+}
+
+void CacheStatsTabHelper::NotifyCacheStats(
+ CacheStats::TabEvent event,
+ RenderViewHost* render_view_host) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (is_otr_profile_)
+ return;
+ int process_id = render_view_host->GetProcess()->GetID();
+ int route_id = render_view_host->GetRoutingID();
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&CallCacheStatsTabEventOnIOThread,
+ std::pair<int, int>(process_id, route_id),
+ event,
+ base::Unretained(g_browser_process->io_thread())));
+}
+
+CacheStats::CacheStats() {
+ for (int i = 0;
+ i < static_cast<int>(arraysize(kStatsCollectionTimesMs));
+ i++) {
+ final_histograms_.push_back(
+ base::LinearHistogram::FactoryGet(
+ "CacheStats.FractionCacheUseFinalPLT_" +
+ base::IntToString(kStatsCollectionTimesMs[i]),
+ 0, 101, 102, base::Histogram::kUmaTargetedHistogramFlag));
+ intermediate_histograms_.push_back(
+ base::LinearHistogram::FactoryGet(
+ "DiskCache.FractionCacheUseIntermediatePLT_" +
+ base::IntToString(kStatsCollectionTimesMs[i]),
+ 0, 101, 102, base::Histogram::kNoFlags));
+ }
+ DCHECK_EQ(final_histograms_.size(), arraysize(kStatsCollectionTimesMs));
+ DCHECK_EQ(intermediate_histograms_.size(),
+ arraysize(kStatsCollectionTimesMs));
+}
+
+CacheStats::~CacheStats() {
+ STLDeleteValues(&tab_load_stats_);
+}
+
+CacheStats::TabLoadStats* CacheStats::GetTabLoadStats(
+ std::pair<int, int> render_view_id) {
+ TabLoadStatsMap::const_iterator it = tab_load_stats_.find(render_view_id);
+ if (it != tab_load_stats_.end())
+ return it->second;
+ TabLoadStats* new_tab_load_stats = new TabLoadStats(render_view_id, this);
+ tab_load_stats_[render_view_id] = new_tab_load_stats;
+ return new_tab_load_stats;
+}
+
+void CacheStats::RemoveTabLoadStats(std::pair<int, int> render_view_id) {
+ TabLoadStatsMap::iterator it = tab_load_stats_.find(render_view_id);
+ if (it != tab_load_stats_.end()) {
+ delete it->second;
+ tab_load_stats_.erase(it);
+ }
+}
+
+void CacheStats::OnCacheWaitStateChange(
+ const net::URLRequest& request,
+ net::NetworkDelegate::CacheWaitState state) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (main_request_contexts_.count(request.context()) < 1)
+ return;
+ int process_id, route_id;
+ if (!GetRenderView(request, &process_id, &route_id))
+ return;
+ TabLoadStats* stats =
+ GetTabLoadStats(std::pair<int, int>(process_id, route_id));
+ bool newly_started = false;
+ bool newly_finished = false;
+ switch (state) {
+ case net::NetworkDelegate::CACHE_WAIT_STATE_START:
+ DCHECK(stats->active_requests.count(&request) == 0);
+ newly_started = true;
+ stats->active_requests.insert(&request);
+ break;
+ case net::NetworkDelegate::CACHE_WAIT_STATE_FINISH:
+ if (stats->active_requests.count(&request) > 0) {
+ stats->active_requests.erase(&request);
+ newly_finished = true;
+ }
+ break;
+ case net::NetworkDelegate::CACHE_WAIT_STATE_RESET:
+ if (stats->active_requests.count(&request) > 0) {
+ stats->active_requests.erase(&request);
+ newly_finished = true;
+ }
+ break;
+ }
+ DCHECK_GE(stats->num_active, 0);
+ if (newly_started) {
+ DCHECK(!newly_finished);
+ if (stats->num_active == 0) {
+ stats->cache_start_time = base::TimeTicks::Now();
+ }
+ stats->num_active++;
+ }
+ if (newly_finished) {
+ DCHECK(!newly_started);
+ if (stats->num_active == 1) {
+ stats->cache_total_time +=
+ base::TimeTicks::Now() - stats->cache_start_time;
+ }
+ stats->num_active--;
+ }
+ DCHECK_GE(stats->num_active, 0);
+}
+
+void CacheStats::OnTabEvent(std::pair<int, int> render_view_id,
+ TabEvent event) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ TabLoadStats* stats = GetTabLoadStats(render_view_id);
+ if (event == SPINNER_START) {
+ stats->spinner_started = true;
+ stats->cache_total_time = base::TimeDelta();
+ stats->cache_start_time = base::TimeTicks::Now();
+ stats->load_start_time = base::TimeTicks::Now();
+ stats->next_timer_index = 0;
+ ScheduleTimer(stats);
+ } else {
+ DCHECK_EQ(event, SPINNER_STOP);
+ if (stats->spinner_started) {
+ stats->spinner_started = false;
+ base::TimeDelta load_time =
+ base::TimeTicks::Now() - stats->load_start_time;
+ if (stats->num_active > 1)
+ stats->cache_total_time +=
+ base::TimeTicks::Now() - stats->cache_start_time;
+ RecordCacheFractionHistogram(load_time, stats->cache_total_time, true,
+ stats->next_timer_index);
+ }
+ RemoveTabLoadStats(render_view_id);
+ }
+}
+
+void CacheStats::ScheduleTimer(TabLoadStats* stats) {
+ int timer_index = stats->next_timer_index;
+ DCHECK(timer_index >= 0 &&
+ timer_index < static_cast<int>(arraysize(kStatsCollectionTimesMs)));
+ base::TimeDelta delta =
+ base::TimeDelta::FromMilliseconds(kStatsCollectionTimesMs[timer_index]);
+ delta -= base::TimeTicks::Now() - stats->load_start_time;
+ stats->timer.Start(FROM_HERE,
+ delta,
+ base::Bind(&CacheStats::TimerCallback,
+ base::Unretained(this),
+ base::Unretained(stats)));
+}
+
+void CacheStats::TimerCallback(TabLoadStats* stats) {
+ DCHECK(stats->spinner_started);
+ base::TimeDelta load_time = base::TimeTicks::Now() - stats->load_start_time;
+ base::TimeDelta cache_time = stats->cache_total_time;
+ if (stats->num_active > 1)
+ cache_time += base::TimeTicks::Now() - stats->cache_start_time;
+ RecordCacheFractionHistogram(load_time, cache_time, false,
+ stats->next_timer_index);
+ stats->next_timer_index++;
+ if (stats->next_timer_index <
+ static_cast<int>(arraysize(kStatsCollectionTimesMs))) {
+ ScheduleTimer(stats);
+ } else {
+ RemoveTabLoadStats(stats->render_view_id);
+ }
+}
+
+void CacheStats::RecordCacheFractionHistogram(base::TimeDelta elapsed,
+ base::TimeDelta cache_time,
+ bool is_load_done,
+ int timer_index) {
+ DCHECK(timer_index >= 0 &&
+ timer_index < static_cast<int>(arraysize(kStatsCollectionTimesMs)));
+
+ if (elapsed.InMilliseconds() <= 0)
+ return;
+
+ int64 cache_fraction_percentage =
+ 100 * cache_time.InMilliseconds() / elapsed.InMilliseconds();
+
+ DCHECK(cache_fraction_percentage >= 0 && cache_fraction_percentage <= 100);
+
+ if (is_load_done) {
+ final_histograms_[timer_index]->Add(cache_fraction_percentage);
+ } else {
+ intermediate_histograms_[timer_index]->Add(cache_fraction_percentage);
+ }
+}
+
+void CacheStats::RegisterURLRequestContext(
+ const net::URLRequestContext* context,
+ ChromeURLRequestContext::ContextType type) {
+ if (type == ChromeURLRequestContext::CONTEXT_TYPE_MAIN)
+ main_request_contexts_.insert(context);
+}
+
+void CacheStats::UnregisterURLRequestContext(
+ const net::URLRequestContext* context) {
+ main_request_contexts_.erase(context);
+}
+
+} // namespace chrome_browser_net
diff --git a/chrome/browser/net/cache_stats.h b/chrome/browser/net/cache_stats.h
new file mode 100644
index 0000000..a3db95b
--- /dev/null
+++ b/chrome/browser/net/cache_stats.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2012 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 CHROME_BROWSER_NET_CACHE_STATS_H_
+#define CHROME_BROWSER_NET_CACHE_STATS_H_
+
+#include <map>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/hash_tables.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/time.h"
+#include "chrome/browser/net/chrome_url_request_context.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "net/base/network_delegate.h"
+
+class TabContents;
+
+namespace base {
+class Histogram;
+}
+
+namespace net {
+class URLRequest;
+class URLRequestContext;
+}
+
+#if defined(COMPILER_GCC)
+
+namespace BASE_HASH_NAMESPACE {
+template <>
+struct hash<const net::URLRequestContext*> {
+ std::size_t operator()(const net::URLRequestContext* value) const {
+ return reinterpret_cast<std::size_t>(value);
+ }
+};
+}
+
+#endif
+
+namespace chrome_browser_net {
+
+// This class collects UMA stats about cache performance.
+class CacheStats {
+ public:
+ enum TabEvent {
+ SPINNER_START,
+ SPINNER_STOP
+ };
+ CacheStats();
+ ~CacheStats();
+
+ void OnCacheWaitStateChange(const net::URLRequest& request,
+ net::NetworkDelegate::CacheWaitState state);
+ void OnTabEvent(std::pair<int, int> render_view_id, TabEvent event);
+ void RegisterURLRequestContext(const net::URLRequestContext* context,
+ ChromeURLRequestContext::ContextType type);
+ void UnregisterURLRequestContext(const net::URLRequestContext* context);
+
+ private:
+ struct TabLoadStats;
+ // A map mapping a renderer's process id and route id to a TabLoadStats,
+ // representing that renderer's load statistics.
+ typedef std::map<std::pair<int, int>, TabLoadStats*> TabLoadStatsMap;
+
+ // Gets TabLoadStats for a given RenderView.
+ TabLoadStats* GetTabLoadStats(std::pair<int, int> render_view_id);
+ // Deletes TabLoadStats no longer needed for a render view.
+ void RemoveTabLoadStats(std::pair<int, int> render_view_id);
+ // Sets a timer for a given tab to collect stats. |timer_index| indicates
+ // how many times stats have been collected since the navigation has started
+ // for this tab.
+ void ScheduleTimer(TabLoadStats* stats);
+ // The callback when a timer fires to collect stats again.
+ void TimerCallback(TabLoadStats* stats);
+ // Helper function to put the current set of cache statistics into an UMA
+ // histogram.
+ void RecordCacheFractionHistogram(base::TimeDelta elapsed,
+ base::TimeDelta cache_time,
+ bool is_load_done,
+ int timer_index);
+
+ TabLoadStatsMap tab_load_stats_;
+ std::vector<base::Histogram*> final_histograms_;
+ std::vector<base::Histogram*> intermediate_histograms_;
+ base::hash_set<const net::URLRequestContext*> main_request_contexts_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheStats);
+};
+
+// A WebContentsObserver watching all tabs, notifying CacheStats
+// whenever the spinner starts or stops for a given tab, and when a renderer
+// is no longer used.
+class CacheStatsTabHelper : public content::WebContentsObserver {
+ public:
+ explicit CacheStatsTabHelper(TabContents* tab);
+ virtual ~CacheStatsTabHelper();
+
+ // content::WebContentsObserver implementation
+ virtual void DidStartProvisionalLoadForFrame(
+ int64 frame_id,
+ bool is_main_frame,
+ const GURL& validated_url,
+ bool is_error_page,
+ content::RenderViewHost* render_view_host) OVERRIDE;
+ virtual void DidStopLoading(
+ content::RenderViewHost* render_view_host) OVERRIDE;
+
+ private:
+ // Calls into CacheStats to notify that a reportable event has occurred
+ // for the tab being observed.
+ void NotifyCacheStats(CacheStats::TabEvent event,
+ content::RenderViewHost* render_view_host);
+
+ CacheStats* cache_stats_;
+ bool is_otr_profile_;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheStatsTabHelper);
+};
+
+} // namespace chrome_browser_net
+
+#endif // CHROME_BROWSER_NET_CACHE_STATS_H_
diff --git a/chrome/browser/net/chrome_fraudulent_certificate_reporter_unittest.cc b/chrome/browser/net/chrome_fraudulent_certificate_reporter_unittest.cc
index 7dc092a..3246553 100644
--- a/chrome/browser/net/chrome_fraudulent_certificate_reporter_unittest.cc
+++ b/chrome/browser/net/chrome_fraudulent_certificate_reporter_unittest.cc
@@ -121,7 +121,7 @@ class NotSendingTestReporter : public TestReporter {
// This class doesn't do anything now, but in near future versions it will.
class MockURLRequest : public net::URLRequest {
public:
- MockURLRequest(net::URLRequestContext* context)
+ explicit MockURLRequest(net::URLRequestContext* context)
: net::URLRequest(GURL(""), NULL, context) {
}
@@ -152,21 +152,24 @@ class MockReporter : public ChromeFraudulentCertificateReporter {
};
static void DoReportIsSent() {
- ChromeURLRequestContext context;
+ ChromeURLRequestContext context(ChromeURLRequestContext::CONTEXT_TYPE_MAIN,
+ NULL);
SendingTestReporter reporter(&context);
SSLInfo info = GetGoodSSLInfo();
reporter.SendReport("mail.google.com", info, true);
}
static void DoReportIsNotSent() {
- ChromeURLRequestContext context;
+ ChromeURLRequestContext context(ChromeURLRequestContext::CONTEXT_TYPE_MAIN,
+ NULL);
NotSendingTestReporter reporter(&context);
SSLInfo info = GetBadSSLInfo();
reporter.SendReport("www.example.com", info, true);
}
static void DoMockReportIsSent() {
- ChromeURLRequestContext context;
+ ChromeURLRequestContext context(ChromeURLRequestContext::CONTEXT_TYPE_MAIN,
+ NULL);
MockReporter reporter(&context);
SSLInfo info = GetGoodSSLInfo();
reporter.SendReport("mail.google.com", info, true);
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index 207bb08..0295195 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/extensions/event_router_forwarder.h"
#include "chrome/browser/extensions/extension_info_map.h"
#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/net/cache_stats.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/task_manager/task_manager.h"
@@ -126,14 +127,16 @@ ChromeNetworkDelegate::ChromeNetworkDelegate(
const policy::URLBlacklistManager* url_blacklist_manager,
void* profile,
CookieSettings* cookie_settings,
- BooleanPrefMember* enable_referrers)
+ BooleanPrefMember* enable_referrers,
+ chrome_browser_net::CacheStats* cache_stats)
: event_router_(event_router),
profile_(profile),
cookie_settings_(cookie_settings),
extension_info_map_(extension_info_map),
enable_referrers_(enable_referrers),
never_throttle_requests_(false),
- url_blacklist_manager_(url_blacklist_manager) {
+ url_blacklist_manager_(url_blacklist_manager),
+ cache_stats_(cache_stats) {
DCHECK(event_router);
DCHECK(enable_referrers);
DCHECK(!profile || cookie_settings);
@@ -389,3 +392,10 @@ int ChromeNetworkDelegate::OnBeforeSocketStreamConnect(
#endif
return net::OK;
}
+
+void ChromeNetworkDelegate::OnCacheWaitStateChange(
+ const net::URLRequest& request,
+ CacheWaitState state) {
+ if (cache_stats_)
+ cache_stats_->OnCacheWaitStateChange(request, state);
+}
diff --git a/chrome/browser/net/chrome_network_delegate.h b/chrome/browser/net/chrome_network_delegate.h
index 8cf28d6..a5fb87d 100644
--- a/chrome/browser/net/chrome_network_delegate.h
+++ b/chrome/browser/net/chrome_network_delegate.h
@@ -17,6 +17,10 @@ template<class T> class PrefMember;
typedef PrefMember<bool> BooleanPrefMember;
+namespace chrome_browser_net {
+class CacheStats;
+}
+
namespace extensions {
class EventRouterForwarder;
}
@@ -41,7 +45,8 @@ class ChromeNetworkDelegate : public net::NetworkDelegate {
const policy::URLBlacklistManager* url_blacklist_manager,
void* profile,
CookieSettings* cookie_settings,
- BooleanPrefMember* enable_referrers);
+ BooleanPrefMember* enable_referrers,
+ chrome_browser_net::CacheStats* cache_stats);
virtual ~ChromeNetworkDelegate();
// Causes |OnCanThrottleRequest| to never return true.
@@ -98,6 +103,8 @@ class ChromeNetworkDelegate : public net::NetworkDelegate {
virtual int OnBeforeSocketStreamConnect(
net::SocketStream* stream,
const net::CompletionCallback& callback) OVERRIDE;
+ virtual void OnCacheWaitStateChange(const net::URLRequest& request,
+ CacheWaitState state) OVERRIDE;
scoped_refptr<extensions::EventRouterForwarder> event_router_;
void* profile_;
@@ -117,6 +124,9 @@ class ChromeNetworkDelegate : public net::NetworkDelegate {
// When true, allow access to all file:// URLs.
static bool g_allow_file_access_;
+ // Pointer to IOThread global, should outlive ChromeNetworkDelegate.
+ chrome_browser_net::CacheStats* cache_stats_;
+
DISALLOW_COPY_AND_ASSIGN(ChromeNetworkDelegate);
};
diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc
index 0b3d77d..ee067c8 100644
--- a/chrome/browser/net/chrome_url_request_context.cc
+++ b/chrome/browser/net/chrome_url_request_context.cc
@@ -10,6 +10,7 @@
#include "base/message_loop_proxy.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/io_thread.h"
+#include "chrome/browser/net/cache_stats.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_io_data.h"
@@ -290,14 +291,21 @@ void ChromeURLRequestContextGetter::OnDefaultCharsetChange(
// ChromeURLRequestContext
// ----------------------------------------------------------------------------
-ChromeURLRequestContext::ChromeURLRequestContext()
+ChromeURLRequestContext::ChromeURLRequestContext(
+ ContextType type,
+ chrome_browser_net::CacheStats* cache_stats)
: ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
- is_incognito_(false) {
+ is_incognito_(false),
+ cache_stats_(cache_stats) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (cache_stats_)
+ cache_stats_->RegisterURLRequestContext(this, type);
}
ChromeURLRequestContext::~ChromeURLRequestContext() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (cache_stats_)
+ cache_stats_->UnregisterURLRequestContext(this);
}
void ChromeURLRequestContext::CopyFrom(ChromeURLRequestContext* other) {
diff --git a/chrome/browser/net/chrome_url_request_context.h b/chrome/browser/net/chrome_url_request_context.h
index 61345e1..83f8037 100644
--- a/chrome/browser/net/chrome_url_request_context.h
+++ b/chrome/browser/net/chrome_url_request_context.h
@@ -20,6 +20,10 @@ class IOThread;
class Profile;
class ProfileIOData;
+namespace chrome_browser_net {
+class CacheStats;
+}
+
// Subclass of net::URLRequestContext which can be used to store extra
// information for requests.
//
@@ -27,7 +31,14 @@ class ProfileIOData;
// including the constructor and destructor.
class ChromeURLRequestContext : public net::URLRequestContext {
public:
- ChromeURLRequestContext();
+ enum ContextType {
+ CONTEXT_TYPE_MAIN,
+ CONTEXT_TYPE_MEDIA,
+ CONTEXT_TYPE_EXTENSIONS,
+ CONTEXT_TYPE_APP
+ };
+ ChromeURLRequestContext(ContextType type,
+ chrome_browser_net::CacheStats* cache_stats);
virtual ~ChromeURLRequestContext();
base::WeakPtr<ChromeURLRequestContext> GetWeakPtr() {
@@ -70,6 +81,7 @@ class ChromeURLRequestContext : public net::URLRequestContext {
ChromeURLDataManagerBackend* chrome_url_data_manager_backend_;
bool is_incognito_;
+ chrome_browser_net::CacheStats* cache_stats_;
// ---------------------------------------------------------------------------
// Important: When adding any new members above, consider whether they need to
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.cc b/chrome/browser/profiles/off_the_record_profile_io_data.cc
index 830d6df..471bac3 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.cc
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.cc
@@ -272,7 +272,7 @@ ChromeURLRequestContext*
OffTheRecordProfileIOData::InitializeAppRequestContext(
ChromeURLRequestContext* main_context,
const std::string& app_id) const {
- AppRequestContext* context = new AppRequestContext;
+ AppRequestContext* context = new AppRequestContext(cache_stats());
// Copy most state from the main context.
context->CopyFrom(main_context);
@@ -320,3 +320,7 @@ void OffTheRecordProfileIOData::CreateFtpProtocolHandler(
network_delegate(), ftp_factory_.get(), ftp_auth_cache));
}
+chrome_browser_net::CacheStats* OffTheRecordProfileIOData::GetCacheStats(
+ IOThread::Globals* io_thread_globals) const {
+ return NULL;
+}
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.h b/chrome/browser/profiles/off_the_record_profile_io_data.h
index c939932..984e8c6 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.h
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.h
@@ -110,6 +110,9 @@ class OffTheRecordProfileIOData : public ProfileIOData {
void CreateFtpProtocolHandler(net::URLRequestJobFactory* job_factory,
net::FtpAuthCache* ftp_auth_cache) const;
+ virtual chrome_browser_net::CacheStats* GetCacheStats(
+ IOThread::Globals* io_thread_globals) const OVERRIDE;
+
mutable scoped_ptr<net::HttpServerPropertiesImpl> http_server_properties_;
mutable scoped_ptr<net::HttpTransactionFactory> main_http_factory_;
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index 8bf761e..d757e86 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -267,7 +267,8 @@ void ProfileImplIOData::LazyInitializeInternal(
ProfileParams* profile_params) const {
ChromeURLRequestContext* main_context = main_request_context();
ChromeURLRequestContext* extensions_context = extensions_request_context();
- media_request_context_.reset(new ChromeURLRequestContext);
+ media_request_context_.reset(new ChromeURLRequestContext(
+ ChromeURLRequestContext::CONTEXT_TYPE_MEDIA, cache_stats()));
IOThread* const io_thread = profile_params->io_thread;
IOThread::Globals* const io_thread_globals = io_thread->globals();
@@ -477,7 +478,7 @@ ChromeURLRequestContext*
ProfileImplIOData::InitializeAppRequestContext(
ChromeURLRequestContext* main_context,
const std::string& app_id) const {
- AppRequestContext* context = new AppRequestContext;
+ AppRequestContext* context = new AppRequestContext(cache_stats());
// If this is for a guest process, we should not persist cookies and http
// cache.
@@ -564,6 +565,11 @@ ProfileImplIOData::AcquireIsolatedAppRequestContext(
return app_request_context;
}
+chrome_browser_net::CacheStats* ProfileImplIOData::GetCacheStats(
+ IOThread::Globals* io_thread_globals) const {
+ return io_thread_globals->cache_stats.get();
+}
+
void ProfileImplIOData::CreateFtpProtocolHandler(
net::URLRequestJobFactory* job_factory,
net::FtpAuthCache* ftp_auth_cache) const {
diff --git a/chrome/browser/profiles/profile_impl_io_data.h b/chrome/browser/profiles/profile_impl_io_data.h
index 5435063..e7ef8f2 100644
--- a/chrome/browser/profiles/profile_impl_io_data.h
+++ b/chrome/browser/profiles/profile_impl_io_data.h
@@ -139,6 +139,8 @@ class ProfileImplIOData : public ProfileIOData {
AcquireIsolatedAppRequestContext(
ChromeURLRequestContext* main_context,
const std::string& app_id) const OVERRIDE;
+ virtual chrome_browser_net::CacheStats* GetCacheStats(
+ IOThread::Globals* io_thread_globals) const OVERRIDE;
void CreateFtpProtocolHandler(net::URLRequestJobFactory* job_factory,
net::FtpAuthCache* ftp_auth_cache) const;
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 12fec63..4277fd3 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -28,6 +28,7 @@
#include "chrome/browser/extensions/extension_resource_protocols.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/io_thread.h"
+#include "chrome/browser/net/cache_stats.h"
#include "chrome/browser/net/chrome_cookie_notification_details.h"
#include "chrome/browser/net/chrome_fraudulent_certificate_reporter.h"
#include "chrome/browser/net/chrome_net_log.h"
@@ -220,7 +221,11 @@ void ProfileIOData::InitializeOnUIThread(Profile* profile) {
BrowserContext::EnsureResourceContextInitialized(profile);
}
-ProfileIOData::AppRequestContext::AppRequestContext() {}
+ProfileIOData::AppRequestContext::AppRequestContext(
+ chrome_browser_net::CacheStats* cache_stats)
+ : ChromeURLRequestContext(ChromeURLRequestContext::CONTEXT_TYPE_APP,
+ cache_stats) {
+}
void ProfileIOData::AppRequestContext::SetCookieStore(
net::CookieStore* cookie_store) {
@@ -456,10 +461,16 @@ void ProfileIOData::LazyInitialize() const {
IOThread* const io_thread = profile_params_->io_thread;
IOThread::Globals* const io_thread_globals = io_thread->globals();
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ cache_stats_ = GetCacheStats(io_thread_globals);
// Create the common request contexts.
- main_request_context_.reset(new ChromeURLRequestContext);
- extensions_request_context_.reset(new ChromeURLRequestContext);
+ main_request_context_.reset(
+ new ChromeURLRequestContext(ChromeURLRequestContext::CONTEXT_TYPE_MAIN,
+ cache_stats_));
+ extensions_request_context_.reset(
+ new ChromeURLRequestContext(
+ ChromeURLRequestContext::CONTEXT_TYPE_EXTENSIONS,
+ cache_stats_));
chrome_url_data_manager_backend_.reset(new ChromeURLDataManagerBackend);
@@ -469,7 +480,8 @@ void ProfileIOData::LazyInitialize() const {
url_blacklist_manager_.get(),
profile_params_->profile,
profile_params_->cookie_settings,
- &enable_referrers_));
+ &enable_referrers_,
+ cache_stats_));
fraudulent_certificate_reporter_.reset(
new chrome_browser_net::ChromeFraudulentCertificateReporter(
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index 6a900a3..ff5c463 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -14,6 +14,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
+#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/prefs/pref_member.h"
#include "content/public/browser/resource_context.h"
@@ -24,12 +25,12 @@ class CookieSettings;
class DesktopNotificationService;
class ExtensionInfoMap;
class HostContentSettingsMap;
-class IOThread;
class Profile;
class ProtocolHandlerRegistry;
class TransportSecurityPersister;
namespace chrome_browser_net {
+class CacheStats;
class HttpServerPropertiesManager;
class ResourcePrefetchPredictorObserver;
}
@@ -136,7 +137,7 @@ class ProfileIOData {
protected:
class AppRequestContext : public ChromeURLRequestContext {
public:
- AppRequestContext();
+ explicit AppRequestContext(chrome_browser_net::CacheStats* cache_stats);
void SetCookieStore(net::CookieStore* cookie_store);
void SetHttpTransactionFactory(net::HttpTransactionFactory* http_factory);
@@ -239,6 +240,10 @@ class ProfileIOData {
return main_request_context_.get();
}
+ chrome_browser_net::CacheStats* cache_stats() const {
+ return cache_stats_;
+ }
+
// Destroys the ResourceContext first, to cancel any URLRequests that are
// using it still, before we destroy the member variables that those
// URLRequests may be accessing.
@@ -291,6 +296,10 @@ class ProfileIOData {
ChromeURLRequestContext* main_context,
const std::string& app_id) const = 0;
+ // Returns the CacheStats object to be used for this profile.
+ virtual chrome_browser_net::CacheStats* GetCacheStats(
+ IOThread::Globals* io_thread_globals) const = 0;
+
// The order *DOES* matter for the majority of these member variables, so
// don't move them around unless you know what you're doing!
// General rules:
@@ -364,6 +373,8 @@ class ProfileIOData {
mutable scoped_ptr<chrome_browser_net::ResourcePrefetchPredictorObserver>
resource_prefetch_predictor_observer_;
+ mutable chrome_browser_net::CacheStats* cache_stats_;
+
// TODO(jhawkins): Remove once crbug.com/102004 is fixed.
bool initialized_on_UI_thread_;
diff --git a/chrome/browser/ui/tab_contents/tab_contents.cc b/chrome/browser/ui/tab_contents/tab_contents.cc
index 407ac05..aa24534 100644
--- a/chrome/browser/ui/tab_contents/tab_contents.cc
+++ b/chrome/browser/ui/tab_contents/tab_contents.cc
@@ -18,6 +18,7 @@
#include "chrome/browser/favicon/favicon_tab_helper.h"
#include "chrome/browser/history/history_tab_helper.h"
#include "chrome/browser/infobars/infobar_tab_helper.h"
+#include "chrome/browser/net/cache_stats.h"
#include "chrome/browser/omnibox_search_hint.h"
#include "chrome/browser/password_manager/password_manager.h"
#include "chrome/browser/password_manager/password_manager_delegate_impl.h"
@@ -102,6 +103,8 @@ TabContents::TabContents(WebContents* contents)
#endif
blocked_content_tab_helper_.reset(new BlockedContentTabHelper(this));
bookmark_tab_helper_.reset(new BookmarkTabHelper(this));
+ cache_stats_tab_helper_.reset(
+ new chrome_browser_net::CacheStatsTabHelper(this));
#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
captive_portal_tab_helper_.reset(
new captive_portal::CaptivePortalTabHelper(profile(), web_contents()));
diff --git a/chrome/browser/ui/tab_contents/tab_contents.h b/chrome/browser/ui/tab_contents/tab_contents.h
index cef0962..e53ad96 100644
--- a/chrome/browser/ui/tab_contents/tab_contents.h
+++ b/chrome/browser/ui/tab_contents/tab_contents.h
@@ -65,6 +65,10 @@ class SearchTabHelper;
}
}
+namespace chrome_browser_net {
+class CacheStatsTabHelper;
+}
+
namespace extensions {
class TabHelper;
class WebNavigationTabObserver;
@@ -267,6 +271,7 @@ class TabContents : public content::WebContentsObserver {
scoped_ptr<AutomationTabHelper> automation_tab_helper_;
scoped_ptr<BlockedContentTabHelper> blocked_content_tab_helper_;
scoped_ptr<BookmarkTabHelper> bookmark_tab_helper_;
+ scoped_ptr<chrome_browser_net::CacheStatsTabHelper> cache_stats_tab_helper_;
#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
scoped_ptr<captive_portal::CaptivePortalTabHelper> captive_portal_tab_helper_;
#endif
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index da49fac..4fe3047 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1450,6 +1450,8 @@
'browser/metrics/variations_service.cc',
'browser/metrics/variations_service.h',
'browser/native_window_notification_source.h',
+ 'browser/net/cache_stats.cc',
+ 'browser/net/cache_stats.h',
'browser/net/chrome_cookie_notification_details.h',
'browser/net/chrome_fraudulent_certificate_reporter.cc',
'browser/net/chrome_fraudulent_certificate_reporter.h',
diff --git a/content/shell/shell_network_delegate.cc b/content/shell/shell_network_delegate.cc
index 1bf35fb..57886eb 100644
--- a/content/shell/shell_network_delegate.cc
+++ b/content/shell/shell_network_delegate.cc
@@ -97,4 +97,9 @@ int ShellNetworkDelegate::OnBeforeSocketStreamConnect(
return net::OK;
}
+void ShellNetworkDelegate::OnCacheWaitStateChange(
+ const net::URLRequest& request,
+ CacheWaitState waiting) {
+}
+
} // namespace content
diff --git a/content/shell/shell_network_delegate.h b/content/shell/shell_network_delegate.h
index da15ff8..a3e01bc 100644
--- a/content/shell/shell_network_delegate.h
+++ b/content/shell/shell_network_delegate.h
@@ -58,6 +58,8 @@ class ShellNetworkDelegate : public net::NetworkDelegate {
virtual int OnBeforeSocketStreamConnect(
net::SocketStream* stream,
const net::CompletionCallback& callback) OVERRIDE;
+ virtual void OnCacheWaitStateChange(const net::URLRequest& request,
+ CacheWaitState state) OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(ShellNetworkDelegate);
};
diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc
index 96e9a23..f52900c 100644
--- a/net/base/network_delegate.cc
+++ b/net/base/network_delegate.cc
@@ -127,4 +127,10 @@ int NetworkDelegate::NotifyBeforeSocketStreamConnect(
return OnBeforeSocketStreamConnect(socket, callback);
}
+void NetworkDelegate::NotifyCacheWaitStateChange(const URLRequest& request,
+ CacheWaitState state) {
+ DCHECK(CalledOnValidThread());
+ OnCacheWaitStateChange(request, state);
+}
+
} // namespace net
diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h
index 5ecd0f8..f3bc758 100644
--- a/net/base/network_delegate.h
+++ b/net/base/network_delegate.h
@@ -48,6 +48,12 @@ class NetworkDelegate : public base::NonThreadSafe {
};
typedef base::Callback<void(AuthRequiredResponse)> AuthCallback;
+ enum CacheWaitState {
+ CACHE_WAIT_STATE_START,
+ CACHE_WAIT_STATE_FINISH,
+ CACHE_WAIT_STATE_RESET
+ };
+
virtual ~NetworkDelegate() {}
// Notification interface called by the network stack. Note that these
@@ -90,6 +96,9 @@ class NetworkDelegate : public base::NonThreadSafe {
int NotifyBeforeSocketStreamConnect(SocketStream* socket,
const CompletionCallback& callback);
+ void NotifyCacheWaitStateChange(const URLRequest& request,
+ CacheWaitState state);
+
private:
// This is the interface for subclasses of NetworkDelegate to implement. These
// member functions will be called by the respective public notification
@@ -214,6 +223,17 @@ class NetworkDelegate : public base::NonThreadSafe {
// Called before a SocketStream tries to connect.
virtual int OnBeforeSocketStreamConnect(
SocketStream* socket, const CompletionCallback& callback) = 0;
+
+ // Called when the completion of a URLRequest is blocking on a cache
+ // transaction (CACHE_WAIT_STATE_START), or when a URLRequest is no longer
+ // blocked on a cache transaction (CACHE_WAIT_STATE_FINISH), or when a
+ // URLRequest is reset (CACHE_WAIT_STATE_RESET), indicating
+ // cancellation of any pending cache waits for this request. Notice that
+ // START can be called several times for the same request. It is the
+ // responsibility of the delegate to keep track of the number of outstanding
+ // cache transactions.
+ virtual void OnCacheWaitStateChange(const URLRequest& request,
+ CacheWaitState state) = 0;
};
} // namespace net
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index defc365..8579471 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -409,7 +409,7 @@ void HttpCache::WriteMetadata(const GURL& url,
CreateBackend(NULL, net::CompletionCallback());
}
- HttpCache::Transaction* trans = new HttpCache::Transaction(this);
+ HttpCache::Transaction* trans = new HttpCache::Transaction(this, NULL);
MetadataWriter* writer = new MetadataWriter(trans);
// The writer will self destruct when done.
@@ -444,14 +444,15 @@ void HttpCache::OnExternalCacheHit(const GURL& url,
disk_cache_->OnExternalCacheHit(key);
}
-int HttpCache::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
+int HttpCache::CreateTransaction(scoped_ptr<HttpTransaction>* trans,
+ HttpTransactionDelegate* delegate) {
// Do lazy initialization of disk cache if needed.
if (!disk_cache_.get()) {
// We don't care about the result.
CreateBackend(NULL, net::CompletionCallback());
}
- trans->reset(new HttpCache::Transaction(this));
+ trans->reset(new HttpCache::Transaction(this, delegate));
return OK;
}
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index f5c391e..4ff00b5 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -191,7 +191,8 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory,
void OnExternalCacheHit(const GURL& url, const std::string& http_method);
// HttpTransactionFactory implementation:
- virtual int CreateTransaction(scoped_ptr<HttpTransaction>* trans) OVERRIDE;
+ virtual int CreateTransaction(scoped_ptr<HttpTransaction>* trans,
+ HttpTransactionDelegate* delegate) OVERRIDE;
virtual HttpCache* GetCache() OVERRIDE;
virtual HttpNetworkSession* GetSession() OVERRIDE;
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 652a3b2..c6a7c9f 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -31,6 +31,7 @@
#include "net/http/http_network_session.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
+#include "net/http/http_transaction_delegate.h"
#include "net/http/http_transaction.h"
#include "net/http/http_util.h"
#include "net/http/partial_data.h"
@@ -101,7 +102,9 @@ static bool HeaderMatches(const HttpRequestHeaders& headers,
//-----------------------------------------------------------------------------
-HttpCache::Transaction::Transaction(HttpCache* cache)
+HttpCache::Transaction::Transaction(
+ HttpCache* cache,
+ HttpTransactionDelegate* transaction_delegate)
: next_state_(STATE_NONE),
request_(NULL),
cache_(cache->AsWeakPtr()),
@@ -126,7 +129,8 @@ HttpCache::Transaction::Transaction(HttpCache* cache)
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(io_callback_(
base::Bind(&Transaction::OnIOComplete,
- weak_factory_.GetWeakPtr()))) {
+ weak_factory_.GetWeakPtr()))),
+ transaction_delegate_(transaction_delegate) {
COMPILE_ASSERT(HttpCache::Transaction::kNumValidationHeaders ==
arraysize(kValidationHeaders),
Invalid_number_of_validation_headers);
@@ -654,11 +658,13 @@ int HttpCache::Transaction::DoGetBackend() {
cache_pending_ = true;
next_state_ = STATE_GET_BACKEND_COMPLETE;
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_GET_BACKEND);
+ ReportCacheActionStart();
return cache_->GetBackendForTransaction(this);
}
int HttpCache::Transaction::DoGetBackendComplete(int result) {
DCHECK(result == OK || result == ERR_FAILED);
+ ReportCacheActionFinish();
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_GET_BACKEND,
result);
cache_pending_ = false;
@@ -719,7 +725,7 @@ int HttpCache::Transaction::DoSendRequest() {
DCHECK(!network_trans_.get());
// Create a network transaction.
- int rv = cache_->network_layer_->CreateTransaction(&network_trans_);
+ int rv = cache_->network_layer_->CreateTransaction(&network_trans_, NULL);
if (rv != OK)
return rv;
@@ -847,6 +853,7 @@ int HttpCache::Transaction::DoOpenEntry() {
next_state_ = STATE_OPEN_ENTRY_COMPLETE;
cache_pending_ = true;
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY);
+ ReportCacheActionStart();
return cache_->OpenEntry(cache_key_, &new_entry_, this);
}
@@ -854,6 +861,7 @@ int HttpCache::Transaction::DoOpenEntryComplete(int result) {
// It is important that we go to STATE_ADD_TO_ENTRY whenever the result is
// OK, otherwise the cache will end up with an active entry without any
// transaction attached.
+ ReportCacheActionFinish();
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_OPEN_ENTRY, result);
cache_pending_ = false;
if (result == OK) {
@@ -897,6 +905,7 @@ int HttpCache::Transaction::DoCreateEntry() {
next_state_ = STATE_CREATE_ENTRY_COMPLETE;
cache_pending_ = true;
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY);
+ ReportCacheActionStart();
return cache_->CreateEntry(cache_key_, &new_entry_, this);
}
@@ -904,6 +913,7 @@ int HttpCache::Transaction::DoCreateEntryComplete(int result) {
// It is important that we go to STATE_ADD_TO_ENTRY whenever the result is
// OK, otherwise the cache will end up with an active entry without any
// transaction attached.
+ ReportCacheActionFinish();
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_CREATE_ENTRY,
result);
cache_pending_ = false;
@@ -932,10 +942,12 @@ int HttpCache::Transaction::DoDoomEntry() {
next_state_ = STATE_DOOM_ENTRY_COMPLETE;
cache_pending_ = true;
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY);
+ ReportCacheActionStart();
return cache_->DoomEntry(cache_key_, this);
}
int HttpCache::Transaction::DoDoomEntryComplete(int result) {
+ ReportCacheActionFinish();
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_DOOM_ENTRY, result);
next_state_ = STATE_CREATE_ENTRY;
cache_pending_ = false;
@@ -1137,15 +1149,18 @@ int HttpCache::Transaction::DoTruncateCachedData() {
return OK;
if (net_log_.IsLoggingAllEvents())
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_DATA);
-
+ ReportCacheActionStart();
// Truncate the stream.
return WriteToEntry(kResponseContentIndex, 0, NULL, 0, io_callback_);
}
int HttpCache::Transaction::DoTruncateCachedDataComplete(int result) {
- if (net_log_.IsLoggingAllEvents() && entry_) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
- result);
+ if (entry_) {
+ ReportCacheActionFinish();
+ if (net_log_.IsLoggingAllEvents()) {
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
+ result);
+ }
}
next_state_ = STATE_TRUNCATE_CACHED_METADATA;
@@ -1159,13 +1174,17 @@ int HttpCache::Transaction::DoTruncateCachedMetadata() {
if (net_log_.IsLoggingAllEvents())
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
+ ReportCacheActionStart();
return WriteToEntry(kMetadataIndex, 0, NULL, 0, io_callback_);
}
int HttpCache::Transaction::DoTruncateCachedMetadataComplete(int result) {
- if (net_log_.IsLoggingAllEvents() && entry_) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO,
- result);
+ if (entry_) {
+ ReportCacheActionFinish();
+ if (net_log_.IsLoggingAllEvents()) {
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO,
+ result);
+ }
}
// If this response is a redirect, then we can stop writing now. (We don't
@@ -1207,11 +1226,13 @@ int HttpCache::Transaction::DoCacheReadResponse() {
read_buf_ = new IOBuffer(io_buf_len_);
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO);
+ ReportCacheActionStart();
return entry_->disk_entry->ReadData(kResponseInfoIndex, 0, read_buf_,
io_buf_len_, io_callback_);
}
int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
+ ReportCacheActionFinish();
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result);
if (result != io_buf_len_ ||
!HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_,
@@ -1256,14 +1277,20 @@ int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
}
int HttpCache::Transaction::DoCacheWriteResponse() {
- if (net_log_.IsLoggingAllEvents() && entry_)
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
+ if (entry_) {
+ if (net_log_.IsLoggingAllEvents())
+ net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
+ ReportCacheActionStart();
+ }
return WriteResponseInfoToEntry(false);
}
int HttpCache::Transaction::DoCacheWriteTruncatedResponse() {
- if (net_log_.IsLoggingAllEvents() && entry_)
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
+ if (entry_) {
+ if (net_log_.IsLoggingAllEvents() && entry_)
+ net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_INFO);
+ ReportCacheActionStart();
+ }
return WriteResponseInfoToEntry(true);
}
@@ -1272,6 +1299,7 @@ int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) {
target_state_ = STATE_NONE;
if (!entry_)
return OK;
+ ReportCacheActionFinish();
if (net_log_.IsLoggingAllEvents()) {
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_INFO,
result);
@@ -1294,12 +1322,14 @@ int HttpCache::Transaction::DoCacheReadMetadata() {
new IOBufferWithSize(entry_->disk_entry->GetDataSize(kMetadataIndex));
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_INFO);
+ ReportCacheActionStart();
return entry_->disk_entry->ReadData(kMetadataIndex, 0, response_.metadata,
response_.metadata->size(),
io_callback_);
}
int HttpCache::Transaction::DoCacheReadMetadataComplete(int result) {
+ ReportCacheActionFinish();
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_INFO, result);
if (result != response_.metadata->size())
return OnCacheReadError(result, false);
@@ -1328,6 +1358,7 @@ int HttpCache::Transaction::DoCacheReadData() {
if (net_log_.IsLoggingAllEvents())
net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_READ_DATA);
+ ReportCacheActionStart();
if (partial_.get()) {
return partial_->CacheRead(entry_->disk_entry, read_buf_, io_buf_len_,
io_callback_);
@@ -1338,6 +1369,7 @@ int HttpCache::Transaction::DoCacheReadData() {
}
int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
+ ReportCacheActionFinish();
if (net_log_.IsLoggingAllEvents()) {
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_READ_DATA,
result);
@@ -1363,16 +1395,22 @@ int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
int HttpCache::Transaction::DoCacheWriteData(int num_bytes) {
next_state_ = STATE_CACHE_WRITE_DATA_COMPLETE;
write_len_ = num_bytes;
- if (net_log_.IsLoggingAllEvents() && entry_)
- net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_DATA);
+ if (entry_) {
+ if (net_log_.IsLoggingAllEvents())
+ net_log_.BeginEvent(NetLog::TYPE_HTTP_CACHE_WRITE_DATA);
+ ReportCacheActionStart();
+ }
return AppendResponseDataToEntry(read_buf_, num_bytes, io_callback_);
}
int HttpCache::Transaction::DoCacheWriteDataComplete(int result) {
- if (net_log_.IsLoggingAllEvents() && entry_) {
- net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
- result);
+ if (entry_) {
+ ReportCacheActionFinish();
+ if (net_log_.IsLoggingAllEvents()) {
+ net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HTTP_CACHE_WRITE_DATA,
+ result);
+ }
}
// Balance the AddRef from DoCacheWriteData.
if (!cache_)
@@ -2112,4 +2150,14 @@ void HttpCache::Transaction::OnIOComplete(int result) {
DoLoop(result);
}
+void HttpCache::Transaction::ReportCacheActionStart() {
+ if (transaction_delegate_)
+ transaction_delegate_->OnCacheActionStart();
+}
+
+void HttpCache::Transaction::ReportCacheActionFinish() {
+ if (transaction_delegate_)
+ transaction_delegate_->OnCacheActionFinish();
+}
+
} // namespace net
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index 5b1dc6c..3f8a5e5 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -22,6 +22,7 @@ namespace net {
class PartialData;
struct HttpRequestInfo;
+class HttpTransactionDelegate;
// This is the transaction that is returned by the HttpCache transaction
// factory.
@@ -56,7 +57,7 @@ class HttpCache::Transaction : public HttpTransaction {
UPDATE = READ_META | WRITE, // READ_WRITE & ~READ_DATA
};
- explicit Transaction(HttpCache* cache);
+ Transaction(HttpCache* cache, HttpTransactionDelegate* transaction_delegate);
virtual ~Transaction();
Mode mode() const { return mode_; }
@@ -334,6 +335,9 @@ class HttpCache::Transaction : public HttpTransaction {
// Called to signal completion of asynchronous IO.
void OnIOComplete(int result);
+ void ReportCacheActionStart();
+ void ReportCacheActionFinish();
+
State next_state_;
const HttpRequestInfo* request_;
BoundNetLog net_log_;
@@ -371,6 +375,7 @@ class HttpCache::Transaction : public HttpTransaction {
uint64 final_upload_progress_;
base::WeakPtrFactory<Transaction> weak_factory_;
CompletionCallback io_callback_;
+ HttpTransactionDelegate* transaction_delegate_;
};
} // namespace net
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index d692c51..c43d49d 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -24,6 +24,7 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/http/http_transaction.h"
+#include "net/http/http_transaction_delegate.h"
#include "net/http/http_transaction_unittest.h"
#include "net/http/http_util.h"
#include "net/http/mock_http_cache.h"
@@ -59,6 +60,32 @@ class DeleteCacheCompletionCallback : public net::TestCompletionCallbackBase {
//-----------------------------------------------------------------------------
// helpers
+class TestHttpTransactionDelegate : public net::HttpTransactionDelegate {
+ public:
+ explicit TestHttpTransactionDelegate(int num_actions_to_observe)
+ : num_remaining_actions_to_observe_(num_actions_to_observe),
+ action_in_progress_(false) {
+ }
+ virtual ~TestHttpTransactionDelegate() {
+ EXPECT_EQ(0, num_remaining_actions_to_observe_);
+ EXPECT_FALSE(action_in_progress_);
+ }
+ virtual void OnCacheActionStart() {
+ EXPECT_FALSE(action_in_progress_);
+ EXPECT_GT(num_remaining_actions_to_observe_, 0);
+ num_remaining_actions_to_observe_--;
+ action_in_progress_ = true;
+ }
+ virtual void OnCacheActionFinish() {
+ EXPECT_TRUE(action_in_progress_);
+ action_in_progress_ = false;
+ }
+
+ private:
+ int num_remaining_actions_to_observe_;
+ bool action_in_progress_;
+};
+
void ReadAndVerifyTransaction(net::HttpTransaction* trans,
const MockTransaction& trans_info) {
std::string content;
@@ -69,17 +96,25 @@ void ReadAndVerifyTransaction(net::HttpTransaction* trans,
EXPECT_EQ(expected, content);
}
-void RunTransactionTestWithRequestAndLog(net::HttpCache* cache,
- const MockTransaction& trans_info,
- const MockHttpRequest& request,
- net::HttpResponseInfo* response_info,
- const net::BoundNetLog& net_log) {
+const int kNoDelegateTransactionCheck = -1;
+
+void RunTransactionTestWithRequestAndLogAndDelegate(
+ net::HttpCache* cache,
+ const MockTransaction& trans_info,
+ const MockHttpRequest& request,
+ net::HttpResponseInfo* response_info,
+ const net::BoundNetLog& net_log,
+ int num_delegate_actions) {
net::TestCompletionCallback callback;
// write to the cache
+ scoped_ptr<TestHttpTransactionDelegate> delegate;
+ if (num_delegate_actions != kNoDelegateTransactionCheck) {
+ delegate.reset(new TestHttpTransactionDelegate(num_delegate_actions));
+ }
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache->CreateTransaction(&trans);
+ int rv = cache->CreateTransaction(&trans, delegate.get());
EXPECT_EQ(net::OK, rv);
ASSERT_TRUE(trans.get());
@@ -101,15 +136,25 @@ void RunTransactionTestWithRequest(net::HttpCache* cache,
const MockTransaction& trans_info,
const MockHttpRequest& request,
net::HttpResponseInfo* response_info) {
- RunTransactionTestWithRequestAndLog(cache, trans_info, request,
- response_info, net::BoundNetLog());
+ RunTransactionTestWithRequestAndLogAndDelegate(
+ cache, trans_info, request, response_info, net::BoundNetLog(),
+ kNoDelegateTransactionCheck);
}
void RunTransactionTestWithLog(net::HttpCache* cache,
const MockTransaction& trans_info,
const net::BoundNetLog& log) {
- RunTransactionTestWithRequestAndLog(
- cache, trans_info, MockHttpRequest(trans_info), NULL, log);
+ RunTransactionTestWithRequestAndLogAndDelegate(
+ cache, trans_info, MockHttpRequest(trans_info), NULL, log,
+ kNoDelegateTransactionCheck);
+}
+
+void RunTransactionTestWithDelegate(net::HttpCache* cache,
+ const MockTransaction& trans_info,
+ int num_delegate_actions) {
+ RunTransactionTestWithRequestAndLogAndDelegate(
+ cache, trans_info, MockHttpRequest(trans_info), NULL, net::BoundNetLog(),
+ num_delegate_actions);
}
void RunTransactionTest(net::HttpCache* cache,
@@ -396,7 +441,7 @@ TEST(HttpCache, CreateThenDestroy) {
MockHttpCache cache;
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
ASSERT_TRUE(trans.get());
}
@@ -500,7 +545,7 @@ TEST(HttpCache, SimpleGETWithDiskFailures2) {
MockHttpRequest request(kSimpleGET_Transaction);
scoped_ptr<Context> c(new Context());
- int rv = cache.http_cache()->CreateTransaction(&c->trans);
+ int rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -545,7 +590,7 @@ TEST(HttpCache, SimpleGETWithDiskFailures3) {
// Now fail to read from the cache.
scoped_ptr<Context> c(new Context());
- int rv = cache.http_cache()->CreateTransaction(&c->trans);
+ int rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
MockHttpRequest request(kSimpleGET_Transaction);
@@ -645,7 +690,7 @@ TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Miss) {
net::TestCompletionCallback callback;
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
ASSERT_TRUE(trans.get());
@@ -871,7 +916,7 @@ TEST(HttpCache, SimpleGET_ManyReaders) {
context_list.push_back(new Context());
Context* c = context_list[i];
- c->result = cache.http_cache()->CreateTransaction(&c->trans);
+ c->result = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
EXPECT_EQ(net::LOAD_STATE_IDLE, c->trans->GetLoadState());
@@ -939,7 +984,7 @@ TEST(HttpCache, SimpleGET_RacingReaders) {
context_list.push_back(new Context());
Context* c = context_list[i];
- c->result = cache.http_cache()->CreateTransaction(&c->trans);
+ c->result = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
MockHttpRequest* this_request = &request;
@@ -1024,7 +1069,7 @@ TEST(HttpCache, SimpleGET_DoomWithPending) {
context_list.push_back(new Context());
Context* c = context_list[i];
- c->result = cache.http_cache()->CreateTransaction(&c->trans);
+ c->result = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
MockHttpRequest* this_request = &request;
@@ -1072,7 +1117,7 @@ TEST(HttpCache, FastNoStoreGET_DoneWithPending) {
context_list.push_back(new Context());
Context* c = context_list[i];
- c->result = cache.http_cache()->CreateTransaction(&c->trans);
+ c->result = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
c->result = c->trans->Start(
@@ -1119,7 +1164,7 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelFirst) {
context_list.push_back(new Context());
Context* c = context_list[i];
- c->result = cache.http_cache()->CreateTransaction(&c->trans);
+ c->result = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
c->result = c->trans->Start(
@@ -1179,7 +1224,7 @@ TEST(HttpCache, SimpleGET_ManyWriters_CancelCreate) {
context_list.push_back(new Context());
Context* c = context_list[i];
- c->result = cache.http_cache()->CreateTransaction(&c->trans);
+ c->result = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
c->result = c->trans->Start(
@@ -1230,7 +1275,7 @@ TEST(HttpCache, SimpleGET_CancelCreate) {
Context* c = new Context();
- c->result = cache.http_cache()->CreateTransaction(&c->trans);
+ c->result = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
c->result = c->trans->Start(
@@ -1260,7 +1305,7 @@ TEST(HttpCache, SimpleGET_ManyWriters_BypassCache) {
context_list.push_back(new Context());
Context* c = context_list[i];
- c->result = cache.http_cache()->CreateTransaction(&c->trans);
+ c->result = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
c->result = c->trans->Start(
@@ -1302,7 +1347,7 @@ TEST(HttpCache, SimpleGET_AbandonedCacheRead) {
net::TestCompletionCallback callback;
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = trans->Start(&request, callback.callback(), net::BoundNetLog());
if (rv == net::ERR_IO_PENDING)
@@ -1337,7 +1382,7 @@ TEST(HttpCache, SimpleGET_ManyWriters_DeleteCache) {
context_list.push_back(new Context());
Context* c = context_list[i];
- c->result = cache->http_cache()->CreateTransaction(&c->trans);
+ c->result = cache->http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
c->result = c->trans->Start(
@@ -1376,7 +1421,7 @@ TEST(HttpCache, SimpleGET_WaitForBackend) {
context_list.push_back(new Context());
Context* c = context_list[i];
- c->result = cache.http_cache()->CreateTransaction(&c->trans);
+ c->result = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
}
@@ -1422,7 +1467,7 @@ TEST(HttpCache, SimpleGET_WaitForBackend_CancelCreate) {
context_list.push_back(new Context());
Context* c = context_list[i];
- c->result = cache.http_cache()->CreateTransaction(&c->trans);
+ c->result = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
}
@@ -1468,7 +1513,7 @@ TEST(HttpCache, DeleteCacheWaitingForBackend) {
MockHttpRequest request(kSimpleGET_Transaction);
scoped_ptr<Context> c(new Context());
- c->result = cache->http_cache()->CreateTransaction(&c->trans);
+ c->result = cache->http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -1506,7 +1551,7 @@ TEST(HttpCache, DeleteCacheWaitingForBackend2) {
MockHttpRequest request(kSimpleGET_Transaction);
scoped_ptr<Context> c(new Context());
- c->result = cache->http_cache()->CreateTransaction(&c->trans);
+ c->result = cache->http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, c->result);
c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -2192,7 +2237,7 @@ TEST(HttpCache, SimplePOST_LoadOnlyFromCache_Miss) {
net::TestCompletionCallback callback;
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
ASSERT_TRUE(trans.get());
@@ -3253,7 +3298,7 @@ TEST(HttpCache, RangeGET_Cancel) {
MockHttpRequest request(kRangeGET_TransactionOK);
Context* c = new Context();
- int rv = cache.http_cache()->CreateTransaction(&c->trans);
+ int rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -3292,7 +3337,7 @@ TEST(HttpCache, RangeGET_Cancel2) {
request.load_flags |= net::LOAD_VALIDATE_CACHE;
Context* c = new Context();
- int rv = cache.http_cache()->CreateTransaction(&c->trans);
+ int rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -3337,7 +3382,7 @@ TEST(HttpCache, RangeGET_Cancel3) {
request.load_flags |= net::LOAD_VALIDATE_CACHE;
Context* c = new Context();
- int rv = cache.http_cache()->CreateTransaction(&c->trans);
+ int rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -3364,7 +3409,7 @@ TEST(HttpCache, RangeGET_Cancel3) {
// active entry (no open or create).
c = new Context();
- rv = cache.http_cache()->CreateTransaction(&c->trans);
+ rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -3645,7 +3690,7 @@ TEST(HttpCache, RangeGET_OK_LoadOnlyFromCache) {
net::TestCompletionCallback callback;
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
ASSERT_TRUE(trans.get());
@@ -3723,7 +3768,7 @@ TEST(HttpCache, DoomOnDestruction) {
MockHttpRequest request(kSimpleGET_Transaction);
Context* c = new Context();
- int rv = cache.http_cache()->CreateTransaction(&c->trans);
+ int rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -3753,7 +3798,7 @@ TEST(HttpCache, DoomOnDestruction2) {
MockHttpRequest request(kSimpleGET_Transaction);
Context* c = new Context();
- int rv = cache.http_cache()->CreateTransaction(&c->trans);
+ int rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -3796,7 +3841,7 @@ TEST(HttpCache, DoomOnDestruction3) {
MockHttpRequest request(transaction);
Context* c = new Context();
- int rv = cache.http_cache()->CreateTransaction(&c->trans);
+ int rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -3839,7 +3884,7 @@ TEST(HttpCache, SetTruncatedFlag) {
MockHttpRequest request(transaction);
scoped_ptr<Context> c(new Context());
- int rv = cache.http_cache()->CreateTransaction(&c->trans);
+ int rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -3899,7 +3944,7 @@ TEST(HttpCache, DontSetTruncatedFlag) {
MockHttpRequest request(transaction);
scoped_ptr<Context> c(new Context());
- int rv = cache.http_cache()->CreateTransaction(&c->trans);
+ int rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
@@ -4043,7 +4088,7 @@ TEST(HttpCache, GET_IncompleteResource_Cancel) {
MockHttpRequest request(transaction);
Context* c = new Context();
- int rv = cache.http_cache()->CreateTransaction(&c->trans);
+ int rv = cache.http_cache()->CreateTransaction(&c->trans, NULL);
EXPECT_EQ(net::OK, rv);
// Queue another request to this transaction. We have to start this request
@@ -4051,7 +4096,8 @@ TEST(HttpCache, GET_IncompleteResource_Cancel) {
// otherwise it will just create a new entry without being queued to the first
// request.
Context* pending = new Context();
- EXPECT_EQ(net::OK, cache.http_cache()->CreateTransaction(&pending->trans));
+ EXPECT_EQ(net::OK,
+ cache.http_cache()->CreateTransaction(&pending->trans, NULL));
rv = c->trans->Start(&request, c->callback.callback(), net::BoundNetLog());
EXPECT_EQ(net::ERR_IO_PENDING,
@@ -4135,7 +4181,7 @@ TEST(HttpCache, GET_IncompleteResource3) {
"rg: 50-59 rg: 60-69 rg: 70-79 ";
scoped_ptr<Context> c(new Context);
- EXPECT_EQ(net::OK, cache.http_cache()->CreateTransaction(&c->trans));
+ EXPECT_EQ(net::OK, cache.http_cache()->CreateTransaction(&c->trans, NULL));
MockHttpRequest request(transaction);
int rv = c->trans->Start(
@@ -4207,7 +4253,7 @@ TEST(HttpCache, GET_CancelIncompleteResource) {
MockHttpRequest request(transaction);
Context* c = new Context();
- EXPECT_EQ(net::OK, cache.http_cache()->CreateTransaction(&c->trans));
+ EXPECT_EQ(net::OK, cache.http_cache()->CreateTransaction(&c->trans, NULL));
int rv = c->trans->Start(
&request, c->callback.callback(), net::BoundNetLog());
@@ -4335,7 +4381,7 @@ TEST(HttpCache, CachedRedirect) {
// write to the cache
{
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
ASSERT_TRUE(trans.get());
@@ -4363,7 +4409,7 @@ TEST(HttpCache, CachedRedirect) {
// read from the cache
{
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
ASSERT_TRUE(trans.get());
@@ -4488,7 +4534,7 @@ TEST(HttpCache, SimpleGET_SSLError) {
net::TestCompletionCallback callback;
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
ASSERT_TRUE(trans.get());
@@ -4503,7 +4549,7 @@ TEST(HttpCache, OutlivedTransactions) {
MockHttpCache* cache = new MockHttpCache;
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache->http_cache()->CreateTransaction(&trans);
+ int rv = cache->http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
delete cache;
@@ -4741,7 +4787,7 @@ TEST(HttpCache, FilterCompletion) {
{
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
MockHttpRequest request(kSimpleGET_Transaction);
@@ -4775,7 +4821,7 @@ TEST(HttpCache, StopCachingDeletesEntry) {
{
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = trans->Start(&request, callback.callback(), net::BoundNetLog());
@@ -4813,7 +4859,7 @@ TEST(HttpCache, StopCachingSavesEntry) {
{
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
// Force a response that can be resumed.
@@ -4870,7 +4916,7 @@ TEST(HttpCache, StopCachingTruncatedEntry) {
{
// Now make a regular request.
scoped_ptr<net::HttpTransaction> trans;
- int rv = cache.http_cache()->CreateTransaction(&trans);
+ int rv = cache.http_cache()->CreateTransaction(&trans, NULL);
EXPECT_EQ(net::OK, rv);
rv = trans->Start(&request, callback.callback(), net::BoundNetLog());
@@ -4949,3 +4995,20 @@ TEST(HttpCache, TruncatedByContentLength2) {
EXPECT_TRUE(truncated);
entry->Close();
}
+
+TEST(HttpCache, SimpleGET_LoadOnlyFromCache_Hit_TransactionDelegate) {
+ MockHttpCache cache;
+
+ // Write to the cache.
+ RunTransactionTestWithDelegate(cache.http_cache(),
+ kSimpleGET_Transaction,
+ 8);
+
+ // Force this transaction to read from the cache.
+ MockTransaction transaction(kSimpleGET_Transaction);
+ transaction.load_flags |= net::LOAD_ONLY_FROM_CACHE;
+
+ RunTransactionTestWithDelegate(cache.http_cache(),
+ kSimpleGET_Transaction,
+ 5);
+}
diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc
index 0650b45..b326438 100644
--- a/net/http/http_network_layer.cc
+++ b/net/http/http_network_layer.cc
@@ -102,7 +102,8 @@ void HttpNetworkLayer::EnableSpdy(const std::string& mode) {
//-----------------------------------------------------------------------------
-int HttpNetworkLayer::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
+int HttpNetworkLayer::CreateTransaction(scoped_ptr<HttpTransaction>* trans,
+ HttpTransactionDelegate* delegate) {
if (suspended_)
return ERR_NETWORK_IO_SUSPENDED;
diff --git a/net/http/http_network_layer.h b/net/http/http_network_layer.h
index 283bcca..d9eb676 100644
--- a/net/http/http_network_layer.h
+++ b/net/http/http_network_layer.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
@@ -47,7 +47,8 @@ class NET_EXPORT HttpNetworkLayer
static void EnableSpdy(const std::string& mode);
// HttpTransactionFactory methods:
- virtual int CreateTransaction(scoped_ptr<HttpTransaction>* trans) OVERRIDE;
+ virtual int CreateTransaction(scoped_ptr<HttpTransaction>* trans,
+ HttpTransactionDelegate* delegate) OVERRIDE;
virtual HttpCache* GetCache() OVERRIDE;
virtual HttpNetworkSession* GetSession() OVERRIDE;
diff --git a/net/http/http_network_layer_unittest.cc b/net/http/http_network_layer_unittest.cc
index 167b209..a82dd00 100644
--- a/net/http/http_network_layer_unittest.cc
+++ b/net/http/http_network_layer_unittest.cc
@@ -50,28 +50,28 @@ class HttpNetworkLayerTest : public PlatformTest {
TEST_F(HttpNetworkLayerTest, CreateAndDestroy) {
scoped_ptr<HttpTransaction> trans;
- int rv = factory_->CreateTransaction(&trans);
+ int rv = factory_->CreateTransaction(&trans, NULL);
EXPECT_EQ(OK, rv);
EXPECT_TRUE(trans.get() != NULL);
}
TEST_F(HttpNetworkLayerTest, Suspend) {
scoped_ptr<HttpTransaction> trans;
- int rv = factory_->CreateTransaction(&trans);
+ int rv = factory_->CreateTransaction(&trans, NULL);
EXPECT_EQ(OK, rv);
trans.reset();
factory_->OnSuspend();
- rv = factory_->CreateTransaction(&trans);
+ rv = factory_->CreateTransaction(&trans, NULL);
EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, rv);
ASSERT_TRUE(trans == NULL);
factory_->OnResume();
- rv = factory_->CreateTransaction(&trans);
+ rv = factory_->CreateTransaction(&trans, NULL);
EXPECT_EQ(OK, rv);
}
@@ -101,7 +101,7 @@ TEST_F(HttpNetworkLayerTest, GET) {
request_info.load_flags = LOAD_NORMAL;
scoped_ptr<HttpTransaction> trans;
- int rv = factory_->CreateTransaction(&trans);
+ int rv = factory_->CreateTransaction(&trans, NULL);
EXPECT_EQ(OK, rv);
rv = trans->Start(&request_info, callback.callback(), BoundNetLog());
diff --git a/net/http/http_transaction_delegate.h b/net/http/http_transaction_delegate.h
new file mode 100644
index 0000000..99f348d
--- /dev/null
+++ b/net/http/http_transaction_delegate.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2012 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_DELEGATE_H_
+#define NET_HTTP_HTTP_TRANSACTION_DELEGATE_H_
+
+namespace net {
+
+// Delegate class receiving notifications when cache actions start and finish,
+// i.e. when the object starts and finishes waiting on an underlying cache.
+// The owner of a HttpTransaction can use this to register a delegate to
+// receive notifications when these events happen.
+class HttpTransactionDelegate {
+ public:
+ virtual ~HttpTransactionDelegate() {}
+ virtual void OnCacheActionStart() = 0;
+ virtual void OnCacheActionFinish() = 0;
+};
+
+} // namespace net
+
+#endif // NET_HTTP_HTTP_TRANSACTION_DELEGATE_H_
diff --git a/net/http/http_transaction_factory.h b/net/http/http_transaction_factory.h
index 6d2dfe0..08f43e5 100644
--- a/net/http/http_transaction_factory.h
+++ b/net/http/http_transaction_factory.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,7 +13,7 @@ namespace net {
class HttpCache;
class HttpNetworkSession;
class HttpTransaction;
-
+class HttpTransactionDelegate;
// An interface to a class that can create HttpTransaction objects.
class NET_EXPORT HttpTransactionFactory {
@@ -22,7 +22,8 @@ class NET_EXPORT HttpTransactionFactory {
// Creates a HttpTransaction object. On success, saves the new
// transaction to |*trans| and returns OK.
- virtual int CreateTransaction(scoped_ptr<HttpTransaction>* trans) = 0;
+ virtual int CreateTransaction(scoped_ptr<HttpTransaction>* trans,
+ HttpTransactionDelegate* delegate) = 0;
// Returns the associated cache if any (may be NULL).
virtual HttpCache* GetCache() = 0;
diff --git a/net/http/http_transaction_unittest.cc b/net/http/http_transaction_unittest.cc
index 9c09c42..f8d1958 100644
--- a/net/http/http_transaction_unittest.cc
+++ b/net/http/http_transaction_unittest.cc
@@ -151,7 +151,7 @@ TestTransactionConsumer::TestTransactionConsumer(
trans_(NULL),
error_(net::OK) {
// Disregard the error code.
- factory->CreateTransaction(&trans_);
+ factory->CreateTransaction(&trans_, NULL);
++quit_counter_;
}
@@ -341,7 +341,8 @@ void MockNetworkLayer::TransactionDoneReading() {
}
int MockNetworkLayer::CreateTransaction(
- scoped_ptr<net::HttpTransaction>* trans) {
+ scoped_ptr<net::HttpTransaction>* trans,
+ net::HttpTransactionDelegate* delegate) {
transaction_count_++;
trans->reset(new MockNetworkTransaction(this));
return net::OK;
diff --git a/net/http/http_transaction_unittest.h b/net/http/http_transaction_unittest.h
index ad2aaf8..43a9fa7 100644
--- a/net/http/http_transaction_unittest.h
+++ b/net/http/http_transaction_unittest.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
@@ -210,7 +210,8 @@ class MockNetworkLayer : public net::HttpTransactionFactory,
// net::HttpTransactionFactory:
virtual int CreateTransaction(
- scoped_ptr<net::HttpTransaction>* trans) OVERRIDE;
+ scoped_ptr<net::HttpTransaction>* trans,
+ net::HttpTransactionDelegate* delegate) OVERRIDE;
virtual net::HttpCache* GetCache() OVERRIDE;
virtual net::HttpNetworkSession* GetSession() OVERRIDE;
diff --git a/net/net.gyp b/net/net.gyp
index e320152..99f4298 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -515,6 +515,7 @@
'http/http_stream_parser.cc',
'http/http_stream_parser.h',
'http/http_transaction.h',
+ 'http/http_transaction_delegate.h',
'http/http_transaction_factory.h',
'http/http_util.cc',
'http/http_util.h',
diff --git a/net/proxy/network_delegate_error_observer_unittest.cc b/net/proxy/network_delegate_error_observer_unittest.cc
index b8084e0..46d2b01 100644
--- a/net/proxy/network_delegate_error_observer_unittest.cc
+++ b/net/proxy/network_delegate_error_observer_unittest.cc
@@ -84,6 +84,9 @@ class TestNetworkDelegate : public net::NetworkDelegate {
const CompletionCallback& callback) OVERRIDE {
return OK;
}
+ virtual void OnCacheWaitStateChange(const net::URLRequest& request,
+ CacheWaitState state) OVERRIDE {
+ }
bool got_pac_error_;
};
diff --git a/net/proxy/proxy_script_fetcher_impl_unittest.cc b/net/proxy/proxy_script_fetcher_impl_unittest.cc
index 74e37ae..62b5fbc 100644
--- a/net/proxy/proxy_script_fetcher_impl_unittest.cc
+++ b/net/proxy/proxy_script_fetcher_impl_unittest.cc
@@ -193,6 +193,10 @@ class BasicNetworkDelegate : public NetworkDelegate {
return OK;
}
+ virtual void OnCacheWaitStateChange(const net::URLRequest& request,
+ CacheWaitState state) OVERRIDE {
+ }
+
DISALLOW_COPY_AND_ASSIGN(BasicNetworkDelegate);
};
diff --git a/net/tools/fetch/fetch_client.cc b/net/tools/fetch/fetch_client.cc
index 32feba3..b69b2c9 100644
--- a/net/tools/fetch/fetch_client.cc
+++ b/net/tools/fetch/fetch_client.cc
@@ -59,7 +59,7 @@ class Client {
Client(net::HttpTransactionFactory* factory, const std::string& url) :
url_(url),
buffer_(new net::IOBuffer(kBufferSize)) {
- int rv = factory->CreateTransaction(&transaction_);
+ int rv = factory->CreateTransaction(&transaction_, NULL);
DCHECK_EQ(net::OK, rv);
buffer_->AddRef();
g_driver.Get().ClientStarted();
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 69038c5..e6baddc 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -111,6 +111,10 @@ class BasicNetworkDelegate : public NetworkDelegate {
return OK;
}
+ virtual void OnCacheWaitStateChange(const URLRequest& request,
+ CacheWaitState state) OVERRIDE {
+ }
+
DISALLOW_COPY_AND_ASSIGN(BasicNetworkDelegate);
};
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 718b454..06214e6 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -34,6 +34,7 @@
#include "net/http/http_response_info.h"
#include "net/http/http_status_code.h"
#include "net/http/http_transaction.h"
+#include "net/http/http_transaction_delegate.h"
#include "net/http/http_transaction_factory.h"
#include "net/http/http_util.h"
#include "net/url_request/fraudulent_certificate_reporter.h"
@@ -74,6 +75,43 @@ class URLRequestHttpJob::HttpFilterContext : public FilterContext {
DISALLOW_COPY_AND_ASSIGN(HttpFilterContext);
};
+class URLRequestHttpJob::HttpTransactionDelegateImpl
+ : public HttpTransactionDelegate {
+ public:
+ explicit HttpTransactionDelegateImpl(URLRequest* request)
+ : request_(request),
+ network_delegate_(request->context()->network_delegate()) {
+ }
+ virtual ~HttpTransactionDelegateImpl() {
+ OnDetachRequest();
+ }
+ void OnDetachRequest() {
+ if (request_ == NULL || network_delegate_ == NULL)
+ return;
+ network_delegate_->NotifyCacheWaitStateChange(
+ *request_,
+ NetworkDelegate::CACHE_WAIT_STATE_RESET);
+ request_ = NULL;
+ }
+ virtual void OnCacheActionStart() OVERRIDE {
+ if (request_ == NULL || network_delegate_ == NULL)
+ return;
+ network_delegate_->NotifyCacheWaitStateChange(
+ *request_,
+ NetworkDelegate::CACHE_WAIT_STATE_START);
+ }
+ virtual void OnCacheActionFinish() OVERRIDE {
+ if (request_ == NULL || network_delegate_ == NULL)
+ return;
+ network_delegate_->NotifyCacheWaitStateChange(
+ *request_,
+ NetworkDelegate::CACHE_WAIT_STATE_FINISH);
+ }
+ private:
+ URLRequest* request_;
+ NetworkDelegate* network_delegate_;
+};
+
URLRequestHttpJob::HttpFilterContext::HttpFilterContext(URLRequestHttpJob* job)
: job_(job) {
DCHECK(job_);
@@ -178,7 +216,8 @@ URLRequestHttpJob::URLRequestHttpJob(URLRequest* request)
ALLOW_THIS_IN_INITIALIZER_LIST(on_headers_received_callback_(
base::Bind(&URLRequestHttpJob::OnHeadersReceivedCallback,
base::Unretained(this)))),
- awaiting_callback_(false) {
+ awaiting_callback_(false),
+ http_transaction_delegate_(new HttpTransactionDelegateImpl(request)) {
URLRequestThrottlerManager* manager = request->context()->throttler_manager();
if (manager)
throttling_entry_ = manager->RegisterRequestUrl(request->url());
@@ -306,7 +345,7 @@ void URLRequestHttpJob::StartTransactionInternal() {
DCHECK(request_->context()->http_transaction_factory());
rv = request_->context()->http_transaction_factory()->CreateTransaction(
- &transaction_);
+ &transaction_, http_transaction_delegate_.get());
if (rv == OK) {
if (!throttling_entry_ ||
!throttling_entry_->ShouldRejectRequest(*request_)) {
@@ -1437,4 +1476,8 @@ void URLRequestHttpJob::NotifyURLRequestDestroyed() {
awaiting_callback_ = false;
}
+void URLRequestHttpJob::OnDetachRequest() {
+ http_transaction_delegate_->OnDetachRequest();
+}
+
} // namespace net
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h
index 39451c6..874955e 100644
--- a/net/url_request/url_request_http_job.h
+++ b/net/url_request/url_request_http_job.h
@@ -142,6 +142,7 @@ class URLRequestHttpJob : public URLRequestJob {
typedef base::RefCountedData<bool> SharedBoolean;
class HttpFilterContext;
+ class HttpTransactionDelegateImpl;
virtual ~URLRequestHttpJob();
@@ -187,6 +188,9 @@ class URLRequestHttpJob : public URLRequestJob {
// overridden by |override_response_headers_|.
HttpResponseHeaders* GetResponseHeaders() const;
+ // Override of the private interface of URLRequestJob.
+ virtual void OnDetachRequest() OVERRIDE;
+
base::Time request_creation_time_;
// Data used for statistics gathering. This data is only used for histograms
@@ -234,6 +238,8 @@ class URLRequestHttpJob : public URLRequestJob {
// to inform the NetworkDelegate that it may not call back.
bool awaiting_callback_;
+ scoped_ptr<HttpTransactionDelegateImpl> http_transaction_delegate_;
+
DISALLOW_COPY_AND_ASSIGN(URLRequestHttpJob);
};
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index 91dc5ba..9ba5578 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -55,6 +55,7 @@ void URLRequestJob::Kill() {
void URLRequestJob::DetachRequest() {
request_ = NULL;
+ OnDetachRequest();
}
// This function calls ReadData to get stream data. If a filter exists, passes
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h
index 92ceb14..6e3dbba 100644
--- a/net/url_request/url_request_job.h
+++ b/net/url_request/url_request_job.h
@@ -334,6 +334,9 @@ class NET_EXPORT URLRequestJob : public base::RefCounted<URLRequestJob>,
// The default implementation does nothing.
virtual void UpdatePacketReadTimes();
+ // Custom handler for derived classes when the request is detached.
+ virtual void OnDetachRequest() {}
+
// Indicates that the job is done producing data, either it has completed
// all the data or an error has been encountered. Set exclusively by
// NotifyDone so that it is kept in sync with the request.
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index 45ed7b7..7880041 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -500,6 +500,10 @@ int TestNetworkDelegate::OnBeforeSocketStreamConnect(
return net::OK;
}
+void TestNetworkDelegate::OnCacheWaitStateChange(const net::URLRequest& request,
+ CacheWaitState state) {
+}
+
// static
std::string ScopedCustomUrlRequestTestHttpHost::value_("127.0.0.1");
diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h
index 256264d..48a928f 100644
--- a/net/url_request/url_request_test_util.h
+++ b/net/url_request/url_request_test_util.h
@@ -245,6 +245,8 @@ class TestNetworkDelegate : public net::NetworkDelegate {
virtual int OnBeforeSocketStreamConnect(
net::SocketStream* stream,
const net::CompletionCallback& callback) OVERRIDE;
+ virtual void OnCacheWaitStateChange(const net::URLRequest& request,
+ CacheWaitState state) OVERRIDE;
void InitRequestStatesIfNew(int request_id);
diff --git a/net/websockets/websocket_job_spdy2_unittest.cc b/net/websockets/websocket_job_spdy2_unittest.cc
index 4835f34..f1ed00d 100644
--- a/net/websockets/websocket_job_spdy2_unittest.cc
+++ b/net/websockets/websocket_job_spdy2_unittest.cc
@@ -304,7 +304,8 @@ class MockHttpTransactionFactory : public net::HttpTransactionFactory {
}
virtual int CreateTransaction(
- scoped_ptr<net::HttpTransaction>* trans) OVERRIDE {
+ scoped_ptr<net::HttpTransaction>* trans,
+ net::HttpTransactionDelegate* delegate) OVERRIDE {
NOTREACHED();
return net::ERR_UNEXPECTED;
}
diff --git a/net/websockets/websocket_job_spdy3_unittest.cc b/net/websockets/websocket_job_spdy3_unittest.cc
index f69cae4..a05c094 100644
--- a/net/websockets/websocket_job_spdy3_unittest.cc
+++ b/net/websockets/websocket_job_spdy3_unittest.cc
@@ -306,7 +306,8 @@ class MockHttpTransactionFactory : public net::HttpTransactionFactory {
EXPECT_EQ(net::OK,
session_->InitializeWithSocket(connection, false, net::OK));
}
- virtual int CreateTransaction(scoped_ptr<net::HttpTransaction>* trans) {
+ virtual int CreateTransaction(scoped_ptr<net::HttpTransaction>* trans,
+ net::HttpTransactionDelegate* delegate) {
NOTREACHED();
return net::ERR_UNEXPECTED;
}
diff --git a/webkit/tools/test_shell/simple_resource_loader_bridge.cc b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
index 8519e42..106defa 100644
--- a/webkit/tools/test_shell/simple_resource_loader_bridge.cc
+++ b/webkit/tools/test_shell/simple_resource_loader_bridge.cc
@@ -187,6 +187,10 @@ class TestShellNetworkDelegate : public net::NetworkDelegate {
const net::CompletionCallback& callback) OVERRIDE {
return net::OK;
}
+
+ virtual void OnCacheWaitStateChange(const net::URLRequest& request,
+ CacheWaitState state) OVERRIDE {
+ }
};
TestShellRequestContextParams* g_request_context_params = NULL;