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

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

Issue 10020051: Open a login tab on captive portal detection on SSL loads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Update comments Created 8 years, 6 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
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/captive_portal/captive_portal_tab_reloader.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop.h"
9 #include "chrome/browser/captive_portal/captive_portal_service.h"
10 #include "chrome/browser/captive_portal/captive_portal_service_factory.h"
11 #include "chrome/browser/captive_portal/captive_portal_tab_helper.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_finder.h"
14 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
15 #include "chrome/common/chrome_notification_types.h"
16 #include "content/public/browser/navigation_controller.h"
17 #include "content/public/browser/navigation_entry.h"
18 #include "content/public/browser/web_contents.h"
19 #include "net/base/net_errors.h"
20
21 namespace captive_portal {
22
23 namespace {
24
25 // The time to wait for a slow loading SSL page before triggering a captive
26 // portal check.
27 const int kDefaultSlowSSLTimeSeconds = 30;
28
29 } // namespace
30
31 CaptivePortalTabReloader::CaptivePortalTabReloader(
32 Profile* profile,
33 content::WebContents* web_contents)
34 : profile_(profile),
35 web_contents_(web_contents),
36 state_(STATE_NONE),
37 provisional_main_frame_load_(false),
38 slow_ssl_load_time_(
39 base::TimeDelta::FromSeconds(kDefaultSlowSSLTimeSeconds)),
40 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
41 }
42
43 CaptivePortalTabReloader::~CaptivePortalTabReloader() {
44 }
45
46 void CaptivePortalTabReloader::OnLoadStart(bool is_ssl) {
47 provisional_main_frame_load_ = true;
48
49 SetState(STATE_NONE);
50
51 // Start the slow load timer for SSL pages.
52 // TODO(mmenke): Should this look at the port instead? The reason the
53 // request never connects is because of the port, not the
54 // protocol.
55 if (is_ssl)
56 SetState(STATE_TIMER_RUNNING);
57 }
58
59 void CaptivePortalTabReloader::OnLoadCommitted(int net_error) {
60 provisional_main_frame_load_ = false;
61
62 if (state_ == STATE_NONE)
63 return;
64
65 // If there's no timeout error, reset the state.
66 if (net_error != net::ERR_CONNECTION_TIMED_OUT) {
67 // TODO(mmenke): If the new URL is the same as the old broken URL, and the
68 // request succeeds, should probably trigger another
69 // captive portal check.
70 SetState(STATE_NONE);
71 return;
72 }
73
74 // The page timed out before the timer triggered. This is not terribly
75 // likely, but if it does happen, the tab may have been broken by a captive
76 // portal. Go ahead and try to detect a portal now, rather than waiting for
77 // the timer.
78 if (state_ == STATE_TIMER_RUNNING) {
79 OnSlowSSLConnect();
80 return;
81 }
82
83 // If the tab needs to reload, do so asynchronously, to avoid reentrancy
84 // issues.
85 if (state_ == STATE_NEEDS_RELOAD) {
86 MessageLoop::current()->PostTask(
87 FROM_HERE,
88 base::Bind(&CaptivePortalTabReloader::ReloadTabIfNeeded,
89 weak_factory_.GetWeakPtr()));
90 }
91 }
92
93 void CaptivePortalTabReloader::OnAbort() {
94 provisional_main_frame_load_ = false;
95 SetState(STATE_NONE);
96 }
97
98 void CaptivePortalTabReloader::OnCaptivePortalResults(
99 Result previous_result,
100 Result result) {
101 if (result == RESULT_BEHIND_CAPTIVE_PORTAL) {
102 if (state_ == STATE_MAYBE_BROKEN_BY_PORTAL) {
103 SetState(STATE_BROKEN_BY_PORTAL);
104 MaybeOpenCaptivePortalLoginTab();
105 }
106 return;
107 }
108
109 switch (state_) {
110 case STATE_MAYBE_BROKEN_BY_PORTAL:
111 case STATE_TIMER_RUNNING:
112 // If the previous result was BEHIND_CAPTIVE_PORTAL, and the state is
113 // either STATE_MAYBE_BROKEN_BY_PORTAL or STATE_TIMER_RUNNING, reload the
114 // tab. In the latter case, the tab has yet to commit, but is an SSL
115 // page, so if the page ends up at a timeout error, it will be reloaded.
116 // If not, the state will just be reset. The helps in the case that a
117 // user tries to reload a tab, and then quickly logs in.
118 if (previous_result == RESULT_BEHIND_CAPTIVE_PORTAL) {
119 SetState(STATE_NEEDS_RELOAD);
120 return;
121 }
122 SetState(STATE_NONE);
123 return;
124
125 case STATE_BROKEN_BY_PORTAL:
126 // Either reload the tab now, if a connection timed out error page has
127 // already been committed, or reload it if and when a timeout commits.
128 SetState(STATE_NEEDS_RELOAD);
129 return;
130
131 case STATE_NEEDS_RELOAD:
132 case STATE_NONE:
133 // If the tab needs to reload or is in STATE_NONE, do nothing. The reload
134 // case shouldn't be very common, since it only lasts until a tab times
135 // out, but it's still possible.
136 return;
137
138 default:
139 NOTREACHED();
140 }
141 }
142
143 void CaptivePortalTabReloader::OnSlowSSLConnect() {
144 SetState(STATE_MAYBE_BROKEN_BY_PORTAL);
145 }
146
147 void CaptivePortalTabReloader::SetState(State new_state) {
148 // Stop the timer even when old and new states are the same.
149 if (state_ == STATE_TIMER_RUNNING) {
150 slow_ssl_load_timer_.Stop();
151 } else {
152 DCHECK(!slow_ssl_load_timer_.IsRunning());
153 }
154
155 // Check for unexpected state transitions.
156 switch (state_) {
157 case STATE_NONE:
158 DCHECK(new_state == STATE_NONE ||
159 new_state == STATE_TIMER_RUNNING);
160 break;
161 case STATE_TIMER_RUNNING:
162 DCHECK(new_state == STATE_NONE ||
163 new_state == STATE_MAYBE_BROKEN_BY_PORTAL ||
164 new_state == STATE_NEEDS_RELOAD);
165 break;
166 case STATE_MAYBE_BROKEN_BY_PORTAL:
167 DCHECK(new_state == STATE_NONE ||
168 new_state == STATE_BROKEN_BY_PORTAL ||
169 new_state == STATE_NEEDS_RELOAD);
170 break;
171 case STATE_BROKEN_BY_PORTAL:
172 DCHECK(new_state == STATE_NONE ||
173 new_state == STATE_NEEDS_RELOAD);
174 break;
175 case STATE_NEEDS_RELOAD:
176 DCHECK_EQ(STATE_NONE, new_state);
177 break;
178 default:
179 NOTREACHED();
180 break;
181 };
182
183 state_ = new_state;
184
185 switch (state_) {
186 case STATE_TIMER_RUNNING:
187 slow_ssl_load_timer_.Start(
188 FROM_HERE,
189 slow_ssl_load_time_,
190 this,
191 &CaptivePortalTabReloader::OnSlowSSLConnect);
192 break;
193
194 case STATE_MAYBE_BROKEN_BY_PORTAL:
195 CheckForCaptivePortal();
196 break;
197
198 case STATE_NEEDS_RELOAD:
199 // Try to reload the tab now.
200 ReloadTabIfNeeded();
201 break;
202
203 default:
204 break;
205 }
206 }
207
208 void CaptivePortalTabReloader::ReloadTabIfNeeded() {
209 // If there's still a provisional load going, or the page no longer needs
210 // to be reloaded, due to a new navigation, do nothing.
211 if (state_ != STATE_NEEDS_RELOAD || provisional_main_frame_load_)
212 return;
213 SetState(STATE_NONE);
214 ReloadTab();
215 }
216
217 void CaptivePortalTabReloader::ReloadTab() {
218 content::NavigationController* controller = &web_contents_->GetController();
219 if (!controller->GetActiveEntry()->GetHasPostData())
220 controller->Reload(true);
221 }
222
223 void CaptivePortalTabReloader::MaybeOpenCaptivePortalLoginTab() {
cbentzel 2012/05/30 16:26:42 Should this be done by passing a callback in, rath
mmenke 2012/05/30 17:46:25 Done. I like getting rid of the circular dependen
224 Browser* browser = browser::FindTabbedBrowser(profile_, true);
225 // If the Profile doesn't have a tabbed browser window open, do nothing.
226 if (!browser)
227 return;
228
229 // Check if the Profile's topmost browser window already has a login tab.
230 // If so, do nothing.
231 // TODO(mmenke): Consider focusing that tab, at least if this is the tab
232 // helper for the currently active tab for the profile.
233 for (int i = 0; i < browser->tab_count(); ++i) {
234 TabContentsWrapper* tab_contents_wrapper =
235 browser->GetTabContentsWrapperAt(i);
236 if (tab_contents_wrapper->captive_portal_tab_helper()->IsLoginTab())
237 return;
238 }
239
240 // Otherwise, open a login tab. Only end up here when a captive portal result
241 // was received, so it's safe to assume |profile_| has a CaptivePortalService.
242 TabContentsWrapper* tab_contents_wrapper =
243 browser->AddSelectedTabWithURL(
244 CaptivePortalServiceFactory::GetForProfile(profile_)->test_url(),
245 content::PAGE_TRANSITION_TYPED);
246 tab_contents_wrapper->captive_portal_tab_helper()->SetIsLoginTab();
247 }
248
249 void CaptivePortalTabReloader::CheckForCaptivePortal() {
250 CaptivePortalService* service =
251 CaptivePortalServiceFactory::GetForProfile(profile_);
252 if (service)
253 service->DetectCaptivePortal();
254 }
255
256 } // namespace captive_portal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698