NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / net / net_error_tab_helper.cc
blob7112321fa1fa0f2bb550fd08eb0dd71865743930
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/net/net_error_tab_helper.h"
7 #include "base/bind.h"
8 #include "base/prefs/pref_service.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/io_thread.h"
11 #include "chrome/browser/net/dns_probe_service.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/common/net/net_error_info.h"
14 #include "chrome/common/pref_names.h"
15 #include "chrome/common/render_messages.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_frame_host.h"
18 #include "net/base/net_errors.h"
20 using chrome_common_net::DnsProbeStatus;
21 using chrome_common_net::DnsProbeStatusToString;
22 using content::BrowserContext;
23 using content::BrowserThread;
24 using content::PageTransition;
25 using content::RenderViewHost;
26 using content::WebContents;
27 using content::WebContentsObserver;
29 DEFINE_WEB_CONTENTS_USER_DATA_KEY(chrome_browser_net::NetErrorTabHelper);
31 namespace chrome_browser_net {
33 namespace {
35 static NetErrorTabHelper::TestingState testing_state_ =
36 NetErrorTabHelper::TESTING_DEFAULT;
38 // Returns whether |net_error| is a DNS-related error (and therefore whether
39 // the tab helper should start a DNS probe after receiving it.)
40 bool IsDnsError(int net_error) {
41 return net_error == net::ERR_NAME_NOT_RESOLVED ||
42 net_error == net::ERR_NAME_RESOLUTION_FAILED;
45 void OnDnsProbeFinishedOnIOThread(
46 const base::Callback<void(DnsProbeStatus)>& callback,
47 DnsProbeStatus result) {
48 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
50 BrowserThread::PostTask(
51 BrowserThread::UI,
52 FROM_HERE,
53 base::Bind(callback, result));
56 // Can only access g_browser_process->io_thread() from the browser thread,
57 // so have to pass it in to the callback instead of dereferencing it here.
58 void StartDnsProbeOnIOThread(
59 const base::Callback<void(DnsProbeStatus)>& callback,
60 IOThread* io_thread) {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
63 DnsProbeService* probe_service =
64 io_thread->globals()->dns_probe_service.get();
66 probe_service->ProbeDns(base::Bind(&OnDnsProbeFinishedOnIOThread, callback));
69 } // namespace
71 NetErrorTabHelper::~NetErrorTabHelper() {
74 // static
75 void NetErrorTabHelper::set_state_for_testing(TestingState state) {
76 testing_state_ = state;
79 void NetErrorTabHelper::DidStartProvisionalLoadForFrame(
80 int64 frame_id,
81 int64 parent_frame_id,
82 bool is_main_frame,
83 const GURL& validated_url,
84 bool is_error_page,
85 bool is_iframe_srcdoc,
86 RenderViewHost* render_view_host) {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
89 if (!is_main_frame)
90 return;
92 is_error_page_ = is_error_page;
95 void NetErrorTabHelper::DidCommitProvisionalLoadForFrame(
96 int64 frame_id,
97 const base::string16& frame_unique_name,
98 bool is_main_frame,
99 const GURL& url,
100 PageTransition transition_type,
101 RenderViewHost* render_view_host) {
102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
104 if (!is_main_frame)
105 return;
107 // Resend status every time an error page commits; this is somewhat spammy,
108 // but ensures that the status will make it to the real error page, even if
109 // the link doctor loads a blank intermediate page or the tab switches
110 // renderer processes.
111 if (is_error_page_ && dns_error_active_) {
112 dns_error_page_committed_ = true;
113 DVLOG(1) << "Committed error page; resending status.";
114 SendInfo();
115 } else {
116 dns_error_active_ = false;
117 dns_error_page_committed_ = false;
121 void NetErrorTabHelper::DidFailProvisionalLoad(
122 int64 frame_id,
123 const base::string16& frame_unique_name,
124 bool is_main_frame,
125 const GURL& validated_url,
126 int error_code,
127 const base::string16& error_description,
128 RenderViewHost* render_view_host) {
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
131 if (!is_main_frame)
132 return;
134 if (IsDnsError(error_code)) {
135 dns_error_active_ = true;
136 OnMainFrameDnsError();
140 NetErrorTabHelper::NetErrorTabHelper(WebContents* contents)
141 : WebContentsObserver(contents),
142 weak_factory_(this),
143 is_error_page_(false),
144 dns_error_active_(false),
145 dns_error_page_committed_(false),
146 dns_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE) {
147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
149 // If this helper is under test, it won't have a WebContents.
150 if (contents)
151 InitializePref(contents);
154 void NetErrorTabHelper::OnMainFrameDnsError() {
155 if (ProbesAllowed()) {
156 // Don't start more than one probe at a time.
157 if (dns_probe_status_ != chrome_common_net::DNS_PROBE_STARTED) {
158 StartDnsProbe();
159 dns_probe_status_ = chrome_common_net::DNS_PROBE_STARTED;
161 } else {
162 dns_probe_status_ = chrome_common_net::DNS_PROBE_NOT_RUN;
166 void NetErrorTabHelper::StartDnsProbe() {
167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
168 DCHECK(dns_error_active_);
169 DCHECK_NE(chrome_common_net::DNS_PROBE_STARTED, dns_probe_status_);
171 DVLOG(1) << "Starting DNS probe.";
173 BrowserThread::PostTask(
174 BrowserThread::IO,
175 FROM_HERE,
176 base::Bind(&StartDnsProbeOnIOThread,
177 base::Bind(&NetErrorTabHelper::OnDnsProbeFinished,
178 weak_factory_.GetWeakPtr()),
179 g_browser_process->io_thread()));
182 void NetErrorTabHelper::OnDnsProbeFinished(DnsProbeStatus result) {
183 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
184 DCHECK_EQ(chrome_common_net::DNS_PROBE_STARTED, dns_probe_status_);
185 DCHECK(chrome_common_net::DnsProbeStatusIsFinished(result));
187 DVLOG(1) << "Finished DNS probe with result "
188 << DnsProbeStatusToString(result) << ".";
190 dns_probe_status_ = result;
192 if (dns_error_page_committed_)
193 SendInfo();
196 void NetErrorTabHelper::InitializePref(WebContents* contents) {
197 DCHECK(contents);
199 BrowserContext* browser_context = contents->GetBrowserContext();
200 Profile* profile = Profile::FromBrowserContext(browser_context);
201 resolve_errors_with_web_service_.Init(
202 prefs::kAlternateErrorPagesEnabled,
203 profile->GetPrefs());
206 bool NetErrorTabHelper::ProbesAllowed() const {
207 if (testing_state_ != TESTING_DEFAULT)
208 return testing_state_ == TESTING_FORCE_ENABLED;
210 // TODO(ttuttle): Disable on mobile?
211 return *resolve_errors_with_web_service_;
214 void NetErrorTabHelper::SendInfo() {
215 DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, dns_probe_status_);
216 DCHECK(dns_error_page_committed_);
218 DVLOG(1) << "Sending status " << DnsProbeStatusToString(dns_probe_status_);
219 content::RenderFrameHost* rfh = web_contents()->GetMainFrame();
220 rfh->Send(new ChromeViewMsg_NetErrorInfo(rfh->GetRoutingID(),
221 dns_probe_status_));
223 if (!dns_probe_status_snoop_callback_.is_null())
224 dns_probe_status_snoop_callback_.Run(dns_probe_status_);
227 } // namespace chrome_browser_net