Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / captive_portal / captive_portal_tab_helper.cc
blob1e76e41359d1edb19097117f92e7cad68d043409
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/navigation_handle.h"
18 #include "content/public/browser/notification_details.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/browser/notification_source.h"
21 #include "content/public/browser/notification_types.h"
22 #include "content/public/browser/render_frame_host.h"
23 #include "content/public/browser/render_process_host.h"
24 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/resource_request_details.h"
26 #include "content/public/browser/web_contents.h"
27 #include "net/base/net_errors.h"
28 #include "net/ssl/ssl_info.h"
30 using captive_portal::CaptivePortalResult;
31 using content::ResourceType;
33 DEFINE_WEB_CONTENTS_USER_DATA_KEY(CaptivePortalTabHelper);
35 CaptivePortalTabHelper::CaptivePortalTabHelper(
36 content::WebContents* web_contents)
37 : content::WebContentsObserver(web_contents),
38 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
39 navigation_handle_(nullptr),
40 tab_reloader_(new CaptivePortalTabReloader(
41 profile_,
42 web_contents,
43 base::Bind(&CaptivePortalTabHelper::OpenLoginTabForWebContents,
44 web_contents,
45 false))),
46 login_detector_(new CaptivePortalLoginDetector(profile_)) {
47 registrar_.Add(this,
48 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
49 content::Source<Profile>(profile_));
52 CaptivePortalTabHelper::~CaptivePortalTabHelper() {
55 void CaptivePortalTabHelper::DidStartNavigation(
56 content::NavigationHandle* navigation_handle) {
57 DCHECK(CalledOnValidThread());
58 if (!navigation_handle->IsInMainFrame())
59 return;
61 // Always track the latest navigation. If a navigation was already tracked,
62 // and it committed (either the navigation proper or an error page), it is
63 // safe to start tracking the new navigation. Otherwise simulate an abort
64 // before reporting the start of the new navigation.
65 if (navigation_handle_ && !navigation_handle_->HasCommittedDocument() &&
66 !navigation_handle_->HasCommittedErrorPage()) {
67 tab_reloader_->OnAbort();
70 navigation_handle_ = navigation_handle;
71 tab_reloader_->OnLoadStart(
72 navigation_handle->GetURL().SchemeIsCryptographic());
75 void CaptivePortalTabHelper::DidRedirectNavigation(
76 content::NavigationHandle* navigation_handle) {
77 DCHECK(CalledOnValidThread());
78 if (navigation_handle != navigation_handle_)
79 return;
80 DCHECK(navigation_handle->IsInMainFrame());
81 tab_reloader_->OnRedirect(
82 navigation_handle->GetURL().SchemeIsCryptographic());
85 void CaptivePortalTabHelper::DidCommitNavigation(
86 content::NavigationHandle* navigation_handle) {
87 DCHECK(CalledOnValidThread());
88 if (!navigation_handle->IsInMainFrame())
89 return;
91 if (navigation_handle_ != navigation_handle)
92 DidStartNavigation(navigation_handle);
94 tab_reloader_->OnLoadCommitted(navigation_handle->GetNetErrorCode());
97 void CaptivePortalTabHelper::DidFinishNavigation(
98 content::NavigationHandle* navigation_handle) {
99 DCHECK(CalledOnValidThread());
100 if (navigation_handle != navigation_handle_)
101 return;
102 DCHECK(navigation_handle->IsInMainFrame());
104 if (!navigation_handle->HasCommittedDocument() &&
105 !navigation_handle->HasCommittedErrorPage()) {
106 tab_reloader_->OnAbort();
109 login_detector_->OnStoppedLoading();
111 navigation_handle_ = nullptr;
114 void CaptivePortalTabHelper::Observe(
115 int type,
116 const content::NotificationSource& source,
117 const content::NotificationDetails& details) {
118 DCHECK(CalledOnValidThread());
119 DCHECK_EQ(chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT, type);
120 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr());
122 const CaptivePortalService::Results* results =
123 content::Details<CaptivePortalService::Results>(details).ptr();
125 OnCaptivePortalResults(results->previous_result, results->result);
128 void CaptivePortalTabHelper::OnSSLCertError(const net::SSLInfo& ssl_info) {
129 tab_reloader_->OnSSLCertError(ssl_info);
132 bool CaptivePortalTabHelper::IsLoginTab() const {
133 return login_detector_->is_login_tab();
136 // static
137 void CaptivePortalTabHelper::OpenLoginTabForWebContents(
138 content::WebContents* web_contents,
139 bool focus) {
140 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
142 // If the Profile doesn't have a tabbed browser window open, do nothing.
143 if (!browser)
144 return;
146 // Check if the Profile's topmost browser window already has a login tab.
147 // If so, do nothing.
148 // TODO(mmenke): Consider focusing that tab, at least if this is the tab
149 // helper for the currently active tab for the profile.
150 for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
151 content::WebContents* contents =
152 browser->tab_strip_model()->GetWebContentsAt(i);
153 CaptivePortalTabHelper* captive_portal_tab_helper =
154 CaptivePortalTabHelper::FromWebContents(contents);
155 if (captive_portal_tab_helper->IsLoginTab()) {
156 if (focus)
157 browser->tab_strip_model()->ActivateTabAt(i, false);
158 return;
162 // Otherwise, open a login tab. Only end up here when a captive portal result
163 // was received, so it's safe to assume profile has a CaptivePortalService.
164 content::WebContents* new_contents = chrome::AddSelectedTabWithURL(
165 browser,
166 CaptivePortalServiceFactory::GetForProfile(
167 browser->profile())->test_url(),
168 ui::PAGE_TRANSITION_TYPED);
169 CaptivePortalTabHelper* captive_portal_tab_helper =
170 CaptivePortalTabHelper::FromWebContents(new_contents);
171 captive_portal_tab_helper->SetIsLoginTab();
174 void CaptivePortalTabHelper::OnCaptivePortalResults(
175 CaptivePortalResult previous_result,
176 CaptivePortalResult result) {
177 tab_reloader_->OnCaptivePortalResults(previous_result, result);
178 login_detector_->OnCaptivePortalResults(previous_result, result);
181 void CaptivePortalTabHelper::SetIsLoginTab() {
182 login_detector_->SetIsLoginTab();
185 void CaptivePortalTabHelper::SetTabReloaderForTest(
186 CaptivePortalTabReloader* tab_reloader) {
187 tab_reloader_.reset(tab_reloader);
190 CaptivePortalTabReloader* CaptivePortalTabHelper::GetTabReloaderForTest() {
191 return tab_reloader_.get();