Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: content/browser/loader/intercepting_resource_handler.cc

Issue 2668603003: Make ResourceHandler::OnWillRead able to complete asynchronously. (Closed)
Patch Set: Response to comments Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/loader/intercepting_resource_handler.h" 5 #include "content/browser/loader/intercepting_resource_handler.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/location.h" 8 #include "base/location.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
11 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
12 #include "base/threading/thread_task_runner_handle.h" 12 #include "base/threading/thread_task_runner_handle.h"
13 #include "content/browser/loader/null_resource_controller.h" 13 #include "content/browser/loader/null_resource_controller.h"
14 #include "content/browser/loader/resource_controller.h" 14 #include "content/browser/loader/resource_controller.h"
15 #include "content/public/common/resource_response.h" 15 #include "content/public/common/resource_response.h"
16 #include "net/base/io_buffer.h" 16 #include "net/base/io_buffer.h"
17 #include "net/url_request/url_request.h" 17 #include "net/url_request/url_request.h"
18 18
19 namespace content { 19 namespace content {
20 20
21 class InterceptingResourceHandler::Controller : public ResourceController { 21 class InterceptingResourceHandler::Controller : public ResourceController {
22 public: 22 public:
23 explicit Controller(InterceptingResourceHandler* mime_handler) 23 explicit Controller(InterceptingResourceHandler* mime_handler)
24 : intercepting_handler_(mime_handler) {} 24 : intercepting_handler_(mime_handler) {
25 DCHECK(intercepting_handler_->has_controller());
26 }
25 27
26 void Resume() override { 28 void Resume() override {
27 MarkAsUsed(); 29 MarkAsUsed();
28 intercepting_handler_->ResumeInternal(); 30 intercepting_handler_->ResumeInternal();
29 } 31 }
30 32
31 void Cancel() override { 33 void Cancel() override {
32 MarkAsUsed(); 34 MarkAsUsed();
33 intercepting_handler_->Cancel(); 35 intercepting_handler_->Cancel();
34 } 36 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 response_ = response; 87 response_ = response;
86 88
87 // Otherwise, switch handlers. First, inform the original ResourceHandler 89 // Otherwise, switch handlers. First, inform the original ResourceHandler
88 // that this will be handled entirely by the new ResourceHandler. 90 // that this will be handled entirely by the new ResourceHandler.
89 HoldController(std::move(controller)); 91 HoldController(std::move(controller));
90 state_ = State::SWAPPING_HANDLERS; 92 state_ = State::SWAPPING_HANDLERS;
91 93
92 DoLoop(); 94 DoLoop();
93 } 95 }
94 96
95 bool InterceptingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, 97 void InterceptingResourceHandler::OnWillRead(
96 int* buf_size) { 98 scoped_refptr<net::IOBuffer>* buf,
97 if (state_ == State::PASS_THROUGH) 99 int* buf_size,
98 return next_handler_->OnWillRead(buf, buf_size); 100 std::unique_ptr<ResourceController> controller) {
101 if (state_ == State::PASS_THROUGH) {
102 next_handler_->OnWillRead(buf, buf_size, std::move(controller));
103 return;
104 }
99 105
100 DCHECK_EQ(State::STARTING, state_); 106 DCHECK_EQ(State::STARTING, state_);
107 DCHECK(!first_read_buffer_);
108 DCHECK_EQ(0, first_read_buffer_size_);
109 DCHECK(!parent_read_buffer_);
110 DCHECK(!parent_read_buffer_size_);
101 111
102 if (!next_handler_->OnWillRead(buf, buf_size)) 112 parent_read_buffer_ = buf;
103 return false; 113 parent_read_buffer_size_ = buf_size;
104 114
105 first_read_buffer_ = *buf; 115 state_ = State::SENDING_ON_WILL_READ_TO_OLD_HANDLER;
106 first_read_buffer_size_ = *buf_size; 116 HoldController(std::move(controller));
107 first_read_buffer_double_ = new net::IOBuffer(static_cast<size_t>(*buf_size)); 117 DoLoop();
108 *buf = first_read_buffer_double_;
109 return true;
110 } 118 }
111 119
112 void InterceptingResourceHandler::OnReadCompleted( 120 void InterceptingResourceHandler::OnReadCompleted(
113 int bytes_read, 121 int bytes_read,
114 std::unique_ptr<ResourceController> controller) { 122 std::unique_ptr<ResourceController> controller) {
115 DCHECK(!has_controller()); 123 DCHECK(!has_controller());
116 124
117 DCHECK_GE(bytes_read, 0); 125 DCHECK_GE(bytes_read, 0);
118 if (state_ == State::PASS_THROUGH) { 126 if (state_ == State::PASS_THROUGH) {
119 if (first_read_buffer_double_) { 127 if (first_read_buffer_double_) {
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 192
185 while (advance_to_next_state_) { 193 while (advance_to_next_state_) {
186 advance_to_next_state_ = false; 194 advance_to_next_state_ = false;
187 195
188 switch (state_) { 196 switch (state_) {
189 case State::STARTING: 197 case State::STARTING:
190 case State::WAITING_FOR_ON_READ_COMPLETED: 198 case State::WAITING_FOR_ON_READ_COMPLETED:
191 case State::PASS_THROUGH: 199 case State::PASS_THROUGH:
192 NOTREACHED(); 200 NOTREACHED();
193 break; 201 break;
202 case State::SENDING_ON_WILL_READ_TO_OLD_HANDLER:
203 SendOnWillReadToOldHandler();
204 break;
205 case State::WAITING_FOR_OLD_HANDLERS_BUFFER:
206 OnBufferReceived();
207 break;
194 case State::SENDING_ON_WILL_START_TO_NEW_HANDLER: 208 case State::SENDING_ON_WILL_START_TO_NEW_HANDLER:
195 SendOnResponseStartedToNewHandler(); 209 SendOnResponseStartedToNewHandler();
196 break; 210 break;
197 case State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER: 211 case State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER:
198 if (first_read_buffer_double_) { 212 if (first_read_buffer_double_) {
199 // OnWillRead has been called, so copying the data from 213 // OnWillRead has been called, so copying the data from
200 // |first_read_buffer_double_| to |first_read_buffer_| will be needed 214 // |first_read_buffer_double_| to |first_read_buffer_| will be needed
201 // when OnReadCompleted is called. 215 // when OnReadCompleted is called.
202 state_ = State::WAITING_FOR_ON_READ_COMPLETED; 216 state_ = State::WAITING_FOR_ON_READ_COMPLETED;
203 } else { 217 } else {
204 // OnWillRead has not been called, so no special handling will be 218 // OnWillRead has not been called, so no special handling will be
205 // needed from now on. 219 // needed from now on.
206 state_ = State::PASS_THROUGH; 220 state_ = State::PASS_THROUGH;
207 } 221 }
208 ResumeInternal(); 222 ResumeInternal();
209 break; 223 break;
210 case State::SWAPPING_HANDLERS: 224 case State::SWAPPING_HANDLERS:
211 SendOnResponseStartedToOldHandler(); 225 SendOnResponseStartedToOldHandler();
212 break; 226 break;
213 case State::SENDING_PAYLOAD_TO_OLD_HANDLER: 227 case State::SENDING_PAYLOAD_TO_OLD_HANDLER:
214 SendPayloadToOldHandler(); 228 SendPayloadToOldHandler();
215 break; 229 break;
230 case State::RECEIVING_BUFFER_FROM_OLD_HANDLER:
231 ReceivedBufferFromOldHandler();
232 break;
216 case State::SENDING_BUFFER_TO_NEW_HANDLER: 233 case State::SENDING_BUFFER_TO_NEW_HANDLER:
217 SendFirstReadBufferToNewHandler(); 234 SendFirstReadBufferToNewHandler();
218 break; 235 break;
236 case State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER:
237 ReceivedBufferFromNewHandler();
238 break;
219 } 239 }
220 } 240 }
221 } 241 }
222 242
223 void InterceptingResourceHandler::ResumeInternal() { 243 void InterceptingResourceHandler::ResumeInternal() {
224 DCHECK(has_controller()); 244 DCHECK(has_controller());
225 if (state_ == State::STARTING || 245 if (state_ == State::STARTING ||
226 state_ == State::WAITING_FOR_ON_READ_COMPLETED || 246 state_ == State::WAITING_FOR_ON_READ_COMPLETED ||
227 state_ == State::PASS_THROUGH) { 247 state_ == State::PASS_THROUGH) {
228 // Uninteresting Resume: just delegate to the original resource controller. 248 // Uninteresting Resume: just delegate to the original resource controller.
229 Resume(); 249 Resume();
230 return; 250 return;
231 } 251 }
232 252
233 // If called recusively from a DoLoop, advance state when returning to the 253 // If called recusively from a DoLoop, advance state when returning to the
234 // loop. 254 // loop.
235 if (in_do_loop_) { 255 if (in_do_loop_) {
236 DCHECK(!advance_to_next_state_); 256 DCHECK(!advance_to_next_state_);
237 advance_to_next_state_ = true; 257 advance_to_next_state_ = true;
238 return; 258 return;
239 } 259 }
240 260
241 // Can't call DoLoop synchronously, as it may call into |next_handler_| 261 // Can't call DoLoop synchronously, as it may call into |next_handler_|
242 // synchronously, which is what called Resume(). 262 // synchronously, which is what called Resume().
243 base::ThreadTaskRunnerHandle::Get()->PostTask( 263 base::ThreadTaskRunnerHandle::Get()->PostTask(
244 FROM_HERE, base::Bind(&InterceptingResourceHandler::DoLoop, 264 FROM_HERE, base::Bind(&InterceptingResourceHandler::DoLoop,
245 weak_ptr_factory_.GetWeakPtr())); 265 weak_ptr_factory_.GetWeakPtr()));
246 } 266 }
247 267
268 void InterceptingResourceHandler::SendOnWillReadToOldHandler() {
269 DCHECK_EQ(State::SENDING_ON_WILL_READ_TO_OLD_HANDLER, state_);
270
271 state_ = State::WAITING_FOR_OLD_HANDLERS_BUFFER;
272 next_handler_->OnWillRead(&first_read_buffer_, &first_read_buffer_size_,
273 base::MakeUnique<Controller>(this));
274 }
275
276 void InterceptingResourceHandler::OnBufferReceived() {
277 DCHECK_EQ(State::WAITING_FOR_OLD_HANDLERS_BUFFER, state_);
278
279 // TODO(mmenke): If this method is just going to allocate a double buffer
280 // anyways, can the call to the old handler's OnWillRead be removed? That
281 // would mean handling replaying data in the case that |next_handler_|'s
282 // buffer is smaller than the double buffer, but SendPayloadToOldHandler
283 // already handles that case, anyways, so could share that code with the
284 // no-swap path as well. Or better, just have MimeSniffingResourceHandler
285 // create and manage the buffer itself.
286 first_read_buffer_double_ =
287 new net::IOBuffer(static_cast<size_t>(first_read_buffer_size_));
288 *parent_read_buffer_ = first_read_buffer_double_;
289 *parent_read_buffer_size_ = first_read_buffer_size_;
290
291 parent_read_buffer_ = nullptr;
292 parent_read_buffer_size_ = nullptr;
293
294 state_ = State::STARTING;
295 Resume();
296 }
297
248 void InterceptingResourceHandler::SendOnResponseStartedToOldHandler() { 298 void InterceptingResourceHandler::SendOnResponseStartedToOldHandler() {
249 state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER; 299 state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER;
250 next_handler_->OnResponseStarted(response_.get(), 300 next_handler_->OnResponseStarted(response_.get(),
251 base::MakeUnique<Controller>(this)); 301 base::MakeUnique<Controller>(this));
252 } 302 }
253 303
254 void InterceptingResourceHandler::SendPayloadToOldHandler() { 304 void InterceptingResourceHandler::SendPayloadToOldHandler() {
255 DCHECK_EQ(State::SENDING_PAYLOAD_TO_OLD_HANDLER, state_); 305 DCHECK_EQ(State::SENDING_PAYLOAD_TO_OLD_HANDLER, state_);
256 if (payload_bytes_written_ == payload_for_old_handler_.size()) { 306 DCHECK(has_controller());
307
308 if (static_cast<size_t>(payload_bytes_written_) ==
309 payload_for_old_handler_.size()) {
257 net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0); 310 net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
258 if (payload_for_old_handler_.empty()) { 311 if (payload_for_old_handler_.empty()) {
259 // If there is no payload, just finalize the request on the old handler. 312 // If there is no payload, just finalize the request on the old handler.
260 status = net::URLRequestStatus::FromError(net::ERR_ABORTED); 313 status = net::URLRequestStatus::FromError(net::ERR_ABORTED);
261 } 314 }
262 bool was_resumed = false; 315 bool was_resumed = false;
263 // TODO(mmenke): Get rid of NullResourceController and do something more 316 // TODO(mmenke): Get rid of NullResourceController and do something more
264 // reasonable. 317 // reasonable.
265 next_handler_->OnResponseCompleted( 318 next_handler_->OnResponseCompleted(
266 status, base::MakeUnique<NullResourceController>(&was_resumed)); 319 status, base::MakeUnique<NullResourceController>(&was_resumed));
267 DCHECK(was_resumed); 320 DCHECK(was_resumed);
268 321
269 next_handler_ = std::move(new_handler_); 322 next_handler_ = std::move(new_handler_);
270 state_ = State::SENDING_ON_WILL_START_TO_NEW_HANDLER; 323 state_ = State::SENDING_ON_WILL_START_TO_NEW_HANDLER;
271 next_handler_->OnWillStart(request()->url(), 324 next_handler_->OnWillStart(request()->url(),
272 base::MakeUnique<Controller>(this)); 325 base::MakeUnique<Controller>(this));
273 return; 326 return;
274 } 327 }
275 328
329 state_ = State::RECEIVING_BUFFER_FROM_OLD_HANDLER;
330
276 scoped_refptr<net::IOBuffer> buffer; 331 scoped_refptr<net::IOBuffer> buffer;
277 int size = 0; 332 // If |first_read_buffer_| is non-NULL, it was already received from
333 // |next_handler_| via OnWillRead. Can just use the buffer.
278 if (first_read_buffer_) { 334 if (first_read_buffer_) {
279 // |first_read_buffer_| is a buffer gotten from |next_handler_| via 335 DCHECK_GT(first_read_buffer_size_, 0);
280 // OnWillRead. Use the buffer.
281 buffer = first_read_buffer_;
282 size = first_read_buffer_size_;
283 336
284 first_read_buffer_ = nullptr; 337 ResumeInternal();
285 first_read_buffer_size_ = 0; 338 return;
286 } else {
287 if (!next_handler_->OnWillRead(&buffer, &size)) {
288 Cancel();
289 return;
290 }
291 } 339 }
292 340
293 size = std::min(size, static_cast<int>(payload_for_old_handler_.size() - 341 DCHECK(!first_read_buffer_size_);
294 payload_bytes_written_)); 342 next_handler_->OnWillRead(&first_read_buffer_, &first_read_buffer_size_,
295 memcpy(buffer->data(), 343 base::MakeUnique<Controller>(this));
296 payload_for_old_handler_.data() + payload_bytes_written_, size); 344 }
297 payload_bytes_written_ += size; 345
298 next_handler_->OnReadCompleted(size, base::MakeUnique<Controller>(this)); 346 void InterceptingResourceHandler::ReceivedBufferFromOldHandler() {
347 DCHECK_EQ(State::RECEIVING_BUFFER_FROM_OLD_HANDLER, state_);
348 DCHECK(first_read_buffer_);
349 DCHECK_GT(first_read_buffer_size_, 0);
350
351 int bytes_to_copy =
352 std::min(first_read_buffer_size_,
353 static_cast<int>(payload_for_old_handler_.size() -
354 payload_bytes_written_));
355 memcpy(first_read_buffer_->data(),
356 payload_for_old_handler_.data() + payload_bytes_written_,
357 bytes_to_copy);
358 payload_bytes_written_ += bytes_to_copy;
359
360 first_read_buffer_ = nullptr;
361 first_read_buffer_size_ = 0;
362
363 state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER;
364 next_handler_->OnReadCompleted(bytes_to_copy,
365 base::MakeUnique<Controller>(this));
299 } 366 }
300 367
301 void InterceptingResourceHandler::SendOnResponseStartedToNewHandler() { 368 void InterceptingResourceHandler::SendOnResponseStartedToNewHandler() {
302 state_ = State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER; 369 state_ = State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER;
303 next_handler_->OnResponseStarted(response_.get(), 370 next_handler_->OnResponseStarted(response_.get(),
304 base::MakeUnique<Controller>(this)); 371 base::MakeUnique<Controller>(this));
305 } 372 }
306 373
307 void InterceptingResourceHandler::SendFirstReadBufferToNewHandler() { 374 void InterceptingResourceHandler::SendFirstReadBufferToNewHandler() {
308 DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER); 375 DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER);
376 DCHECK(!new_handler_read_buffer_);
377 DCHECK(!new_handler_read_buffer_size_);
309 378
310 if (first_read_buffer_bytes_written_ == first_read_buffer_bytes_read_) { 379 if (first_read_buffer_bytes_written_ == first_read_buffer_bytes_read_) {
311 state_ = State::PASS_THROUGH; 380 state_ = State::PASS_THROUGH;
312 first_read_buffer_double_ = nullptr; 381 first_read_buffer_double_ = nullptr;
313 ResumeInternal(); 382 ResumeInternal();
314 return; 383 return;
315 } 384 }
316 385
317 scoped_refptr<net::IOBuffer> buf; 386 state_ = State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER;
318 int size = 0; 387 next_handler_->OnWillRead(&new_handler_read_buffer_,
319 if (!next_handler_->OnWillRead(&buf, &size)) { 388 &new_handler_read_buffer_size_,
320 Cancel(); 389 base::MakeUnique<Controller>(this));
321 return; 390 }
322 } 391
323 size = std::min(size, static_cast<int>(first_read_buffer_bytes_read_ - 392 void InterceptingResourceHandler::ReceivedBufferFromNewHandler() {
324 first_read_buffer_bytes_written_)); 393 DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER);
325 memcpy(buf->data(), 394 DCHECK(new_handler_read_buffer_);
395 DCHECK(new_handler_read_buffer_size_);
396
397 int bytes_to_copy =
398 std::min(new_handler_read_buffer_size_,
399 static_cast<int>(first_read_buffer_bytes_read_ -
400 first_read_buffer_bytes_written_));
401 memcpy(new_handler_read_buffer_->data(),
326 first_read_buffer_double_->data() + first_read_buffer_bytes_written_, 402 first_read_buffer_double_->data() + first_read_buffer_bytes_written_,
327 size); 403 bytes_to_copy);
328 first_read_buffer_bytes_written_ += size; 404 first_read_buffer_bytes_written_ += bytes_to_copy;
329 next_handler_->OnReadCompleted(size, base::MakeUnique<Controller>(this)); 405
406 new_handler_read_buffer_ = nullptr;
407 new_handler_read_buffer_size_ = 0;
408
409 state_ = State::SENDING_BUFFER_TO_NEW_HANDLER;
410 next_handler_->OnReadCompleted(bytes_to_copy,
411 base::MakeUnique<Controller>(this));
330 } 412 }
331 413
332 } // namespace content 414 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698