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

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

Powered by Google App Engine
This is Rietveld 408576698