offline_resource_handler.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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/metrics/histogram.h"
11#include "base/singleton.h"
12#include "base/string_util.h"
13#include "chrome/browser/browser_thread.h"
14#include "chrome/browser/chromeos/network_state_notifier.h"
15#include "chrome/browser/chromeos/offline/offline_load_page.h"
16#include "chrome/browser/chromeos/offline/offline_load_service.h"
17#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
18#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
19#include "chrome/common/url_constants.h"
20
21OfflineResourceHandler::OfflineResourceHandler(
22    ResourceHandler* handler,
23    int host_id,
24    int route_id,
25    ResourceDispatcherHost* rdh,
26    net::URLRequest* request)
27    : next_handler_(handler),
28      process_host_id_(host_id),
29      render_view_id_(route_id),
30      rdh_(rdh),
31      request_(request),
32      deferred_request_id_(-1) {
33}
34
35bool OfflineResourceHandler::OnUploadProgress(int request_id,
36                                               uint64 position,
37                                               uint64 size) {
38  return next_handler_->OnUploadProgress(request_id, position, size);
39}
40
41bool OfflineResourceHandler::OnRequestRedirected(int request_id,
42                                                 const GURL& new_url,
43                                                 ResourceResponse* response,
44                                                 bool* defer) {
45  return next_handler_->OnRequestRedirected(
46      request_id, new_url, response, defer);
47}
48
49bool OfflineResourceHandler::OnResponseStarted(int request_id,
50                                                ResourceResponse* response) {
51  return next_handler_->OnResponseStarted(request_id, response);
52}
53
54bool OfflineResourceHandler::OnResponseCompleted(
55    int request_id,
56    const URLRequestStatus& status,
57    const std::string& security_info) {
58  return next_handler_->OnResponseCompleted(request_id, status, security_info);
59}
60
61void OfflineResourceHandler::OnRequestClosed() {
62  next_handler_->OnRequestClosed();
63}
64
65bool OfflineResourceHandler::OnWillStart(int request_id,
66                                         const GURL& url,
67                                         bool* defer) {
68  if (ShouldShowOfflinePage(url)) {
69    deferred_request_id_ = request_id;
70    deferred_url_ = url;
71    DVLOG(1) << "WillStart: this=" << this << ", request id=" << request_id;
72    AddRef();  //  Balanced with OnBlockingPageComplete
73    BrowserThread::PostTask(
74        BrowserThread::UI, FROM_HERE,
75        NewRunnableMethod(this, &OfflineResourceHandler::ShowOfflinePage));
76    *defer = true;
77    return true;
78  }
79  return next_handler_->OnWillStart(request_id, url, defer);
80}
81
82// We'll let the original event handler provide a buffer, and reuse it for
83// subsequent reads until we're done buffering.
84bool OfflineResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
85                                         int* buf_size, int min_size) {
86  return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
87}
88
89bool OfflineResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
90  return next_handler_->OnReadCompleted(request_id, bytes_read);
91}
92
93void OfflineResourceHandler::OnBlockingPageComplete(bool proceed) {
94  if (deferred_request_id_ < 0) {
95    LOG(WARNING) << "OnBlockingPageComplete called after completion: "
96                 << " this=" << this << ", request_id="
97                 << deferred_request_id_;
98    NOTREACHED();
99    return;
100  }
101  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
102    BrowserThread::PostTask(
103        BrowserThread::IO, FROM_HERE,
104        NewRunnableMethod(this,
105                          &OfflineResourceHandler::OnBlockingPageComplete,
106                          proceed));
107    return;
108  }
109  if (proceed) {
110    Resume();
111  } else {
112    int request_id = deferred_request_id_;
113    ClearRequestInfo();
114    rdh_->CancelRequest(process_host_id_, request_id, false);
115  }
116  Release();  // Balanced with OnWillStart
117}
118
119void OfflineResourceHandler::ClearRequestInfo() {
120  deferred_url_ = GURL();
121  deferred_request_id_ = -1;
122}
123
124bool OfflineResourceHandler::IsRemote(const GURL& url) const {
125  return url.SchemeIs(chrome::kFtpScheme) ||
126         url.SchemeIs(chrome::kHttpScheme) ||
127         url.SchemeIs(chrome::kHttpsScheme);
128}
129
130bool OfflineResourceHandler::ShouldShowOfflinePage(const GURL& url) const {
131  // Only check main frame. If the network is disconnected while
132  // loading other resources, we'll simply show broken link/images.
133  return IsRemote(url) &&
134      !chromeos::NetworkStateNotifier::is_connected() &&
135      ResourceDispatcherHost::InfoForRequest(request_)->resource_type()
136          == ResourceType::MAIN_FRAME &&
137      !chromeos::OfflineLoadService::Get()->ShouldProceed(
138          process_host_id_, render_view_id_, url);
139}
140
141void OfflineResourceHandler::Resume() {
142  const GURL url = deferred_url_;
143  int request_id = deferred_request_id_;
144  ClearRequestInfo();
145
146  chromeos::OfflineLoadService::Get()->Proceeded(
147      process_host_id_, render_view_id_, url);
148
149  DCHECK_NE(request_id, -1);
150  bool defer = false;
151  DVLOG(1) << "Resume load: this=" << this << ", request id=" << request_id;
152  next_handler_->OnWillStart(request_id, url, &defer);
153  if (!defer)
154    rdh_->StartDeferredRequest(process_host_id_, request_id);
155}
156
157void OfflineResourceHandler::ShowOfflinePage() {
158  chromeos::OfflineLoadPage::Show(
159      process_host_id_, render_view_id_, deferred_url_, this);
160}
161