Home | History | Annotate | Download | only in renderer_host
      1 // Copyright (c) 2011 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_handler.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/logging.h"
     10 #include "base/memory/singleton.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/string_util.h"
     13 #include "chrome/browser/chromeos/network_state_notifier.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/browser/browser_thread.h"
     18 #include "content/browser/renderer_host/resource_dispatcher_host.h"
     19 #include "content/browser/renderer_host/resource_dispatcher_host_request_info.h"
     20 #include "net/base/net_errors.h"
     21 #include "net/url_request/url_request.h"
     22 #include "net/url_request/url_request_context.h"
     23 
     24 OfflineResourceHandler::OfflineResourceHandler(
     25     ResourceHandler* handler,
     26     int host_id,
     27     int route_id,
     28     ResourceDispatcherHost* rdh,
     29     net::URLRequest* request)
     30     : next_handler_(handler),
     31       process_host_id_(host_id),
     32       render_view_id_(route_id),
     33       rdh_(rdh),
     34       request_(request),
     35       deferred_request_id_(-1) {
     36 }
     37 
     38 OfflineResourceHandler::~OfflineResourceHandler() {
     39   DCHECK(!appcache_completion_callback_.get());
     40 }
     41 
     42 bool OfflineResourceHandler::OnUploadProgress(int request_id,
     43                                                uint64 position,
     44                                                uint64 size) {
     45   return next_handler_->OnUploadProgress(request_id, position, size);
     46 }
     47 
     48 bool OfflineResourceHandler::OnRequestRedirected(int request_id,
     49                                                  const GURL& new_url,
     50                                                  ResourceResponse* response,
     51                                                  bool* defer) {
     52   return next_handler_->OnRequestRedirected(
     53       request_id, new_url, response, defer);
     54 }
     55 
     56 bool OfflineResourceHandler::OnResponseStarted(int request_id,
     57                                                 ResourceResponse* response) {
     58   return next_handler_->OnResponseStarted(request_id, response);
     59 }
     60 
     61 bool OfflineResourceHandler::OnResponseCompleted(
     62     int request_id,
     63     const net::URLRequestStatus& status,
     64     const std::string& security_info) {
     65   return next_handler_->OnResponseCompleted(request_id, status, security_info);
     66 }
     67 
     68 void OfflineResourceHandler::OnRequestClosed() {
     69   if (appcache_completion_callback_) {
     70     appcache_completion_callback_->Cancel();
     71     appcache_completion_callback_.release();
     72     Release();  // Balanced with OnWillStart
     73   }
     74   next_handler_->OnRequestClosed();
     75 }
     76 
     77 void OfflineResourceHandler::OnCanHandleOfflineComplete(int rv) {
     78   CHECK(appcache_completion_callback_);
     79   appcache_completion_callback_ = NULL;
     80   if (deferred_request_id_ == -1) {
     81     LOG(WARNING) << "OnCanHandleOfflineComplete called after completion: "
     82                  << " this=" << this;
     83     NOTREACHED();
     84     return;
     85   }
     86   if (rv == net::OK) {
     87     Resume();
     88     Release();  // Balanced with OnWillStart
     89   } else {
     90     // Skipping AddRef/Release because they're redundant.
     91     BrowserThread::PostTask(
     92         BrowserThread::UI, FROM_HERE,
     93         NewRunnableMethod(this, &OfflineResourceHandler::ShowOfflinePage));
     94   }
     95 }
     96 
     97 bool OfflineResourceHandler::OnWillStart(int request_id,
     98                                          const GURL& url,
     99                                          bool* defer) {
    100   if (ShouldShowOfflinePage(url)) {
    101     deferred_request_id_ = request_id;
    102     deferred_url_ = url;
    103     DVLOG(1) << "OnWillStart: this=" << this << ", request id=" << request_id
    104              << ", url=" << url;
    105     AddRef();  //  Balanced with OnCanHandleOfflineComplete
    106     DCHECK(!appcache_completion_callback_);
    107     appcache_completion_callback_ =
    108         new net::CancelableCompletionCallback<OfflineResourceHandler>(
    109             this, &OfflineResourceHandler::OnCanHandleOfflineComplete);
    110     ChromeURLRequestContext* url_request_context =
    111         static_cast<ChromeURLRequestContext*>(request_->context());
    112     url_request_context->appcache_service()->CanHandleMainResourceOffline(
    113         url, appcache_completion_callback_);
    114 
    115     *defer = true;
    116     return true;
    117   }
    118   return next_handler_->OnWillStart(request_id, url, defer);
    119 }
    120 
    121 // We'll let the original event handler provide a buffer, and reuse it for
    122 // subsequent reads until we're done buffering.
    123 bool OfflineResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
    124                                          int* buf_size, int min_size) {
    125   return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
    126 }
    127 
    128 bool OfflineResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
    129   return next_handler_->OnReadCompleted(request_id, bytes_read);
    130 }
    131 
    132 void OfflineResourceHandler::OnBlockingPageComplete(bool proceed) {
    133   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
    134     BrowserThread::PostTask(
    135         BrowserThread::IO, FROM_HERE,
    136         NewRunnableMethod(this,
    137                           &OfflineResourceHandler::OnBlockingPageComplete,
    138                           proceed));
    139     return;
    140   }
    141   if (deferred_request_id_ == -1) {
    142     LOG(WARNING) << "OnBlockingPageComplete called after completion: "
    143                  << " this=" << this;
    144     NOTREACHED();
    145     return;
    146   }
    147   if (proceed) {
    148     Resume();
    149   } else {
    150     int request_id = deferred_request_id_;
    151     ClearRequestInfo();
    152     rdh_->CancelRequest(process_host_id_, request_id, false);
    153   }
    154   Release();  // Balanced with OnWillStart
    155 }
    156 
    157 void OfflineResourceHandler::ClearRequestInfo() {
    158   deferred_url_ = GURL();
    159   deferred_request_id_ = -1;
    160 }
    161 
    162 bool OfflineResourceHandler::IsRemote(const GURL& url) const {
    163   return url.SchemeIs(chrome::kFtpScheme) ||
    164          url.SchemeIs(chrome::kHttpScheme) ||
    165          url.SchemeIs(chrome::kHttpsScheme);
    166 }
    167 
    168 bool OfflineResourceHandler::ShouldShowOfflinePage(const GURL& url) const {
    169   // Only check main frame. If the network is disconnected while
    170   // loading other resources, we'll simply show broken link/images.
    171   return IsRemote(url) &&
    172       !chromeos::NetworkStateNotifier::is_connected() &&
    173       ResourceDispatcherHost::InfoForRequest(request_)->resource_type()
    174         == ResourceType::MAIN_FRAME;
    175 }
    176 
    177 void OfflineResourceHandler::Resume() {
    178   const GURL url = deferred_url_;
    179   int request_id = deferred_request_id_;
    180   ClearRequestInfo();
    181 
    182   bool defer = false;
    183   DVLOG(1) << "Resume load: this=" << this << ", request id=" << request_id;
    184   next_handler_->OnWillStart(request_id, url, &defer);
    185   if (!defer)
    186     rdh_->StartDeferredRequest(process_host_id_, request_id);
    187 }
    188 
    189 void OfflineResourceHandler::ShowOfflinePage() {
    190   chromeos::OfflineLoadPage::Show(
    191       process_host_id_, render_view_id_, deferred_url_, this);
    192 }
    193