root/chrome/browser/renderer_host/offline_resource_throttle.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ShowOfflinePage
  2. appcache_service_
  3. WillStartRequest
  4. GetNameForLogging
  5. OnBlockingPageComplete
  6. IsRemote
  7. ShouldShowOfflinePage
  8. OnCanHandleOfflineComplete

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/renderer_host/offline_resource_throttle.h"

#include <vector>

#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
#include "chrome/browser/chromeos/offline/offline_load_page.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/web_contents.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/base/network_change_notifier.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "webkit/browser/appcache/appcache_service.h"

using content::BrowserThread;
using content::RenderViewHost;
using content::WebContents;

namespace {

void ShowOfflinePage(
    int render_process_id,
    int render_view_id,
    const GURL& url,
    const chromeos::OfflineLoadPage::CompletionCallback& callback) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // Check again on UI thread and proceed if it's connected.
  if (!net::NetworkChangeNotifier::IsOffline()) {
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE, base::Bind(callback, true));
  } else {
    RenderViewHost* render_view_host =
        RenderViewHost::FromID(render_process_id, render_view_id);
    WebContents* web_contents = render_view_host ?
        WebContents::FromRenderViewHost(render_view_host) : NULL;
    // There is a chance that the tab closed after we decided to show
    // the offline page on the IO thread and before we actually show the
    // offline page here on the UI thread.
    if (web_contents)
      (new chromeos::OfflineLoadPage(web_contents, url, callback))->Show();
  }
}

}  // namespace

OfflineResourceThrottle::OfflineResourceThrottle(
    net::URLRequest* request,
    appcache::AppCacheService* appcache_service)
    : request_(request),
      appcache_service_(appcache_service) {
  DCHECK(appcache_service);
}

OfflineResourceThrottle::~OfflineResourceThrottle() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  if (!appcache_completion_callback_.IsCancelled())
    appcache_completion_callback_.Cancel();
}

void OfflineResourceThrottle::WillStartRequest(bool* defer) {
  if (!ShouldShowOfflinePage(request_->url()))
    return;

  DVLOG(1) << "WillStartRequest: this=" << this << ", url=" << request_->url();

  const GURL* url = &(request_->url());
  const GURL* first_party = &(request_->first_party_for_cookies());

  // Anticipate a client-side HSTS based redirect from HTTP to HTTPS, and
  // ask the appcache about the HTTPS url instead of the HTTP url.
  GURL redirect_url;
  if (request_->GetHSTSRedirect(&redirect_url)) {
    if (url->GetOrigin() == first_party->GetOrigin())
      first_party = &redirect_url;
    url = &redirect_url;
  }

  DCHECK(appcache_completion_callback_.IsCancelled());

  appcache_completion_callback_.Reset(
      base::Bind(&OfflineResourceThrottle::OnCanHandleOfflineComplete,
                 AsWeakPtr()));
  appcache_service_->CanHandleMainResourceOffline(
      *url, *first_party,
      appcache_completion_callback_.callback());

  *defer = true;
}

const char* OfflineResourceThrottle::GetNameForLogging() const {
  return "OfflineResourceThrottle";
}

void OfflineResourceThrottle::OnBlockingPageComplete(bool proceed) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  if (proceed) {
    controller()->Resume();
  } else {
    controller()->Cancel();
  }
}

bool OfflineResourceThrottle::IsRemote(const GURL& url) const {
  return !net::IsLocalhost(url.host()) && (url.SchemeIs(content::kFtpScheme) ||
                                           url.SchemeIs(content::kHttpScheme) ||
                                           url.SchemeIs(content::kHttpsScheme));
}

bool OfflineResourceThrottle::ShouldShowOfflinePage(const GURL& url) const {
  // If the network is disconnected while loading other resources, we'll simply
  // show broken link/images.
  return IsRemote(url) && net::NetworkChangeNotifier::IsOffline();
}

void OfflineResourceThrottle::OnCanHandleOfflineComplete(int rv) {
  appcache_completion_callback_.Cancel();

  if (rv == net::OK) {
    controller()->Resume();
  } else {
    const content::ResourceRequestInfo* info =
        content::ResourceRequestInfo::ForRequest(request_);
    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        base::Bind(
            &ShowOfflinePage,
            info->GetChildID(),
            info->GetRouteID(),
            request_->url(),
            base::Bind(
                &OfflineResourceThrottle::OnBlockingPageComplete,
                AsWeakPtr())));
  }
}

/* [<][>][^][v][top][bottom][index][help] */