blob: 42c7d1f191d5a6261dfbc2bf265d689b313886f9 [file] [log] [blame]
[email protected]146b8b22013-11-20 03:59:181// 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_status.h"
13
14namespace {
15// This matches the maximum allocation size of AsyncResourceHandler.
16const int kReadBufSize = 32 * 1024;
17}
18
19namespace content {
20
21DetachableResourceHandler::DetachableResourceHandler(
22 net::URLRequest* request,
23 base::TimeDelta cancel_delay,
24 scoped_ptr<ResourceHandler> next_handler)
25 : ResourceHandler(request),
26 next_handler_(next_handler.Pass()),
27 cancel_delay_(cancel_delay),
28 is_deferred_(false),
29 is_finished_(false) {
30 GetRequestInfo()->set_detachable_handler(this);
31}
32
33DetachableResourceHandler::~DetachableResourceHandler() {
34 // Cleanup back-pointer stored on the request info.
35 GetRequestInfo()->set_detachable_handler(NULL);
36}
37
38void DetachableResourceHandler::Detach() {
39 if (is_detached())
40 return;
41
42 if (!is_finished_) {
43 // Simulate a cancel on the next handler before destroying it.
44 net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
45 net::ERR_ABORTED);
46 bool defer_ignored = false;
47 next_handler_->OnResponseCompleted(GetRequestID(), status, std::string(),
48 &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 Resume();
75}
76
77void DetachableResourceHandler::SetController(ResourceController* controller) {
78 ResourceHandler::SetController(controller);
79
80 // Intercept the ResourceController for downstream handlers to keep track of
81 // whether the request is deferred.
82 if (next_handler_)
83 next_handler_->SetController(this);
84}
85
86bool DetachableResourceHandler::OnUploadProgress(int request_id,
87 uint64 position,
88 uint64 size) {
89 if (!next_handler_)
90 return true;
91
92 return next_handler_->OnUploadProgress(request_id, position, size);
93}
94
95bool DetachableResourceHandler::OnRequestRedirected(int request_id,
96 const GURL& url,
97 ResourceResponse* response,
98 bool* defer) {
99 DCHECK(!is_deferred_);
100
101 if (!next_handler_)
102 return true;
103
104 bool ret = next_handler_->OnRequestRedirected(request_id, url, response,
105 &is_deferred_);
106 *defer = is_deferred_;
107 return ret;
108}
109
110bool DetachableResourceHandler::OnResponseStarted(int request_id,
111 ResourceResponse* response,
112 bool* defer) {
113 DCHECK(!is_deferred_);
114
115 if (!next_handler_)
116 return true;
117
118 bool ret =
119 next_handler_->OnResponseStarted(request_id, response, &is_deferred_);
120 *defer = is_deferred_;
121 return ret;
122}
123
124bool DetachableResourceHandler::OnWillStart(int request_id, const GURL& url,
125 bool* defer) {
126 DCHECK(!is_deferred_);
127
128 if (!next_handler_)
129 return true;
130
131 bool ret = next_handler_->OnWillStart(request_id, url, &is_deferred_);
132 *defer = is_deferred_;
133 return ret;
134}
135
[email protected]5584eab2014-01-09 22:16:15136bool DetachableResourceHandler::OnBeforeNetworkStart(int request_id,
137 const GURL& url,
138 bool* defer) {
139 DCHECK(!is_deferred_);
140
141 if (!next_handler_)
142 return true;
143
144 bool ret =
145 next_handler_->OnBeforeNetworkStart(request_id, url, &is_deferred_);
146 *defer = is_deferred_;
147 return ret;
148}
149
[email protected]146b8b22013-11-20 03:59:18150bool DetachableResourceHandler::OnWillRead(int request_id,
151 scoped_refptr<net::IOBuffer>* buf,
152 int* buf_size,
153 int min_size) {
154 if (!next_handler_) {
155 DCHECK_EQ(-1, min_size);
156 if (!read_buffer_)
157 read_buffer_ = new net::IOBuffer(kReadBufSize);
158 *buf = read_buffer_;
159 *buf_size = kReadBufSize;
160 return true;
161 }
162
163 return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
164}
165
166bool DetachableResourceHandler::OnReadCompleted(int request_id, int bytes_read,
167 bool* defer) {
168 DCHECK(!is_deferred_);
169
170 if (!next_handler_)
171 return true;
172
173 bool ret =
174 next_handler_->OnReadCompleted(request_id, bytes_read, &is_deferred_);
175 *defer = is_deferred_;
176 return ret;
177}
178
179void DetachableResourceHandler::OnResponseCompleted(
180 int request_id,
181 const net::URLRequestStatus& status,
182 const std::string& security_info,
183 bool* defer) {
184 // No DCHECK(!is_deferred_) as the request may have been cancelled while
185 // deferred.
186
187 if (!next_handler_)
188 return;
189
190 is_finished_ = true;
191
192 next_handler_->OnResponseCompleted(request_id, status, security_info,
193 &is_deferred_);
194 *defer = is_deferred_;
195}
196
197void DetachableResourceHandler::OnDataDownloaded(int request_id,
198 int bytes_downloaded) {
199 if (!next_handler_)
200 return;
201
202 next_handler_->OnDataDownloaded(request_id, bytes_downloaded);
203}
204
205void DetachableResourceHandler::Resume() {
206 DCHECK(is_deferred_);
207 is_deferred_ = false;
208 controller()->Resume();
209}
210
211void DetachableResourceHandler::Cancel() {
212 controller()->Cancel();
213}
214
215void DetachableResourceHandler::CancelAndIgnore() {
216 controller()->CancelAndIgnore();
217}
218
219void DetachableResourceHandler::CancelWithError(int error_code) {
220 controller()->CancelWithError(error_code);
221}
222
223} // namespace content