Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / loader / detachable_resource_handler.cc
blobab7e240b1ee0b9f8d8703892c361bbf5c933b146
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"
15 namespace {
16 // This matches the maximum allocation size of AsyncResourceHandler.
17 const int kReadBufSize = 32 * 1024;
20 namespace content {
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);
34 DetachableResourceHandler::~DetachableResourceHandler() {
35 // Cleanup back-pointer stored on the request info.
36 GetRequestInfo()->set_detachable_handler(NULL);
39 void DetachableResourceHandler::Detach() {
40 if (is_detached())
41 return;
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.
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();
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
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();
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.
86 if (next_handler_)
87 next_handler_->SetController(this);
90 bool DetachableResourceHandler::OnUploadProgress(uint64 position, uint64 size) {
91 if (!next_handler_)
92 return true;
94 return next_handler_->OnUploadProgress(position, size);
97 bool DetachableResourceHandler::OnRequestRedirected(
98 const net::RedirectInfo& redirect_info,
99 ResourceResponse* response,
100 bool* defer) {
101 DCHECK(!is_deferred_);
103 if (!next_handler_)
104 return true;
106 bool ret = next_handler_->OnRequestRedirected(
107 redirect_info, response, &is_deferred_);
108 *defer = is_deferred_;
109 return ret;
112 bool DetachableResourceHandler::OnResponseStarted(ResourceResponse* response,
113 bool* defer) {
114 DCHECK(!is_deferred_);
116 if (!next_handler_)
117 return true;
119 bool ret =
120 next_handler_->OnResponseStarted(response, &is_deferred_);
121 *defer = is_deferred_;
122 return ret;
125 bool DetachableResourceHandler::OnWillStart(const GURL& url, bool* defer) {
126 DCHECK(!is_deferred_);
128 if (!next_handler_)
129 return true;
131 bool ret = next_handler_->OnWillStart(url, &is_deferred_);
132 *defer = is_deferred_;
133 return ret;
136 bool DetachableResourceHandler::OnBeforeNetworkStart(const GURL& url,
137 bool* defer) {
138 DCHECK(!is_deferred_);
140 if (!next_handler_)
141 return true;
143 bool ret =
144 next_handler_->OnBeforeNetworkStart(url, &is_deferred_);
145 *defer = is_deferred_;
146 return ret;
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;
161 return next_handler_->OnWillRead(buf, buf_size, min_size);
164 bool DetachableResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
165 DCHECK(!is_deferred_);
167 if (!next_handler_)
168 return true;
170 bool ret =
171 next_handler_->OnReadCompleted(bytes_read, &is_deferred_);
172 *defer = is_deferred_;
173 return ret;
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.
183 if (!next_handler_)
184 return;
186 is_finished_ = true;
188 next_handler_->OnResponseCompleted(status, security_info, &is_deferred_);
189 *defer = is_deferred_;
192 void DetachableResourceHandler::OnDataDownloaded(int bytes_downloaded) {
193 if (!next_handler_)
194 return;
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