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"
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(
43 base::Bind(&CaptivePortalTabHelper::OpenLoginTabForWebContents
,
46 login_detector_(new CaptivePortalLoginDetector(profile_
)) {
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())
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_
)
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())
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_
)
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(
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();
137 void CaptivePortalTabHelper::OpenLoginTabForWebContents(
138 content::WebContents
* web_contents
,
140 Browser
* browser
= chrome::FindBrowserWithWebContents(web_contents
);
142 // If the Profile doesn't have a tabbed browser window open, do nothing.
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()) {
157 browser
->tab_strip_model()->ActivateTabAt(i
, false);
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(
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();