15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/captive_portal/captive_portal_tab_reloader.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
99ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/captive_portal/captive_portal_service.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/captive_portal/captive_portal_service_factory.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/interstitial_page.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_controller.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/navigation_entry.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing captive_portal::CaptivePortalResult;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The time to wait for a slow loading SSL page before triggering a captive
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// portal check.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDefaultSlowSSLTimeSeconds = 30;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if an SSL request resulting in |error| may indicate a captive
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// portal.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SslNetErrorMayImplyCaptivePortal(int error) {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // May be returned when a captive portal silently blocks an SSL request.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error == net::ERR_CONNECTION_TIMED_OUT)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // May be returned when a captive portal lets SSL requests connect, but
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // disconnects Chrome after Chrome starts SSL negotiation, or sends an
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // HTTP response.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error == net::ERR_SSL_PROTOCOL_ERROR)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CaptivePortalTabReloader::CaptivePortalTabReloader(
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Profile* profile,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::WebContents* web_contents,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const OpenLoginTabCallback& open_login_tab_callback)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : profile_(profile),
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      web_contents_(web_contents),
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_(STATE_NONE),
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      provisional_main_frame_load_(false),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ssl_url_in_redirect_chain_(false),
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      slow_ssl_load_time_(
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::TimeDelta::FromSeconds(kDefaultSlowSSLTimeSeconds)),
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      open_login_tab_callback_(open_login_tab_callback),
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CaptivePortalTabReloader::~CaptivePortalTabReloader() {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::OnLoadStart(bool is_ssl) {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  provisional_main_frame_load_ = true;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ssl_url_in_redirect_chain_ = is_ssl;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetState(STATE_NONE);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start the slow load timer for SSL pages.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mmenke):  Should this look at the port instead?  The reason the
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //                request never connects is because of the port, not the
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //                protocol.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_ssl)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetState(STATE_TIMER_RUNNING);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::OnLoadCommitted(int net_error) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  provisional_main_frame_load_ = false;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ssl_url_in_redirect_chain_ = false;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == STATE_NONE)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |net_error| is not an error code that could indicate there's a captive
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // portal, reset the state.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SslNetErrorMayImplyCaptivePortal(net_error)) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(mmenke):  If the new URL is the same as the old broken URL, and the
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //                request succeeds, should probably trigger another
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //                captive portal check.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetState(STATE_NONE);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The page returned an error out before the timer triggered.  Go ahead and
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // try to detect a portal now, rather than waiting for the timer.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == STATE_TIMER_RUNNING) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnSlowSSLConnect();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the tab needs to reload, do so asynchronously, to avoid reentrancy
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // issues.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == STATE_NEEDS_RELOAD) {
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&CaptivePortalTabReloader::ReloadTabIfNeeded,
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   weak_factory_.GetWeakPtr()));
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::OnAbort() {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  provisional_main_frame_load_ = false;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ssl_url_in_redirect_chain_ = false;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetState(STATE_NONE);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::OnRedirect(bool is_ssl) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetState(STATE_NONE);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_ssl)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only start the SSL timer running if no SSL URL has been seen in the current
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // redirect chain.  If we've already successfully downloaded one SSL URL,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // assume we're not behind a captive portal.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ssl_url_in_redirect_chain_)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetState(STATE_TIMER_RUNNING);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ssl_url_in_redirect_chain_ = true;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::OnCaptivePortalResults(
1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    CaptivePortalResult previous_result,
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    CaptivePortalResult result) {
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (state_ == STATE_MAYBE_BROKEN_BY_PORTAL) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetState(STATE_BROKEN_BY_PORTAL);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MaybeOpenCaptivePortalLoginTab();
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (state_) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_MAYBE_BROKEN_BY_PORTAL:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_TIMER_RUNNING:
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the previous result was BEHIND_CAPTIVE_PORTAL, and the state is
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // either STATE_MAYBE_BROKEN_BY_PORTAL or STATE_TIMER_RUNNING, reload the
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // tab.  In the latter case, the tab has yet to commit, but is an SSL
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // page, so if the page ends up at an error caused by a captive portal, it
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // will be reloaded.  If not, the state will just be reset.  The helps in
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the case that a user tries to reload a tab, and then quickly logs in.
1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (previous_result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetState(STATE_NEEDS_RELOAD);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetState(STATE_NONE);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_BROKEN_BY_PORTAL:
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Either reload the tab now, if an error page has already been committed
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // or an interstitial is being displayed, or reload it if and when a
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // timeout commits.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetState(STATE_NEEDS_RELOAD);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_NEEDS_RELOAD:
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_NONE:
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the tab needs to reload or is in STATE_NONE, do nothing.  The reload
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // case shouldn't be very common, since it only lasts until a tab times
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // out, but it's still possible.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::OnSSLCertError(const net::SSLInfo& ssl_info) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(mmenke):  Figure out if any cert errors should be ignored.  The
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // most common errors when behind captive portals are likely
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ERR_CERT_COMMON_NAME_INVALID and ERR_CERT_AUTHORITY_INVALID.  It's unclear
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if captive portals cause any others.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == STATE_TIMER_RUNNING)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetState(STATE_MAYBE_BROKEN_BY_PORTAL);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::OnSlowSSLConnect() {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetState(STATE_MAYBE_BROKEN_BY_PORTAL);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::SetState(State new_state) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stop the timer even when old and new states are the same.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == STATE_TIMER_RUNNING) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    slow_ssl_load_timer_.Stop();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!slow_ssl_load_timer_.IsRunning());
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for unexpected state transitions.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (state_) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_NONE:
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(new_state == STATE_NONE ||
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             new_state == STATE_TIMER_RUNNING);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_TIMER_RUNNING:
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(new_state == STATE_NONE ||
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             new_state == STATE_MAYBE_BROKEN_BY_PORTAL ||
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             new_state == STATE_NEEDS_RELOAD);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_MAYBE_BROKEN_BY_PORTAL:
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(new_state == STATE_NONE ||
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             new_state == STATE_BROKEN_BY_PORTAL ||
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             new_state == STATE_NEEDS_RELOAD);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_BROKEN_BY_PORTAL:
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(new_state == STATE_NONE ||
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             new_state == STATE_NEEDS_RELOAD);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_NEEDS_RELOAD:
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(STATE_NONE, new_state);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = new_state;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (state_) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_TIMER_RUNNING:
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      slow_ssl_load_timer_.Start(
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          slow_ssl_load_time_,
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          this,
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          &CaptivePortalTabReloader::OnSlowSSLConnect);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_MAYBE_BROKEN_BY_PORTAL:
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CheckForCaptivePortal();
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case STATE_NEEDS_RELOAD:
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Try to reload the tab now.
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReloadTabIfNeeded();
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::ReloadTabIfNeeded() {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the page no longer needs to be reloaded, do nothing.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != STATE_NEEDS_RELOAD)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there's still a provisional load going, do nothing unless there's an
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // interstitial page.  Reloading when displaying an interstitial page will
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reload the underlying page, even if it hasn't yet committed.
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (provisional_main_frame_load_ &&
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !content::InterstitialPage::GetInterstitialPage(web_contents_)) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetState(STATE_NONE);
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReloadTab();
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::ReloadTab() {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NavigationController* controller = &web_contents_->GetController();
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!controller->GetActiveEntry()->GetHasPostData())
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller->Reload(true);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::MaybeOpenCaptivePortalLoginTab() {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  open_login_tab_callback_.Run();
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CaptivePortalTabReloader::CheckForCaptivePortal() {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CaptivePortalService* service =
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CaptivePortalServiceFactory::GetForProfile(profile_);
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (service)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    service->DetectCaptivePortal();
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
282