OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/captive_portal/captive_portal_tab_helper.h" | 5 #include "chrome/browser/captive_portal/captive_portal_tab_helper.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "chrome/browser/captive_portal/captive_portal_login_detector.h" | 8 #include "chrome/browser/captive_portal/captive_portal_login_detector.h" |
9 #include "chrome/browser/captive_portal/captive_portal_tab_reloader.h" | 9 #include "chrome/browser/captive_portal/captive_portal_tab_reloader.h" |
10 #include "chrome/browser/captive_portal/captive_portal_service_factory.h" | 10 #include "chrome/browser/captive_portal/captive_portal_service_factory.h" |
11 #include "chrome/browser/ui/browser.h" | 11 #include "chrome/browser/ui/browser.h" |
12 #include "chrome/browser/ui/browser_finder.h" | 12 #include "chrome/browser/ui/browser_finder.h" |
13 #include "chrome/browser/ui/browser_tabstrip.h" | 13 #include "chrome/browser/ui/browser_tabstrip.h" |
14 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 14 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
15 #include "chrome/common/chrome_notification_types.h" | 15 #include "chrome/common/chrome_notification_types.h" |
16 #include "content/public/browser/notification_details.h" | 16 #include "content/public/browser/notification_details.h" |
17 #include "content/public/browser/notification_service.h" | |
17 #include "content/public/browser/notification_source.h" | 18 #include "content/public/browser/notification_source.h" |
18 #include "content/public/browser/notification_types.h" | 19 #include "content/public/browser/notification_types.h" |
20 #include "content/public/browser/render_process_host.h" | |
21 #include "content/public/browser/render_view_host.h" | |
19 #include "content/public/browser/resource_request_details.h" | 22 #include "content/public/browser/resource_request_details.h" |
23 #include "content/public/browser/web_contents.h" | |
20 #include "net/base/net_errors.h" | 24 #include "net/base/net_errors.h" |
21 | 25 |
22 namespace captive_portal { | 26 namespace captive_portal { |
23 | 27 |
24 CaptivePortalTabHelper::CaptivePortalTabHelper( | 28 CaptivePortalTabHelper::CaptivePortalTabHelper( |
25 Profile* profile, | 29 Profile* profile, |
26 content::WebContents* web_contents) | 30 content::WebContents* web_contents) |
27 : content::WebContentsObserver(web_contents), | 31 : content::WebContentsObserver(web_contents), |
28 tab_reloader_( | 32 tab_reloader_( |
29 new CaptivePortalTabReloader( | 33 new CaptivePortalTabReloader( |
30 profile, | 34 profile, |
31 web_contents, | 35 web_contents, |
32 base::Bind(&CaptivePortalTabHelper::OpenLoginTab, | 36 base::Bind(&CaptivePortalTabHelper::OpenLoginTab, |
33 base::Unretained(this)))), | 37 base::Unretained(this)))), |
34 login_detector_(new CaptivePortalLoginDetector(profile)), | 38 login_detector_(new CaptivePortalLoginDetector(profile)), |
35 profile_(profile), | 39 profile_(profile), |
36 pending_error_code_(net::OK), | 40 pending_error_code_(net::OK), |
37 provisional_main_frame_id_(-1) { | 41 provisional_render_view_host_(NULL) { |
38 registrar_.Add(this, | 42 registrar_.Add(this, |
39 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT, | 43 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT, |
40 content::Source<Profile>(profile_)); | 44 content::Source<Profile>(profile_)); |
41 registrar_.Add(this, | 45 registrar_.Add(this, |
42 content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, | 46 content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT, |
43 content::Source<content::WebContents>(web_contents)); | 47 content::Source<content::WebContents>(web_contents)); |
48 registrar_.Add(this, | |
49 content::NOTIFICATION_RENDER_VIEW_HOST_DELETED, | |
50 content::NotificationService::AllSources()); | |
44 } | 51 } |
45 | 52 |
46 CaptivePortalTabHelper::~CaptivePortalTabHelper() { | 53 CaptivePortalTabHelper::~CaptivePortalTabHelper() { |
47 } | 54 } |
48 | 55 |
49 void CaptivePortalTabHelper::DidStartProvisionalLoadForFrame( | 56 void CaptivePortalTabHelper::DidStartProvisionalLoadForFrame( |
50 int64 frame_id, | 57 int64 frame_id, |
51 bool is_main_frame, | 58 bool is_main_frame, |
52 const GURL& validated_url, | 59 const GURL& validated_url, |
53 bool is_error_page, | 60 bool is_error_page, |
54 content::RenderViewHost* render_view_host) { | 61 content::RenderViewHost* render_view_host) { |
55 DCHECK(CalledOnValidThread()); | 62 DCHECK(CalledOnValidThread()); |
56 | 63 |
57 // Ignore subframes. | 64 // Ignore subframes. |
58 if (!is_main_frame) | 65 if (!is_main_frame) |
59 return; | 66 return; |
60 | 67 |
61 provisional_main_frame_id_ = frame_id; | 68 if (provisional_render_view_host_) { |
69 // If loading an error page for a previous failure, treat this as part of | |
70 // the previous load. Link Doctor pages act like two error page loads in a | |
71 // row. The second time, provisional_render_view_host_ will be NULL. | |
72 if (is_error_page && provisional_render_view_host_ == render_view_host) | |
73 return; | |
74 // Otherwise, abort the old load. | |
75 OnLoadAborted(); | |
76 } | |
62 | 77 |
63 // If loading an error page for a previous failure, treat this as part of | 78 provisional_render_view_host_ = render_view_host; |
64 // the previous load. The second check is needed because Link Doctor pages | |
65 // result in two error page provisional loads in a row. Currently, the | |
66 // second load is treated as a normal load, rather than reusing old error | |
67 // codes. | |
68 if (is_error_page && pending_error_code_ != net::OK) | |
69 return; | |
70 | |
71 // Makes the second load for Link Doctor pages act as a normal load. | |
72 // TODO(mmenke): Figure out if this affects any other cases. | |
73 pending_error_code_ = net::OK; | 79 pending_error_code_ = net::OK; |
74 | 80 |
75 tab_reloader_->OnLoadStart(validated_url.SchemeIsSecure()); | 81 tab_reloader_->OnLoadStart(validated_url.SchemeIsSecure()); |
76 } | 82 } |
77 | 83 |
78 void CaptivePortalTabHelper::DidCommitProvisionalLoadForFrame( | 84 void CaptivePortalTabHelper::DidCommitProvisionalLoadForFrame( |
79 int64 frame_id, | 85 int64 frame_id, |
80 bool is_main_frame, | 86 bool is_main_frame, |
81 const GURL& url, | 87 const GURL& url, |
82 content::PageTransition transition_type, | 88 content::PageTransition transition_type, |
83 content::RenderViewHost* render_view_host) { | 89 content::RenderViewHost* render_view_host) { |
84 DCHECK(CalledOnValidThread()); | 90 DCHECK(CalledOnValidThread()); |
85 | 91 |
86 // Ignore subframes. | 92 // Ignore subframes. |
87 if (!is_main_frame) | 93 if (!is_main_frame) |
88 return; | 94 return; |
89 | 95 |
90 provisional_main_frame_id_ = -1; | 96 if (provisional_render_view_host_ == render_view_host) { |
97 tab_reloader_->OnLoadCommitted(pending_error_code_); | |
98 } else { | |
99 // This may happen if the active RenderView commits a page before a cross | |
100 // process navigation cancels the old load. In this case, the commit of the | |
101 // old navigation will cancel the newer one. | |
102 OnLoadAborted(); | |
91 | 103 |
92 tab_reloader_->OnLoadCommitted(pending_error_code_); | 104 // Send information about the new load. |
105 tab_reloader_->OnLoadStart(url.SchemeIsSecure()); | |
106 tab_reloader_->OnLoadCommitted(net::OK); | |
107 } | |
108 | |
109 provisional_render_view_host_ = NULL; | |
93 pending_error_code_ = net::OK; | 110 pending_error_code_ = net::OK; |
94 } | 111 } |
95 | 112 |
96 void CaptivePortalTabHelper::DidFailProvisionalLoad( | 113 void CaptivePortalTabHelper::DidFailProvisionalLoad( |
97 int64 frame_id, | 114 int64 frame_id, |
98 bool is_main_frame, | 115 bool is_main_frame, |
99 const GURL& validated_url, | 116 const GURL& validated_url, |
100 int error_code, | 117 int error_code, |
101 const string16& error_description, | 118 const string16& error_description, |
102 content::RenderViewHost* render_view_host) { | 119 content::RenderViewHost* render_view_host) { |
103 DCHECK(CalledOnValidThread()); | 120 DCHECK(CalledOnValidThread()); |
104 | 121 |
105 // Ignore subframes. | 122 // Ignore subframes and unexpected RenderViewHosts. |
106 if (!is_main_frame) | 123 if (!is_main_frame || render_view_host != provisional_render_view_host_) |
107 return; | 124 return; |
108 | 125 |
109 provisional_main_frame_id_ = -1; | |
110 | |
111 // Aborts generally aren't followed by loading an error page, so go ahead and | 126 // Aborts generally aren't followed by loading an error page, so go ahead and |
112 // reset the state now, to prevent any captive portal checks from triggering. | 127 // reset the state now, to prevent any captive portal checks from triggering. |
113 if (error_code == net::ERR_ABORTED) { | 128 if (error_code == net::ERR_ABORTED) { |
114 // May have been aborting the load of an error page. | 129 OnLoadAborted(); |
115 pending_error_code_ = net::OK; | |
116 | |
117 tab_reloader_->OnAbort(); | |
118 return; | 130 return; |
119 } | 131 } |
120 | 132 |
121 pending_error_code_ = error_code; | 133 pending_error_code_ = error_code; |
122 } | 134 } |
123 | 135 |
124 void CaptivePortalTabHelper::DidStopLoading( | 136 void CaptivePortalTabHelper::DidStopLoading( |
125 content::RenderViewHost* render_view_host) { | 137 content::RenderViewHost* render_view_host) { |
126 DCHECK(CalledOnValidThread()); | 138 DCHECK(CalledOnValidThread()); |
127 | 139 |
128 login_detector_->OnStoppedLoading(); | 140 login_detector_->OnStoppedLoading(); |
129 } | 141 } |
130 | 142 |
131 void CaptivePortalTabHelper::Observe( | 143 void CaptivePortalTabHelper::Observe( |
132 int type, | 144 int type, |
133 const content::NotificationSource& source, | 145 const content::NotificationSource& source, |
134 const content::NotificationDetails& details) { | 146 const content::NotificationDetails& details) { |
135 DCHECK(CalledOnValidThread()); | 147 DCHECK(CalledOnValidThread()); |
136 if (type == content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT) { | 148 switch (type) { |
137 DCHECK_EQ(web_contents(), | 149 case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: { |
138 content::Source<content::WebContents>(source).ptr()); | 150 DCHECK_EQ(web_contents(), |
151 content::Source<content::WebContents>(source).ptr()); | |
139 | 152 |
140 const content::ResourceRedirectDetails* redirect_details = | 153 const content::ResourceRedirectDetails* redirect_details = |
141 content::Details<content::ResourceRedirectDetails>(details).ptr(); | 154 content::Details<content::ResourceRedirectDetails>(details).ptr(); |
142 | 155 |
143 if (redirect_details->resource_type == ResourceType::MAIN_FRAME) | 156 OnRedirect(redirect_details->origin_child_id, |
144 OnRedirect(redirect_details->frame_id, redirect_details->new_url); | 157 redirect_details->resource_type, |
145 } else if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) { | 158 redirect_details->new_url); |
146 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr()); | 159 break; |
160 } | |
161 case chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT: { | |
162 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr()); | |
147 | 163 |
148 const CaptivePortalService::Results* results = | 164 const CaptivePortalService::Results* results = |
149 content::Details<CaptivePortalService::Results>(details).ptr(); | 165 content::Details<CaptivePortalService::Results>(details).ptr(); |
150 | 166 |
151 OnCaptivePortalResults(results->previous_result, results->result); | 167 OnCaptivePortalResults(results->previous_result, results->result); |
152 } else { | 168 break; |
153 NOTREACHED(); | 169 } |
170 case content::NOTIFICATION_RENDER_VIEW_HOST_DELETED: { | |
171 content::RenderViewHost* render_view_host = | |
172 content::Source<content::RenderViewHost>(source).ptr(); | |
173 // This can happen when a cross-process navigation is aborted, either by | |
174 // pressing stop or by starting a new cross-process navigation that can't | |
175 // re-use |provisional_render_view_host_|. May also happen on a crash. | |
176 if (render_view_host == provisional_render_view_host_) | |
177 OnLoadAborted(); | |
178 break; | |
179 } | |
180 default: | |
181 NOTREACHED(); | |
154 } | 182 } |
155 } | 183 } |
156 | 184 |
157 void CaptivePortalTabHelper::OnRedirect(int64 frame_id, const GURL& new_url) { | 185 void CaptivePortalTabHelper::OnRedirect(int child_id, |
158 // If the main frame's not currently loading, or the redirect is for some | 186 ResourceType::Type resource_type, |
159 // other frame, ignore the redirect. It's unclear if |frame_id| can ever be | 187 const GURL& new_url) { |
160 // -1 ("invalid/unknown"), but best to be careful. | 188 // Only main frame redirects for the provisional RenderViewHost matter. |
161 if (provisional_main_frame_id_ == -1 || | 189 if (resource_type != ResourceType::MAIN_FRAME || |
162 provisional_main_frame_id_ != frame_id) { | 190 !provisional_render_view_host_ || |
191 provisional_render_view_host_->GetProcess()->GetID() != child_id) { | |
163 return; | 192 return; |
164 } | 193 } |
165 | 194 |
166 tab_reloader_->OnRedirect(new_url.SchemeIsSecure()); | 195 tab_reloader_->OnRedirect(new_url.SchemeIsSecure()); |
167 } | 196 } |
168 | 197 |
169 void CaptivePortalTabHelper::OnCaptivePortalResults(Result previous_result, | 198 void CaptivePortalTabHelper::OnCaptivePortalResults(Result previous_result, |
170 Result result) { | 199 Result result) { |
171 tab_reloader_->OnCaptivePortalResults(previous_result, result); | 200 tab_reloader_->OnCaptivePortalResults(previous_result, result); |
172 login_detector_->OnCaptivePortalResults(previous_result, result); | 201 login_detector_->OnCaptivePortalResults(previous_result, result); |
173 } | 202 } |
174 | 203 |
204 void CaptivePortalTabHelper::OnLoadAborted() { | |
205 // No further messages for the cancelled navigation will occur. | |
206 provisional_render_view_host_ = NULL; | |
207 // May have been aborting the load of an error page. | |
208 pending_error_code_ = net::OK; | |
209 | |
210 tab_reloader_->OnAbort(); | |
211 } | |
212 | |
175 bool CaptivePortalTabHelper::IsLoginTab() const { | 213 bool CaptivePortalTabHelper::IsLoginTab() const { |
cbentzel
2012/08/16 19:15:05
Nit: This doesn't match ordering in header.
mmenke
2012/08/16 19:18:34
Done.
| |
176 return login_detector_->is_login_tab(); | 214 return login_detector_->is_login_tab(); |
177 } | 215 } |
178 | 216 |
179 void CaptivePortalTabHelper::SetIsLoginTab() { | 217 void CaptivePortalTabHelper::SetIsLoginTab() { |
180 login_detector_->set_is_login_tab(); | 218 login_detector_->set_is_login_tab(); |
181 } | 219 } |
182 | 220 |
183 void CaptivePortalTabHelper::SetTabReloaderForTest( | 221 void CaptivePortalTabHelper::SetTabReloaderForTest( |
184 CaptivePortalTabReloader* tab_reloader) { | 222 CaptivePortalTabReloader* tab_reloader) { |
185 tab_reloader_.reset(tab_reloader); | 223 tab_reloader_.reset(tab_reloader); |
(...skipping 22 matching lines...) Expand all Loading... | |
208 // Otherwise, open a login tab. Only end up here when a captive portal result | 246 // Otherwise, open a login tab. Only end up here when a captive portal result |
209 // was received, so it's safe to assume |profile_| has a CaptivePortalService. | 247 // was received, so it's safe to assume |profile_| has a CaptivePortalService. |
210 TabContents* tab_contents = chrome::AddSelectedTabWithURL( | 248 TabContents* tab_contents = chrome::AddSelectedTabWithURL( |
211 browser, | 249 browser, |
212 CaptivePortalServiceFactory::GetForProfile(profile_)->test_url(), | 250 CaptivePortalServiceFactory::GetForProfile(profile_)->test_url(), |
213 content::PAGE_TRANSITION_TYPED); | 251 content::PAGE_TRANSITION_TYPED); |
214 tab_contents->captive_portal_tab_helper()->SetIsLoginTab(); | 252 tab_contents->captive_portal_tab_helper()->SetIsLoginTab(); |
215 } | 253 } |
216 | 254 |
217 } // namespace captive_portal | 255 } // namespace captive_portal |
OLD | NEW |