• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
OfflineResourceHandler(ResourceHandler * handler,int host_id,int route_id,ResourceDispatcherHost * rdh,net::URLRequest * request)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 
~OfflineResourceHandler()38 OfflineResourceHandler::~OfflineResourceHandler() {
39   DCHECK(!appcache_completion_callback_.get());
40 }
41 
OnUploadProgress(int request_id,uint64 position,uint64 size)42 bool OfflineResourceHandler::OnUploadProgress(int request_id,
43                                                uint64 position,
44                                                uint64 size) {
45   return next_handler_->OnUploadProgress(request_id, position, size);
46 }
47 
OnRequestRedirected(int request_id,const GURL & new_url,ResourceResponse * response,bool * defer)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 
OnResponseStarted(int request_id,ResourceResponse * response)56 bool OfflineResourceHandler::OnResponseStarted(int request_id,
57                                                 ResourceResponse* response) {
58   return next_handler_->OnResponseStarted(request_id, response);
59 }
60 
OnResponseCompleted(int request_id,const net::URLRequestStatus & status,const std::string & security_info)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 
OnRequestClosed()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 
OnCanHandleOfflineComplete(int rv)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 
OnWillStart(int request_id,const GURL & url,bool * defer)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.
OnWillRead(int request_id,net::IOBuffer ** buf,int * buf_size,int min_size)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 
OnReadCompleted(int request_id,int * bytes_read)128 bool OfflineResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
129   return next_handler_->OnReadCompleted(request_id, bytes_read);
130 }
131 
OnBlockingPageComplete(bool proceed)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 
ClearRequestInfo()157 void OfflineResourceHandler::ClearRequestInfo() {
158   deferred_url_ = GURL();
159   deferred_request_id_ = -1;
160 }
161 
IsRemote(const GURL & url) const162 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 
ShouldShowOfflinePage(const GURL & url) const168 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 
Resume()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 
ShowOfflinePage()189 void OfflineResourceHandler::ShowOfflinePage() {
190   chromeos::OfflineLoadPage::Show(
191       process_host_id_, render_view_id_, deferred_url_, this);
192 }
193