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.
5 #include "content/browser/loader/detachable_resource_handler.h"
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"
16 // This matches the maximum allocation size of AsyncResourceHandler.
17 const int kReadBufSize
= 32 * 1024;
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
),
31 GetRequestInfo()->set_detachable_handler(this);
34 DetachableResourceHandler::~DetachableResourceHandler() {
35 // Cleanup back-pointer stored on the request info.
36 GetRequestInfo()->set_detachable_handler(NULL
);
39 void DetachableResourceHandler::Detach() {
44 // Simulate a cancel on the next handler before destroying it.
45 net::URLRequestStatus
status(net::URLRequestStatus::CANCELED
,
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.
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
63 next_handler_
.reset();
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
);
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
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();
81 void DetachableResourceHandler::SetController(ResourceController
* controller
) {
82 ResourceHandler::SetController(controller
);
84 // Intercept the ResourceController for downstream handlers to keep track of
85 // whether the request is deferred.
87 next_handler_
->SetController(this);
90 bool DetachableResourceHandler::OnUploadProgress(uint64 position
, uint64 size
) {
94 return next_handler_
->OnUploadProgress(position
, size
);
97 bool DetachableResourceHandler::OnRequestRedirected(
98 const net::RedirectInfo
& redirect_info
,
99 ResourceResponse
* response
,
101 DCHECK(!is_deferred_
);
106 bool ret
= next_handler_
->OnRequestRedirected(
107 redirect_info
, response
, &is_deferred_
);
108 *defer
= is_deferred_
;
112 bool DetachableResourceHandler::OnResponseStarted(ResourceResponse
* response
,
114 DCHECK(!is_deferred_
);
120 next_handler_
->OnResponseStarted(response
, &is_deferred_
);
121 *defer
= is_deferred_
;
125 bool DetachableResourceHandler::OnWillStart(const GURL
& url
, bool* defer
) {
126 DCHECK(!is_deferred_
);
131 bool ret
= next_handler_
->OnWillStart(url
, &is_deferred_
);
132 *defer
= is_deferred_
;
136 bool DetachableResourceHandler::OnBeforeNetworkStart(const GURL
& url
,
138 DCHECK(!is_deferred_
);
144 next_handler_
->OnBeforeNetworkStart(url
, &is_deferred_
);
145 *defer
= is_deferred_
;
149 bool DetachableResourceHandler::OnWillRead(scoped_refptr
<net::IOBuffer
>* buf
,
152 if (!next_handler_
) {
153 DCHECK_EQ(-1, min_size
);
154 if (!read_buffer_
.get())
155 read_buffer_
= new net::IOBuffer(kReadBufSize
);
157 *buf_size
= kReadBufSize
;
161 return next_handler_
->OnWillRead(buf
, buf_size
, min_size
);
164 bool DetachableResourceHandler::OnReadCompleted(int bytes_read
, bool* defer
) {
165 DCHECK(!is_deferred_
);
171 next_handler_
->OnReadCompleted(bytes_read
, &is_deferred_
);
172 *defer
= is_deferred_
;
176 void DetachableResourceHandler::OnResponseCompleted(
177 const net::URLRequestStatus
& status
,
178 const std::string
& security_info
,
180 // No DCHECK(!is_deferred_) as the request may have been cancelled while
188 next_handler_
->OnResponseCompleted(status
, security_info
, &is_deferred_
);
189 *defer
= is_deferred_
;
192 void DetachableResourceHandler::OnDataDownloaded(int bytes_downloaded
) {
196 next_handler_
->OnDataDownloaded(bytes_downloaded
);
199 void DetachableResourceHandler::Resume() {
200 DCHECK(is_deferred_
);
201 is_deferred_
= false;
202 controller()->Resume();
205 void DetachableResourceHandler::Cancel() {
206 controller()->Cancel();
209 void DetachableResourceHandler::CancelAndIgnore() {
210 controller()->CancelAndIgnore();
213 void DetachableResourceHandler::CancelWithError(int error_code
) {
214 controller()->CancelWithError(error_code
);
217 } // namespace content