Fire an error if a pref used in the UI is missing once all prefs are fetched.
[chromium-blink-merge.git] / chrome / browser / captive_portal / captive_portal_tab_helper.cc
bloba8479f74ea1aede5e07e6782f585a3ade5fef882
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/captive_portal/captive_portal_tab_helper.h"
7 #include "base/bind.h"
8 #include "chrome/browser/captive_portal/captive_portal_login_detector.h"
9 #include "chrome/browser/captive_portal/captive_portal_service_factory.h"
10 #include "chrome/browser/captive_portal/captive_portal_tab_reloader.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_finder.h"
15 #include "chrome/browser/ui/browser_tabstrip.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "content/public/browser/notification_details.h"
18 #include "content/public/browser/notification_service.h"
19 #include "content/public/browser/notification_source.h"
20 #include "content/public/browser/notification_types.h"
21 #include "content/public/browser/render_frame_host.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/render_view_host.h"
24 #include "content/public/browser/resource_request_details.h"
25 #include "content/public/browser/web_contents.h"
26 #include "net/base/net_errors.h"
27 #include "net/ssl/ssl_info.h"
29 using captive_portal::CaptivePortalResult;
30 using content::ResourceType;
32 DEFINE_WEB_CONTENTS_USER_DATA_KEY(CaptivePortalTabHelper);
34 CaptivePortalTabHelper::CaptivePortalTabHelper(
35 content::WebContents* web_contents)
36 : content::WebContentsObserver(web_contents),
37 // web_contents is NULL in unit tests.
38 profile_(web_contents ? Profile::FromBrowserContext(
39 web_contents->GetBrowserContext())
40 : NULL),
41 tab_reloader_(
42 new CaptivePortalTabReloader(
43 profile_,
44 web_contents,
45 base::Bind(&CaptivePortalTabHelper::OpenLoginTabForWebContents,
46 web_contents, false))),
47 login_detector_(new CaptivePortalLoginDetector(profile_)),
48 web_contents_(web_contents),
49 pending_error_code_(net::OK),
50 provisional_render_view_host_(NULL) {
51 registrar_.Add(this,
52 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
53 content::Source<Profile>(profile_));
54 registrar_.Add(this,
55 content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT,
56 content::Source<content::WebContents>(web_contents));
59 CaptivePortalTabHelper::~CaptivePortalTabHelper() {
62 void CaptivePortalTabHelper::RenderViewDeleted(
63 content::RenderViewHost* render_view_host) {
64 // This can happen when a cross-process navigation is aborted, either by
65 // pressing stop or by starting a new cross-process navigation that can't
66 // re-use |provisional_render_view_host_|. May also happen on a crash.
67 if (render_view_host == provisional_render_view_host_)
68 OnLoadAborted();
71 void CaptivePortalTabHelper::DidStartProvisionalLoadForFrame(
72 content::RenderFrameHost* render_frame_host,
73 const GURL& validated_url,
74 bool is_error_page,
75 bool is_iframe_srcdoc) {
76 DCHECK(CalledOnValidThread());
78 // Ignore subframes.
79 if (render_frame_host->GetParent())
80 return;
82 content::RenderViewHost* render_view_host =
83 render_frame_host->GetRenderViewHost();
84 if (provisional_render_view_host_) {
85 // If loading an error page for a previous failure, treat this as part of
86 // the previous load. Link Doctor pages act like two error page loads in a
87 // row. The second time, provisional_render_view_host_ will be NULL.
88 if (is_error_page && provisional_render_view_host_ == render_view_host)
89 return;
90 // Otherwise, abort the old load.
91 OnLoadAborted();
94 provisional_render_view_host_ = render_view_host;
95 pending_error_code_ = net::OK;
97 tab_reloader_->OnLoadStart(validated_url.SchemeIsSecure());
100 void CaptivePortalTabHelper::DidCommitProvisionalLoadForFrame(
101 content::RenderFrameHost* render_frame_host,
102 const GURL& url,
103 ui::PageTransition transition_type) {
104 DCHECK(CalledOnValidThread());
106 // Ignore subframes.
107 if (render_frame_host->GetParent())
108 return;
110 if (provisional_render_view_host_ == render_frame_host->GetRenderViewHost()) {
111 tab_reloader_->OnLoadCommitted(pending_error_code_);
112 } else {
113 // This may happen if the active RenderView commits a page before a cross
114 // process navigation cancels the old load. In this case, the commit of the
115 // old navigation will cancel the newer one.
116 OnLoadAborted();
118 // Send information about the new load.
119 tab_reloader_->OnLoadStart(url.SchemeIsSecure());
120 tab_reloader_->OnLoadCommitted(net::OK);
123 provisional_render_view_host_ = NULL;
124 pending_error_code_ = net::OK;
127 void CaptivePortalTabHelper::DidFailProvisionalLoad(
128 content::RenderFrameHost* render_frame_host,
129 const GURL& validated_url,
130 int error_code,
131 const base::string16& error_description) {
132 DCHECK(CalledOnValidThread());
134 // Ignore subframes and unexpected RenderViewHosts.
135 if (render_frame_host->GetParent() ||
136 render_frame_host->GetRenderViewHost() != provisional_render_view_host_)
137 return;
139 // Aborts generally aren't followed by loading an error page, so go ahead and
140 // reset the state now, to prevent any captive portal checks from triggering.
141 if (error_code == net::ERR_ABORTED) {
142 OnLoadAborted();
143 return;
146 pending_error_code_ = error_code;
149 void CaptivePortalTabHelper::DidStopLoading() {
150 DCHECK(CalledOnValidThread());
152 login_detector_->OnStoppedLoading();
155 void CaptivePortalTabHelper::Observe(
156 int type,
157 const content::NotificationSource& source,
158 const content::NotificationDetails& details) {
159 DCHECK(CalledOnValidThread());
160 switch (type) {
161 case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
162 DCHECK_EQ(web_contents(),
163 content::Source<content::WebContents>(source).ptr());
165 const content::ResourceRedirectDetails* redirect_details =
166 content::Details<content::ResourceRedirectDetails>(details).ptr();
168 OnRedirect(redirect_details->origin_child_id,
169 redirect_details->resource_type,
170 redirect_details->new_url);
171 break;
173 case chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT: {
174 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr());
176 const CaptivePortalService::Results* results =
177 content::Details<CaptivePortalService::Results>(details).ptr();
179 OnCaptivePortalResults(results->previous_result, results->result);
180 break;
182 default:
183 NOTREACHED();
187 void CaptivePortalTabHelper::OnSSLCertError(const net::SSLInfo& ssl_info) {
188 tab_reloader_->OnSSLCertError(ssl_info);
191 bool CaptivePortalTabHelper::IsLoginTab() const {
192 return login_detector_->is_login_tab();
195 // static
196 void CaptivePortalTabHelper::OpenLoginTabForWebContents(
197 content::WebContents* web_contents,
198 bool focus) {
199 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
201 // If the Profile doesn't have a tabbed browser window open, do nothing.
202 if (!browser)
203 return;
205 // Check if the Profile's topmost browser window already has a login tab.
206 // If so, do nothing.
207 // TODO(mmenke): Consider focusing that tab, at least if this is the tab
208 // helper for the currently active tab for the profile.
209 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
210 content::WebContents* contents =
211 browser->tab_strip_model()->GetWebContentsAt(i);
212 CaptivePortalTabHelper* captive_portal_tab_helper =
213 CaptivePortalTabHelper::FromWebContents(contents);
214 if (captive_portal_tab_helper->IsLoginTab()) {
215 if (focus)
216 browser->tab_strip_model()->ActivateTabAt(i, false);
217 return;
221 // Otherwise, open a login tab. Only end up here when a captive portal result
222 // was received, so it's safe to assume profile has a CaptivePortalService.
223 content::WebContents* new_contents = chrome::AddSelectedTabWithURL(
224 browser,
225 CaptivePortalServiceFactory::GetForProfile(
226 browser->profile())->test_url(),
227 ui::PAGE_TRANSITION_TYPED);
228 CaptivePortalTabHelper* captive_portal_tab_helper =
229 CaptivePortalTabHelper::FromWebContents(new_contents);
230 captive_portal_tab_helper->SetIsLoginTab();
233 void CaptivePortalTabHelper::OnRedirect(int child_id,
234 ResourceType resource_type,
235 const GURL& new_url) {
236 // Only main frame redirects for the provisional RenderViewHost matter.
237 if (resource_type != content::RESOURCE_TYPE_MAIN_FRAME ||
238 !provisional_render_view_host_ ||
239 provisional_render_view_host_->GetProcess()->GetID() != child_id) {
240 return;
243 tab_reloader_->OnRedirect(new_url.SchemeIsSecure());
246 void CaptivePortalTabHelper::OnCaptivePortalResults(
247 CaptivePortalResult previous_result,
248 CaptivePortalResult result) {
249 tab_reloader_->OnCaptivePortalResults(previous_result, result);
250 login_detector_->OnCaptivePortalResults(previous_result, result);
253 void CaptivePortalTabHelper::OnLoadAborted() {
254 // No further messages for the cancelled navigation will occur.
255 provisional_render_view_host_ = NULL;
256 // May have been aborting the load of an error page.
257 pending_error_code_ = net::OK;
259 tab_reloader_->OnAbort();
262 void CaptivePortalTabHelper::SetIsLoginTab() {
263 login_detector_->SetIsLoginTab();
266 void CaptivePortalTabHelper::SetTabReloaderForTest(
267 CaptivePortalTabReloader* tab_reloader) {
268 tab_reloader_.reset(tab_reloader);
271 CaptivePortalTabReloader* CaptivePortalTabHelper::GetTabReloaderForTest() {
272 return tab_reloader_.get();