Home | History | Annotate | Download | only in renderer_host
      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/renderer_host/offline_resource_throttle.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/logging.h"
     11 #include "base/memory/singleton.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/strings/string_util.h"
     14 #include "chrome/browser/chromeos/offline/offline_load_page.h"
     15 #include "chrome/browser/net/chrome_url_request_context.h"
     16 #include "chrome/common/url_constants.h"
     17 #include "content/public/browser/browser_thread.h"
     18 #include "content/public/browser/render_view_host.h"
     19 #include "content/public/browser/resource_controller.h"
     20 #include "content/public/browser/web_contents.h"
     21 #include "net/base/net_errors.h"
     22 #include "net/base/net_util.h"
     23 #include "net/base/network_change_notifier.h"
     24 #include "net/url_request/url_request.h"
     25 #include "net/url_request/url_request_context.h"
     26 #include "webkit/browser/appcache/appcache_service.h"
     27 
     28 using content::BrowserThread;
     29 using content::RenderViewHost;
     30 using content::WebContents;
     31 
     32 namespace {
     33 
     34 void ShowOfflinePage(
     35     int render_process_id,
     36     int render_view_id,
     37     const GURL& url,
     38     const chromeos::OfflineLoadPage::CompletionCallback& callback) {
     39   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     40 
     41   // Check again on UI thread and proceed if it's connected.
     42   if (!net::NetworkChangeNotifier::IsOffline()) {
     43     BrowserThread::PostTask(
     44         BrowserThread::IO, FROM_HERE, base::Bind(callback, true));
     45   } else {
     46     RenderViewHost* render_view_host =
     47         RenderViewHost::FromID(render_process_id, render_view_id);
     48     WebContents* web_contents = render_view_host ?
     49         WebContents::FromRenderViewHost(render_view_host) : NULL;
     50     // There is a chance that the tab closed after we decided to show
     51     // the offline page on the IO thread and before we actually show the
     52     // offline page here on the UI thread.
     53     if (web_contents)
     54       (new chromeos::OfflineLoadPage(web_contents, url, callback))->Show();
     55   }
     56 }
     57 
     58 }  // namespace
     59 
     60 OfflineResourceThrottle::OfflineResourceThrottle(
     61     int render_process_id,
     62     int render_view_id,
     63     net::URLRequest* request,
     64     appcache::AppCacheService* appcache_service)
     65     : render_process_id_(render_process_id),
     66       render_view_id_(render_view_id),
     67       request_(request),
     68       appcache_service_(appcache_service) {
     69   DCHECK(appcache_service);
     70 }
     71 
     72 OfflineResourceThrottle::~OfflineResourceThrottle() {
     73   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     74 
     75   if (!appcache_completion_callback_.IsCancelled())
     76     appcache_completion_callback_.Cancel();
     77 }
     78 
     79 void OfflineResourceThrottle::WillStartRequest(bool* defer) {
     80   if (!ShouldShowOfflinePage(request_->url()))
     81     return;
     82 
     83   DVLOG(1) << "WillStartRequest: this=" << this << ", url=" << request_->url();
     84 
     85   const GURL* url = &(request_->url());
     86   const GURL* first_party = &(request_->first_party_for_cookies());
     87 
     88   // Anticipate a client-side HSTS based redirect from HTTP to HTTPS, and
     89   // ask the appcache about the HTTPS url instead of the HTTP url.
     90   GURL redirect_url;
     91   if (request_->GetHSTSRedirect(&redirect_url)) {
     92     if (url->GetOrigin() == first_party->GetOrigin())
     93       first_party = &redirect_url;
     94     url = &redirect_url;
     95   }
     96 
     97   DCHECK(appcache_completion_callback_.IsCancelled());
     98 
     99   appcache_completion_callback_.Reset(
    100       base::Bind(&OfflineResourceThrottle::OnCanHandleOfflineComplete,
    101                  AsWeakPtr()));
    102   appcache_service_->CanHandleMainResourceOffline(
    103       *url, *first_party,
    104       appcache_completion_callback_.callback());
    105 
    106   *defer = true;
    107 }
    108 
    109 void OfflineResourceThrottle::OnBlockingPageComplete(bool proceed) {
    110   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    111 
    112   if (proceed) {
    113     controller()->Resume();
    114   } else {
    115     controller()->Cancel();
    116   }
    117 }
    118 
    119 bool OfflineResourceThrottle::IsRemote(const GURL& url) const {
    120   return !net::IsLocalhost(url.host()) &&
    121     (url.SchemeIs(chrome::kFtpScheme) ||
    122      url.SchemeIs(chrome::kHttpScheme) ||
    123      url.SchemeIs(chrome::kHttpsScheme));
    124 }
    125 
    126 bool OfflineResourceThrottle::ShouldShowOfflinePage(const GURL& url) const {
    127   // If the network is disconnected while loading other resources, we'll simply
    128   // show broken link/images.
    129   return IsRemote(url) && net::NetworkChangeNotifier::IsOffline();
    130 }
    131 
    132 void OfflineResourceThrottle::OnCanHandleOfflineComplete(int rv) {
    133   appcache_completion_callback_.Cancel();
    134 
    135   if (rv == net::OK) {
    136     controller()->Resume();
    137   } else {
    138     BrowserThread::PostTask(
    139         BrowserThread::UI,
    140         FROM_HERE,
    141         base::Bind(
    142             &ShowOfflinePage,
    143             render_process_id_,
    144             render_view_id_,
    145             request_->url(),
    146             base::Bind(
    147                 &OfflineResourceThrottle::OnBlockingPageComplete,
    148                 AsWeakPtr())));
    149   }
    150 }
    151