Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / loader / detachable_resource_handler.cc
blob139a6299d3f475c5b8196a55e3acc754823681b7
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. MimeTypeResourceHandler 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::OnRequestRedirected(
91 const net::RedirectInfo& redirect_info,
92 ResourceResponse* response,
93 bool* defer) {
94 DCHECK(!is_deferred_);
96 if (!next_handler_)
97 return true;
99 bool ret = next_handler_->OnRequestRedirected(
100 redirect_info, response, &is_deferred_);
101 *defer = is_deferred_;
102 return ret;
105 bool DetachableResourceHandler::OnResponseStarted(ResourceResponse* response,
106 bool* defer) {
107 DCHECK(!is_deferred_);
109 if (!next_handler_)
110 return true;
112 bool ret =
113 next_handler_->OnResponseStarted(response, &is_deferred_);
114 *defer = is_deferred_;
115 return ret;
118 bool DetachableResourceHandler::OnWillStart(const GURL& url, bool* defer) {
119 DCHECK(!is_deferred_);
121 if (!next_handler_)
122 return true;
124 bool ret = next_handler_->OnWillStart(url, &is_deferred_);
125 *defer = is_deferred_;
126 return ret;
129 bool DetachableResourceHandler::OnBeforeNetworkStart(const GURL& url,
130 bool* defer) {
131 DCHECK(!is_deferred_);
133 if (!next_handler_)
134 return true;
136 bool ret =
137 next_handler_->OnBeforeNetworkStart(url, &is_deferred_);
138 *defer = is_deferred_;
139 return ret;
142 bool DetachableResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf,
143 int* buf_size,
144 int min_size) {
145 if (!next_handler_) {
146 DCHECK_EQ(-1, min_size);
147 if (!read_buffer_.get())
148 read_buffer_ = new net::IOBuffer(kReadBufSize);
149 *buf = read_buffer_;
150 *buf_size = kReadBufSize;
151 return true;
154 return next_handler_->OnWillRead(buf, buf_size, min_size);
157 bool DetachableResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
158 DCHECK(!is_deferred_);
160 if (!next_handler_)
161 return true;
163 bool ret =
164 next_handler_->OnReadCompleted(bytes_read, &is_deferred_);
165 *defer = is_deferred_;
166 return ret;
169 void DetachableResourceHandler::OnResponseCompleted(
170 const net::URLRequestStatus& status,
171 const std::string& security_info,
172 bool* defer) {
173 // No DCHECK(!is_deferred_) as the request may have been cancelled while
174 // deferred.
176 if (!next_handler_)
177 return;
179 is_finished_ = true;
181 next_handler_->OnResponseCompleted(status, security_info, &is_deferred_);
182 *defer = is_deferred_;
185 void DetachableResourceHandler::OnDataDownloaded(int bytes_downloaded) {
186 if (!next_handler_)
187 return;
189 next_handler_->OnDataDownloaded(bytes_downloaded);
192 void DetachableResourceHandler::Resume() {
193 DCHECK(is_deferred_);
194 is_deferred_ = false;
195 controller()->Resume();
198 void DetachableResourceHandler::Cancel() {
199 controller()->Cancel();
202 void DetachableResourceHandler::CancelAndIgnore() {
203 controller()->CancelAndIgnore();
206 void DetachableResourceHandler::CancelWithError(int error_code) {
207 controller()->CancelWithError(error_code);
210 } // namespace content