Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / net / net_error_tab_helper.cc
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.
4
5 #include "chrome/browser/net/net_error_tab_helper.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/prefs/pref_service.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/io_thread.h"
12 #include "chrome/browser/net/dns_probe_service.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/common/pref_names.h"
15 #include "chrome/common/render_messages.h"
16 #include "components/error_page/common/net_error_info.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "net/base/net_errors.h"
20
21 using chrome_common_net::DnsProbeStatus;
22 using chrome_common_net::DnsProbeStatusToString;
23 using content::BrowserContext;
24 using content::BrowserThread;
25 using ui::PageTransition;
26 using content::RenderViewHost;
27 using content::WebContents;
28 using content::WebContentsObserver;
29
30 DEFINE_WEB_CONTENTS_USER_DATA_KEY(chrome_browser_net::NetErrorTabHelper);
31
32 namespace chrome_browser_net {
33
34 namespace {
35
36 static NetErrorTabHelper::TestingState testing_state_ =
37     NetErrorTabHelper::TESTING_DEFAULT;
38
39 // Returns whether |net_error| is a DNS-related error (and therefore whether
40 // the tab helper should start a DNS probe after receiving it.)
41 bool IsDnsError(int net_error) {
42   return net_error == net::ERR_NAME_NOT_RESOLVED ||
43          net_error == net::ERR_NAME_RESOLUTION_FAILED;
44 }
45
46 void OnDnsProbeFinishedOnIOThread(
47     const base::Callback<void(DnsProbeStatus)>& callback,
48     DnsProbeStatus result) {
49   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
50
51   BrowserThread::PostTask(
52       BrowserThread::UI,
53       FROM_HERE,
54       base::Bind(callback, result));
55 }
56
57 // Can only access g_browser_process->io_thread() from the browser thread,
58 // so have to pass it in to the callback instead of dereferencing it here.
59 void StartDnsProbeOnIOThread(
60     const base::Callback<void(DnsProbeStatus)>& callback,
61     IOThread* io_thread) {
62   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
63
64   DnsProbeService* probe_service =
65       io_thread->globals()->dns_probe_service.get();
66
67   probe_service->ProbeDns(base::Bind(&OnDnsProbeFinishedOnIOThread, callback));
68 }
69
70 }  // namespace
71
72 NetErrorTabHelper::~NetErrorTabHelper() {
73 }
74
75 // static
76 void NetErrorTabHelper::set_state_for_testing(TestingState state) {
77   testing_state_ = state;
78 }
79
80 void NetErrorTabHelper::DidStartNavigationToPendingEntry(
81     const GURL& url,
82     content::NavigationController::ReloadType reload_type) {
83   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84
85   if (!is_error_page_)
86     return;
87
88   // Only record reloads.
89   if (reload_type != content::NavigationController::NO_RELOAD) {
90     chrome_common_net::RecordEvent(
91         chrome_common_net::NETWORK_ERROR_PAGE_BROWSER_INITIATED_RELOAD);
92   }
93 }
94
95 void NetErrorTabHelper::DidStartProvisionalLoadForFrame(
96     content::RenderFrameHost* render_frame_host,
97     const GURL& validated_url,
98     bool is_error_page,
99     bool is_iframe_srcdoc) {
100   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
101
102   if (render_frame_host->GetParent())
103     return;
104
105   is_error_page_ = is_error_page;
106 }
107
108 void NetErrorTabHelper::DidCommitProvisionalLoadForFrame(
109     content::RenderFrameHost* render_frame_host,
110     const GURL& url,
111     PageTransition transition_type) {
112   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
113
114   if (render_frame_host->GetParent())
115     return;
116
117   // Resend status every time an error page commits; this is somewhat spammy,
118   // but ensures that the status will make it to the real error page, even if
119   // the link doctor loads a blank intermediate page or the tab switches
120   // renderer processes.
121   if (is_error_page_ && dns_error_active_) {
122     dns_error_page_committed_ = true;
123     DVLOG(1) << "Committed error page; resending status.";
124     SendInfo();
125   } else {
126     dns_error_active_ = false;
127     dns_error_page_committed_ = false;
128   }
129 }
130
131 void NetErrorTabHelper::DidFailProvisionalLoad(
132     content::RenderFrameHost* render_frame_host,
133     const GURL& validated_url,
134     int error_code,
135     const base::string16& error_description) {
136   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
137
138   if (render_frame_host->GetParent())
139     return;
140
141   if (IsDnsError(error_code)) {
142     dns_error_active_ = true;
143     OnMainFrameDnsError();
144   }
145 }
146
147 NetErrorTabHelper::NetErrorTabHelper(WebContents* contents)
148     : WebContentsObserver(contents),
149       is_error_page_(false),
150       dns_error_active_(false),
151       dns_error_page_committed_(false),
152       dns_probe_status_(chrome_common_net::DNS_PROBE_POSSIBLE),
153       weak_factory_(this) {
154   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
155
156   // If this helper is under test, it won't have a WebContents.
157   if (contents)
158     InitializePref(contents);
159 }
160
161 void NetErrorTabHelper::OnMainFrameDnsError() {
162   if (ProbesAllowed()) {
163     // Don't start more than one probe at a time.
164     if (dns_probe_status_ != chrome_common_net::DNS_PROBE_STARTED) {
165       StartDnsProbe();
166       dns_probe_status_ = chrome_common_net::DNS_PROBE_STARTED;
167     }
168   } else {
169     dns_probe_status_ = chrome_common_net::DNS_PROBE_NOT_RUN;
170   }
171 }
172
173 void NetErrorTabHelper::StartDnsProbe() {
174   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
175   DCHECK(dns_error_active_);
176   DCHECK_NE(chrome_common_net::DNS_PROBE_STARTED, dns_probe_status_);
177
178   DVLOG(1) << "Starting DNS probe.";
179
180   BrowserThread::PostTask(
181       BrowserThread::IO,
182       FROM_HERE,
183       base::Bind(&StartDnsProbeOnIOThread,
184                  base::Bind(&NetErrorTabHelper::OnDnsProbeFinished,
185                             weak_factory_.GetWeakPtr()),
186                  g_browser_process->io_thread()));
187 }
188
189 void NetErrorTabHelper::OnDnsProbeFinished(DnsProbeStatus result) {
190   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
191   DCHECK_EQ(chrome_common_net::DNS_PROBE_STARTED, dns_probe_status_);
192   DCHECK(chrome_common_net::DnsProbeStatusIsFinished(result));
193
194   DVLOG(1) << "Finished DNS probe with result "
195            << DnsProbeStatusToString(result) << ".";
196
197   dns_probe_status_ = result;
198
199   if (dns_error_page_committed_)
200     SendInfo();
201 }
202
203 void NetErrorTabHelper::InitializePref(WebContents* contents) {
204   DCHECK(contents);
205
206   BrowserContext* browser_context = contents->GetBrowserContext();
207   Profile* profile = Profile::FromBrowserContext(browser_context);
208   resolve_errors_with_web_service_.Init(
209       prefs::kAlternateErrorPagesEnabled,
210       profile->GetPrefs());
211 }
212
213 bool NetErrorTabHelper::ProbesAllowed() const {
214   if (testing_state_ != TESTING_DEFAULT)
215     return testing_state_ == TESTING_FORCE_ENABLED;
216
217   // TODO(ttuttle): Disable on mobile?
218   return *resolve_errors_with_web_service_;
219 }
220
221 void NetErrorTabHelper::SendInfo() {
222   DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, dns_probe_status_);
223   DCHECK(dns_error_page_committed_);
224
225   DVLOG(1) << "Sending status " << DnsProbeStatusToString(dns_probe_status_);
226   content::RenderFrameHost* rfh = web_contents()->GetMainFrame();
227   rfh->Send(new ChromeViewMsg_NetErrorInfo(rfh->GetRoutingID(),
228                                            dns_probe_status_));
229
230   if (!dns_probe_status_snoop_callback_.is_null())
231     dns_probe_status_snoop_callback_.Run(dns_probe_status_);
232 }
233
234 }  // namespace chrome_browser_net