Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(309)

Side by Side Diff: chrome/browser/captive_portal/captive_portal_tab_helper.cc

Issue 10837146: Fix how captive portals track which page is loading. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: sync Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 error page loads in a
cbentzel 2012/08/15 17:00:38 "Link Doctor pages act like error page loads in a
mmenke 2012/08/16 14:30:03 Correct. "two" added
71 // row. The second time, provisional_render_view_host_ will be NULL.
cbentzel 2012/08/15 17:00:38 Why will provisional_render_view_host_ be NULL? Wi
mmenke 2012/08/16 14:30:03 It's: - provisional load - provisional load fails
72 if (is_error_page && provisional_render_view_host_ == render_view_host)
73 return;
74 // Otherwise, abort the old load.
75 tab_reloader_->OnAbort();
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 tab_reloader_->OnAbort();
91 103
92 tab_reloader_->OnLoadCommitted(pending_error_code_); 104 // Send information about the new load.
cbentzel 2012/08/15 17:00:38 Why do you need to do this? Just for stats?
mmenke 2012/08/16 14:30:03 To make TabReloader's interface a bit better defin
cbentzel 2012/08/16 19:15:04 I think this is fine.
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) {
129 // No further messages for the cancelled navigation will occur.
130 provisional_render_view_host_ = NULL;
114 // May have been aborting the load of an error page. 131 // May have been aborting the load of an error page.
115 pending_error_code_ = net::OK; 132 pending_error_code_ = net::OK;
116 133
117 tab_reloader_->OnAbort(); 134 tab_reloader_->OnAbort();
118 return; 135 return;
119 } 136 }
120 137
121 pending_error_code_ = error_code; 138 pending_error_code_ = error_code;
122 } 139 }
123 140
124 void CaptivePortalTabHelper::DidStopLoading( 141 void CaptivePortalTabHelper::DidStopLoading(
125 content::RenderViewHost* render_view_host) { 142 content::RenderViewHost* render_view_host) {
126 DCHECK(CalledOnValidThread()); 143 DCHECK(CalledOnValidThread());
127 144
128 login_detector_->OnStoppedLoading(); 145 login_detector_->OnStoppedLoading();
129 } 146 }
130 147
131 void CaptivePortalTabHelper::Observe( 148 void CaptivePortalTabHelper::Observe(
132 int type, 149 int type,
133 const content::NotificationSource& source, 150 const content::NotificationSource& source,
134 const content::NotificationDetails& details) { 151 const content::NotificationDetails& details) {
135 DCHECK(CalledOnValidThread()); 152 DCHECK(CalledOnValidThread());
136 if (type == content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT) { 153 switch (type) {
137 DCHECK_EQ(web_contents(), 154 case content::NOTIFICATION_RESOURCE_RECEIVED_REDIRECT: {
138 content::Source<content::WebContents>(source).ptr()); 155 DCHECK_EQ(web_contents(),
156 content::Source<content::WebContents>(source).ptr());
139 157
140 const content::ResourceRedirectDetails* redirect_details = 158 const content::ResourceRedirectDetails* redirect_details =
141 content::Details<content::ResourceRedirectDetails>(details).ptr(); 159 content::Details<content::ResourceRedirectDetails>(details).ptr();
142 160
143 if (redirect_details->resource_type == ResourceType::MAIN_FRAME) 161 OnRedirect(redirect_details->origin_child_id,
144 OnRedirect(redirect_details->frame_id, redirect_details->new_url); 162 redirect_details->resource_type,
145 } else if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) { 163 redirect_details->new_url);
146 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr()); 164 break;
165 }
166 case chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT: {
167 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr());
147 168
148 const CaptivePortalService::Results* results = 169 const CaptivePortalService::Results* results =
149 content::Details<CaptivePortalService::Results>(details).ptr(); 170 content::Details<CaptivePortalService::Results>(details).ptr();
150 171
151 OnCaptivePortalResults(results->previous_result, results->result); 172 OnCaptivePortalResults(results->previous_result, results->result);
152 } else { 173 break;
153 NOTREACHED(); 174 }
175 case content::NOTIFICATION_RENDER_VIEW_HOST_DELETED: {
176 content::RenderViewHost* render_view_host =
177 content::Source<content::RenderViewHost>(source).ptr();
178 // This can happen when a cross-process navigation is aborted, either by
179 // pressing stop or by starting a new cross-process navigation that can't
180 // re-use |provisional_render_view_host_|. May also happen on a crash.
181 if (render_view_host == provisional_render_view_host_) {
182 provisional_render_view_host_ = NULL;
cbentzel 2012/08/15 17:00:38 Should you share this logic with the error_code ==
mmenke 2012/08/16 14:30:03 Done. Went ahead and used the same function for t
183 pending_error_code_ = net::OK;
184 tab_reloader_->OnAbort();
185 }
186 break;
187 }
188 default:
189 NOTREACHED();
154 } 190 }
155 } 191 }
156 192
157 void CaptivePortalTabHelper::OnRedirect(int64 frame_id, const GURL& new_url) { 193 void CaptivePortalTabHelper::OnRedirect(int child_id,
158 // If the main frame's not currently loading, or the redirect is for some 194 ResourceType::Type resource_type,
159 // other frame, ignore the redirect. It's unclear if |frame_id| can ever be 195 const GURL& new_url) {
160 // -1 ("invalid/unknown"), but best to be careful. 196 // Only main frame redirects for the provisional RenderViewHost matter.
161 if (provisional_main_frame_id_ == -1 || 197 if (resource_type != ResourceType::MAIN_FRAME ||
cbentzel 2012/08/15 17:00:38 Would child_id ever be -1 here?
mmenke 2012/08/16 14:30:03 Since the id is actually used to lookup the Render
162 provisional_main_frame_id_ != frame_id) { 198 child_id != GetProvisionalChildID()) {
163 return; 199 return;
164 } 200 }
165 201
166 tab_reloader_->OnRedirect(new_url.SchemeIsSecure()); 202 tab_reloader_->OnRedirect(new_url.SchemeIsSecure());
167 } 203 }
168 204
169 void CaptivePortalTabHelper::OnCaptivePortalResults(Result previous_result, 205 void CaptivePortalTabHelper::OnCaptivePortalResults(Result previous_result,
170 Result result) { 206 Result result) {
171 tab_reloader_->OnCaptivePortalResults(previous_result, result); 207 tab_reloader_->OnCaptivePortalResults(previous_result, result);
172 login_detector_->OnCaptivePortalResults(previous_result, result); 208 login_detector_->OnCaptivePortalResults(previous_result, result);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 243
208 // Otherwise, open a login tab. Only end up here when a captive portal result 244 // 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. 245 // was received, so it's safe to assume |profile_| has a CaptivePortalService.
210 TabContents* tab_contents = chrome::AddSelectedTabWithURL( 246 TabContents* tab_contents = chrome::AddSelectedTabWithURL(
211 browser, 247 browser,
212 CaptivePortalServiceFactory::GetForProfile(profile_)->test_url(), 248 CaptivePortalServiceFactory::GetForProfile(profile_)->test_url(),
213 content::PAGE_TRANSITION_TYPED); 249 content::PAGE_TRANSITION_TYPED);
214 tab_contents->captive_portal_tab_helper()->SetIsLoginTab(); 250 tab_contents->captive_portal_tab_helper()->SetIsLoginTab();
215 } 251 }
216 252
253 int CaptivePortalTabHelper::GetProvisionalChildID() const {
254 if (!provisional_render_view_host_)
255 return -1;
256 return provisional_render_view_host_->GetProcess()->GetID();
257 }
258
217 } // namespace captive_portal 259 } // namespace captive_portal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698