• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 "content/browser/loader/detachable_resource_handler.h"
6 
7 #include "base/logging.h"
8 #include "base/time/time.h"
9 #include "content/browser/loader/resource_request_info_impl.h"
10 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h"
12 #include "net/url_request/url_request.h"
13 #include "net/url_request/url_request_status.h"
14 
15 namespace {
16 // This matches the maximum allocation size of AsyncResourceHandler.
17 const int kReadBufSize = 32 * 1024;
18 }
19 
20 namespace content {
21 
DetachableResourceHandler(net::URLRequest * request,base::TimeDelta cancel_delay,scoped_ptr<ResourceHandler> next_handler)22 DetachableResourceHandler::DetachableResourceHandler(
23     net::URLRequest* request,
24     base::TimeDelta cancel_delay,
25     scoped_ptr<ResourceHandler> next_handler)
26     : ResourceHandler(request),
27       next_handler_(next_handler.Pass()),
28       cancel_delay_(cancel_delay),
29       is_deferred_(false),
30       is_finished_(false) {
31   GetRequestInfo()->set_detachable_handler(this);
32 }
33 
~DetachableResourceHandler()34 DetachableResourceHandler::~DetachableResourceHandler() {
35   // Cleanup back-pointer stored on the request info.
36   GetRequestInfo()->set_detachable_handler(NULL);
37 }
38 
Detach()39 void DetachableResourceHandler::Detach() {
40   if (is_detached())
41     return;
42 
43   if (!is_finished_) {
44     // Simulate a cancel on the next handler before destroying it.
45     net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
46                                  net::ERR_ABORTED);
47     bool defer_ignored = false;
48     next_handler_->OnResponseCompleted(status, std::string(), &defer_ignored);
49     DCHECK(!defer_ignored);
50     // If |next_handler_| were to defer its shutdown in OnResponseCompleted,
51     // this would destroy it anyway. Fortunately, AsyncResourceHandler never
52     // does this anyway, so DCHECK it. BufferedResourceHandler and RVH shutdown
53     // already ignore deferred ResourceHandler shutdown, but
54     // DetachableResourceHandler and the detach-on-renderer-cancel logic
55     // introduces a case where this occurs when the renderer cancels a resource.
56   }
57   // A OnWillRead / OnReadCompleted pair may still be in progress, but
58   // OnWillRead passes back a scoped_refptr, so downstream handler's buffer will
59   // survive long enough to complete that read. From there, future reads will
60   // drain into |read_buffer_|. (If |next_handler_| is an AsyncResourceHandler,
61   // the net::IOBuffer takes a reference to the ResourceBuffer which owns the
62   // shared memory.)
63   next_handler_.reset();
64 
65   // Time the request out if it takes too long.
66   detached_timer_.reset(new base::OneShotTimer<DetachableResourceHandler>());
67   detached_timer_->Start(
68       FROM_HERE, cancel_delay_, this, &DetachableResourceHandler::Cancel);
69 
70   // Resume if necessary. The request may have been deferred, say, waiting on a
71   // full buffer in AsyncResourceHandler. Now that it has been detached, resume
72   // and drain it.
73   if (is_deferred_) {
74     // The nested ResourceHandler may have logged that it's blocking the
75     // request.  Log it as no longer doing so, to avoid a DCHECK on resume.
76     request()->LogUnblocked();
77     Resume();
78   }
79 }
80 
SetController(ResourceController * controller)81 void DetachableResourceHandler::SetController(ResourceController* controller) {
82   ResourceHandler::SetController(controller);
83 
84   // Intercept the ResourceController for downstream handlers to keep track of
85   // whether the request is deferred.
86   if (next_handler_)
87     next_handler_->SetController(this);
88 }
89 
OnUploadProgress(uint64 position,uint64 size)90 bool DetachableResourceHandler::OnUploadProgress(uint64 position, uint64 size) {
91   if (!next_handler_)
92     return true;
93 
94   return next_handler_->OnUploadProgress(position, size);
95 }
96 
OnRequestRedirected(const net::RedirectInfo & redirect_info,ResourceResponse * response,bool * defer)97 bool DetachableResourceHandler::OnRequestRedirected(
98     const net::RedirectInfo& redirect_info,
99     ResourceResponse* response,
100     bool* defer) {
101   DCHECK(!is_deferred_);
102 
103   if (!next_handler_)
104     return true;
105 
106   bool ret = next_handler_->OnRequestRedirected(
107       redirect_info, response, &is_deferred_);
108   *defer = is_deferred_;
109   return ret;
110 }
111 
OnResponseStarted(ResourceResponse * response,bool * defer)112 bool DetachableResourceHandler::OnResponseStarted(ResourceResponse* response,
113                                                   bool* defer) {
114   DCHECK(!is_deferred_);
115 
116   if (!next_handler_)
117     return true;
118 
119   bool ret =
120       next_handler_->OnResponseStarted(response, &is_deferred_);
121   *defer = is_deferred_;
122   return ret;
123 }
124 
OnWillStart(const GURL & url,bool * defer)125 bool DetachableResourceHandler::OnWillStart(const GURL& url, bool* defer) {
126   DCHECK(!is_deferred_);
127 
128   if (!next_handler_)
129     return true;
130 
131   bool ret = next_handler_->OnWillStart(url, &is_deferred_);
132   *defer = is_deferred_;
133   return ret;
134 }
135 
OnBeforeNetworkStart(const GURL & url,bool * defer)136 bool DetachableResourceHandler::OnBeforeNetworkStart(const GURL& url,
137                                                      bool* defer) {
138   DCHECK(!is_deferred_);
139 
140   if (!next_handler_)
141     return true;
142 
143   bool ret =
144       next_handler_->OnBeforeNetworkStart(url, &is_deferred_);
145   *defer = is_deferred_;
146   return ret;
147 }
148 
OnWillRead(scoped_refptr<net::IOBuffer> * buf,int * buf_size,int min_size)149 bool DetachableResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
150                                            int* buf_size,
151                                            int min_size) {
152   if (!next_handler_) {
153     DCHECK_EQ(-1, min_size);
154     if (!read_buffer_.get())
155       read_buffer_ = new net::IOBuffer(kReadBufSize);
156     *buf = read_buffer_;
157     *buf_size = kReadBufSize;
158     return true;
159   }
160 
161   return next_handler_->OnWillRead(buf, buf_size, min_size);
162 }
163 
OnReadCompleted(int bytes_read,bool * defer)164 bool DetachableResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
165   DCHECK(!is_deferred_);
166 
167   if (!next_handler_)
168     return true;
169 
170   bool ret =
171       next_handler_->OnReadCompleted(bytes_read, &is_deferred_);
172   *defer = is_deferred_;
173   return ret;
174 }
175 
OnResponseCompleted(const net::URLRequestStatus & status,const std::string & security_info,bool * defer)176 void DetachableResourceHandler::OnResponseCompleted(
177     const net::URLRequestStatus& status,
178     const std::string& security_info,
179     bool* defer) {
180   // No DCHECK(!is_deferred_) as the request may have been cancelled while
181   // deferred.
182 
183   if (!next_handler_)
184     return;
185 
186   is_finished_ = true;
187 
188   next_handler_->OnResponseCompleted(status, security_info, &is_deferred_);
189   *defer = is_deferred_;
190 }
191 
OnDataDownloaded(int bytes_downloaded)192 void DetachableResourceHandler::OnDataDownloaded(int bytes_downloaded) {
193   if (!next_handler_)
194     return;
195 
196   next_handler_->OnDataDownloaded(bytes_downloaded);
197 }
198 
Resume()199 void DetachableResourceHandler::Resume() {
200   DCHECK(is_deferred_);
201   is_deferred_ = false;
202   controller()->Resume();
203 }
204 
Cancel()205 void DetachableResourceHandler::Cancel() {
206   controller()->Cancel();
207 }
208 
CancelAndIgnore()209 void DetachableResourceHandler::CancelAndIgnore() {
210   controller()->CancelAndIgnore();
211 }
212 
CancelWithError(int error_code)213 void DetachableResourceHandler::CancelWithError(int error_code) {
214   controller()->CancelWithError(error_code);
215 }
216 
217 }  // namespace content
218