OLD | NEW |
---|---|
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/mojo_async_resource_handler.h" | 5 #include "content/browser/loader/mojo_async_resource_handler.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 11 matching lines...) Expand all Loading... | |
22 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 22 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
23 #include "content/browser/loader/resource_request_info_impl.h" | 23 #include "content/browser/loader/resource_request_info_impl.h" |
24 #include "content/browser/loader/resource_scheduler.h" | 24 #include "content/browser/loader/resource_scheduler.h" |
25 #include "content/browser/loader/upload_progress_tracker.h" | 25 #include "content/browser/loader/upload_progress_tracker.h" |
26 #include "content/common/resource_request_completion_status.h" | 26 #include "content/common/resource_request_completion_status.h" |
27 #include "content/public/browser/global_request_id.h" | 27 #include "content/public/browser/global_request_id.h" |
28 #include "content/public/browser/resource_dispatcher_host_delegate.h" | 28 #include "content/public/browser/resource_dispatcher_host_delegate.h" |
29 #include "content/public/common/resource_response.h" | 29 #include "content/public/common/resource_response.h" |
30 #include "mojo/public/c/system/data_pipe.h" | 30 #include "mojo/public/c/system/data_pipe.h" |
31 #include "mojo/public/cpp/bindings/message.h" | 31 #include "mojo/public/cpp/bindings/message.h" |
32 #include "net/base/io_buffer.h" | |
33 #include "net/base/mime_sniffer.h" | 32 #include "net/base/mime_sniffer.h" |
33 #include "net/base/net_errors.h" | |
34 #include "net/url_request/redirect_info.h" | 34 #include "net/url_request/redirect_info.h" |
35 | 35 |
36 namespace content { | 36 namespace content { |
37 namespace { | 37 namespace { |
38 | 38 |
39 int g_allocation_size = MojoAsyncResourceHandler::kDefaultAllocationSize; | 39 int g_allocation_size = MojoAsyncResourceHandler::kDefaultAllocationSize; |
40 | 40 |
41 // MimeTypeResourceHandler *implicitly* requires that the buffer size | 41 // MimeTypeResourceHandler *implicitly* requires that the buffer size |
42 // returned from OnWillRead should be larger than certain size. | 42 // returned from OnWillRead should be larger than certain size. |
43 // TODO(yhirano): Fix MimeTypeResourceHandler. | 43 // TODO(yhirano): Fix MimeTypeResourceHandler. |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
226 base::Unretained(this))); | 226 base::Unretained(this))); |
227 } | 227 } |
228 | 228 |
229 controller->Resume(); | 229 controller->Resume(); |
230 } | 230 } |
231 | 231 |
232 void MojoAsyncResourceHandler::OnWillRead( | 232 void MojoAsyncResourceHandler::OnWillRead( |
233 scoped_refptr<net::IOBuffer>* buf, | 233 scoped_refptr<net::IOBuffer>* buf, |
234 int* buf_size, | 234 int* buf_size, |
235 std::unique_ptr<ResourceController> controller) { | 235 std::unique_ptr<ResourceController> controller) { |
236 DCHECK(!buffer_); | |
237 DCHECK_EQ(0u, buffer_offset_); | |
238 | |
236 if (!CheckForSufficientResource()) { | 239 if (!CheckForSufficientResource()) { |
237 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); | 240 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
238 return; | 241 return; |
239 } | 242 } |
240 | 243 |
244 bool first_call = false; | |
241 if (!shared_writer_) { | 245 if (!shared_writer_) { |
246 first_call = true; | |
242 MojoCreateDataPipeOptions options; | 247 MojoCreateDataPipeOptions options; |
243 options.struct_size = sizeof(MojoCreateDataPipeOptions); | 248 options.struct_size = sizeof(MojoCreateDataPipeOptions); |
244 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; | 249 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; |
245 options.element_num_bytes = 1; | 250 options.element_num_bytes = 1; |
246 options.capacity_num_bytes = g_allocation_size; | 251 options.capacity_num_bytes = g_allocation_size; |
247 mojo::DataPipe data_pipe(options); | 252 mojo::DataPipe data_pipe(options); |
248 | 253 |
249 DCHECK(data_pipe.producer_handle.is_valid()); | 254 DCHECK(data_pipe.producer_handle.is_valid()); |
250 DCHECK(data_pipe.consumer_handle.is_valid()); | 255 DCHECK(data_pipe.consumer_handle.is_valid()); |
251 | 256 |
252 response_body_consumer_handle_ = std::move(data_pipe.consumer_handle); | 257 response_body_consumer_handle_ = std::move(data_pipe.consumer_handle); |
253 shared_writer_ = new SharedWriter(std::move(data_pipe.producer_handle)); | 258 shared_writer_ = new SharedWriter(std::move(data_pipe.producer_handle)); |
254 handle_watcher_.Start(shared_writer_->writer(), MOJO_HANDLE_SIGNAL_WRITABLE, | 259 handle_watcher_.Start(shared_writer_->writer(), MOJO_HANDLE_SIGNAL_WRITABLE, |
255 base::Bind(&MojoAsyncResourceHandler::OnWritable, | 260 base::Bind(&MojoAsyncResourceHandler::OnWritable, |
256 base::Unretained(this))); | 261 base::Unretained(this))); |
262 } | |
257 | 263 |
258 bool defer = false; | 264 bool defer = false; |
259 scoped_refptr<net::IOBufferWithSize> buffer; | 265 if (!AllocateWriterIOBuffer(&buffer_, &defer)) { |
260 if (!AllocateWriterIOBuffer(&buffer, &defer)) { | 266 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
267 return; | |
268 } | |
269 | |
270 if (defer) { | |
271 DCHECK(!buffer_); | |
272 parent_buffer_ = buf; | |
273 parent_buffer_size_ = buf_size; | |
274 HoldController(std::move(controller)); | |
275 request()->LogBlockedBy("MojoAsyncResourceHandler"); | |
276 did_defer_on_will_read_ = true; | |
277 return; | |
278 } | |
279 | |
280 // The first call to OnWillRead must return a buffer of at least | |
281 // kMinAllocationSize. If the Mojo buffer is too small, need to allocate an | |
282 // intermediary buffer. | |
283 if (first_call && static_cast<size_t>(buffer_->size()) < kMinAllocationSize) { | |
284 // The allocated buffer is too small, so need to create an intermediary one. | |
285 if (EndWrite(0) != MOJO_RESULT_OK) { | |
261 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); | 286 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
262 return; | 287 return; |
263 } | 288 } |
264 if (!defer) { | |
265 if (static_cast<size_t>(buffer->size()) >= kMinAllocationSize) { | |
266 *buf = buffer_ = buffer; | |
267 *buf_size = buffer_->size(); | |
268 controller->Resume(); | |
269 return; | |
270 } | |
271 | |
272 // The allocated buffer is too small. | |
273 if (EndWrite(0) != MOJO_RESULT_OK) { | |
274 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); | |
275 return; | |
276 } | |
277 } | |
278 DCHECK(!is_using_io_buffer_not_from_writer_); | 289 DCHECK(!is_using_io_buffer_not_from_writer_); |
279 is_using_io_buffer_not_from_writer_ = true; | 290 is_using_io_buffer_not_from_writer_ = true; |
280 buffer_ = new net::IOBufferWithSize(kMinAllocationSize); | 291 buffer_ = new net::IOBufferWithSize(kMinAllocationSize); |
281 } | 292 } |
282 | 293 |
283 DCHECK_EQ(0u, buffer_offset_); | |
284 *buf = buffer_; | 294 *buf = buffer_; |
285 *buf_size = buffer_->size(); | 295 *buf_size = buffer_->size(); |
286 controller->Resume(); | 296 controller->Resume(); |
287 } | 297 } |
288 | 298 |
289 void MojoAsyncResourceHandler::OnReadCompleted( | 299 void MojoAsyncResourceHandler::OnReadCompleted( |
290 int bytes_read, | 300 int bytes_read, |
291 std::unique_ptr<ResourceController> controller) { | 301 std::unique_ptr<ResourceController> controller) { |
292 DCHECK(!has_controller()); | 302 DCHECK(!has_controller()); |
293 DCHECK_GE(bytes_read, 0); | 303 DCHECK_GE(bytes_read, 0); |
294 DCHECK(buffer_); | 304 DCHECK(buffer_); |
295 | 305 |
296 if (!bytes_read) { | 306 if (bytes_read == 0) { |
307 // Note that |buffer_| is not cleared here, which will cause a DCHECK on | |
308 // subsequent OnWillRead calls. | |
Randy Smith (Not in Mondays)
2017/03/17 20:06:06
Confirming: It seems what this means is that you'r
mmenke
2017/03/17 22:29:39
It's mostly because a buffer_ = nullptr here didn'
| |
297 controller->Resume(); | 309 controller->Resume(); |
298 return; | 310 return; |
299 } | 311 } |
300 | 312 |
301 const ResourceRequestInfoImpl* info = GetRequestInfo(); | 313 const ResourceRequestInfoImpl* info = GetRequestInfo(); |
302 if (info->ShouldReportRawHeaders()) { | 314 if (info->ShouldReportRawHeaders()) { |
303 auto transfer_size_diff = CalculateRecentlyReceivedBytes(); | 315 auto transfer_size_diff = CalculateRecentlyReceivedBytes(); |
304 if (transfer_size_diff > 0) | 316 if (transfer_size_diff > 0) |
305 url_loader_client_->OnTransferSizeUpdated(transfer_size_diff); | 317 url_loader_client_->OnTransferSizeUpdated(transfer_size_diff); |
306 } | 318 } |
307 | 319 |
308 if (response_body_consumer_handle_.is_valid()) { | 320 if (response_body_consumer_handle_.is_valid()) { |
309 // Send the data pipe on the first OnReadCompleted call. | 321 // Send the data pipe on the first OnReadCompleted call. |
310 url_loader_client_->OnStartLoadingResponseBody( | 322 url_loader_client_->OnStartLoadingResponseBody( |
311 std::move(response_body_consumer_handle_)); | 323 std::move(response_body_consumer_handle_)); |
312 response_body_consumer_handle_.reset(); | 324 response_body_consumer_handle_.reset(); |
313 } | 325 } |
314 | 326 |
315 if (is_using_io_buffer_not_from_writer_) { | 327 if (is_using_io_buffer_not_from_writer_) { |
316 // Couldn't allocate a buffer on the data pipe in OnWillRead. | 328 // Couldn't allocate a large enough buffer on the data pipe in OnWillRead. |
317 DCHECK_EQ(0u, buffer_bytes_read_); | 329 DCHECK_EQ(0u, buffer_bytes_read_); |
318 buffer_bytes_read_ = bytes_read; | 330 buffer_bytes_read_ = bytes_read; |
319 bool defer = false; | 331 bool defer = false; |
320 if (!CopyReadDataToDataPipe(&defer)) { | 332 if (!CopyReadDataToDataPipe(&defer)) { |
321 controller->Cancel(); | 333 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
322 return; | 334 return; |
323 } | 335 } |
324 if (defer) { | 336 if (defer) { |
325 request()->LogBlockedBy("MojoAsyncResourceHandler"); | 337 request()->LogBlockedBy("MojoAsyncResourceHandler"); |
326 did_defer_on_writing_ = true; | 338 did_defer_on_writing_ = true; |
327 HoldController(std::move(controller)); | 339 HoldController(std::move(controller)); |
328 return; | 340 return; |
329 } | 341 } |
330 controller->Resume(); | 342 controller->Resume(); |
331 return; | 343 return; |
332 } | 344 } |
333 | 345 |
334 if (EndWrite(bytes_read) != MOJO_RESULT_OK) { | 346 if (EndWrite(bytes_read) != MOJO_RESULT_OK) { |
335 controller->Cancel(); | 347 controller->Cancel(); |
336 return; | 348 return; |
337 } | 349 } |
338 // Allocate a buffer for the next OnWillRead call here, because OnWillRead | |
339 // doesn't have |defer| parameter. | |
340 bool defer = false; | |
341 if (!AllocateWriterIOBuffer(&buffer_, &defer)) { | |
342 controller->Cancel(); | |
343 return; | |
344 } | |
345 if (defer) { | |
346 request()->LogBlockedBy("MojoAsyncResourceHandler"); | |
347 did_defer_on_writing_ = true; | |
348 HoldController(std::move(controller)); | |
349 return; | |
350 } | |
351 | 350 |
351 buffer_ = nullptr; | |
352 controller->Resume(); | 352 controller->Resume(); |
353 } | 353 } |
354 | 354 |
355 void MojoAsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) { | 355 void MojoAsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) { |
356 url_loader_client_->OnDataDownloaded(bytes_downloaded, | 356 url_loader_client_->OnDataDownloaded(bytes_downloaded, |
357 CalculateRecentlyReceivedBytes()); | 357 CalculateRecentlyReceivedBytes()); |
358 } | 358 } |
359 | 359 |
360 void MojoAsyncResourceHandler::FollowRedirect() { | 360 void MojoAsyncResourceHandler::FollowRedirect() { |
361 if (!request()->status().is_success()) { | 361 if (!request()->status().is_success()) { |
362 DVLOG(1) << "FollowRedirect for invalid request"; | 362 DVLOG(1) << "FollowRedirect for invalid request"; |
363 return; | 363 return; |
364 } | 364 } |
365 if (!did_defer_on_redirect_) { | 365 if (!did_defer_on_redirect_) { |
366 DVLOG(1) << "Malformed FollowRedirect request"; | 366 DVLOG(1) << "Malformed FollowRedirect request"; |
367 ReportBadMessage("Malformed FollowRedirect request"); | 367 ReportBadMessage("Malformed FollowRedirect request"); |
368 return; | 368 return; |
369 } | 369 } |
370 | 370 |
371 DCHECK(!did_defer_on_will_read_); | |
371 DCHECK(!did_defer_on_writing_); | 372 DCHECK(!did_defer_on_writing_); |
372 did_defer_on_redirect_ = false; | 373 did_defer_on_redirect_ = false; |
373 request()->LogUnblocked(); | 374 request()->LogUnblocked(); |
374 Resume(); | 375 Resume(); |
375 } | 376 } |
376 | 377 |
377 void MojoAsyncResourceHandler::SetPriority(net::RequestPriority priority, | 378 void MojoAsyncResourceHandler::SetPriority(net::RequestPriority priority, |
378 int32_t intra_priority_value) { | 379 int32_t intra_priority_value) { |
379 ResourceDispatcherHostImpl::Get()->scheduler()->ReprioritizeRequest( | 380 ResourceDispatcherHostImpl::Get()->scheduler()->ReprioritizeRequest( |
380 request(), priority, intra_priority_value); | 381 request(), priority, intra_priority_value); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
447 request_complete_data.completion_time = base::TimeTicks::Now(); | 448 request_complete_data.completion_time = base::TimeTicks::Now(); |
448 request_complete_data.encoded_data_length = | 449 request_complete_data.encoded_data_length = |
449 request()->GetTotalReceivedBytes(); | 450 request()->GetTotalReceivedBytes(); |
450 request_complete_data.encoded_body_length = request()->GetRawBodyBytes(); | 451 request_complete_data.encoded_body_length = request()->GetRawBodyBytes(); |
451 | 452 |
452 url_loader_client_->OnComplete(request_complete_data); | 453 url_loader_client_->OnComplete(request_complete_data); |
453 controller->Resume(); | 454 controller->Resume(); |
454 } | 455 } |
455 | 456 |
456 bool MojoAsyncResourceHandler::CopyReadDataToDataPipe(bool* defer) { | 457 bool MojoAsyncResourceHandler::CopyReadDataToDataPipe(bool* defer) { |
457 while (true) { | 458 while (buffer_bytes_read_ > 0) { |
458 scoped_refptr<net::IOBufferWithSize> dest; | 459 scoped_refptr<net::IOBufferWithSize> dest; |
459 if (!AllocateWriterIOBuffer(&dest, defer)) | 460 if (!AllocateWriterIOBuffer(&dest, defer)) |
460 return false; | 461 return false; |
461 if (*defer) | 462 if (*defer) |
462 return true; | 463 return true; |
463 if (buffer_bytes_read_ == 0) { | |
464 // All bytes are copied. Save the buffer for the next OnWillRead call. | |
465 buffer_ = std::move(dest); | |
466 return true; | |
467 } | |
468 | 464 |
469 size_t copied_size = | 465 size_t copied_size = |
470 std::min(buffer_bytes_read_, static_cast<size_t>(dest->size())); | 466 std::min(buffer_bytes_read_, static_cast<size_t>(dest->size())); |
471 memcpy(dest->data(), buffer_->data() + buffer_offset_, copied_size); | 467 memcpy(dest->data(), buffer_->data() + buffer_offset_, copied_size); |
472 buffer_offset_ += copied_size; | 468 buffer_offset_ += copied_size; |
473 buffer_bytes_read_ -= copied_size; | 469 buffer_bytes_read_ -= copied_size; |
474 if (EndWrite(copied_size) != MOJO_RESULT_OK) | 470 if (EndWrite(copied_size) != MOJO_RESULT_OK) |
475 return false; | 471 return false; |
472 } | |
476 | 473 |
477 if (buffer_bytes_read_ == 0) { | 474 // All bytes are copied. |
478 // All bytes are copied. | 475 buffer_ = nullptr; |
479 buffer_offset_ = 0; | 476 buffer_offset_ = 0; |
480 is_using_io_buffer_not_from_writer_ = false; | 477 is_using_io_buffer_not_from_writer_ = false; |
481 } | 478 return true; |
482 } | |
483 } | 479 } |
484 | 480 |
485 bool MojoAsyncResourceHandler::AllocateWriterIOBuffer( | 481 bool MojoAsyncResourceHandler::AllocateWriterIOBuffer( |
486 scoped_refptr<net::IOBufferWithSize>* buf, | 482 scoped_refptr<net::IOBufferWithSize>* buf, |
487 bool* defer) { | 483 bool* defer) { |
488 void* data = nullptr; | 484 void* data = nullptr; |
489 uint32_t available = 0; | 485 uint32_t available = 0; |
490 MojoResult result = BeginWrite(&data, &available); | 486 MojoResult result = BeginWrite(&data, &available); |
491 if (result == MOJO_RESULT_SHOULD_WAIT) { | 487 if (result == MOJO_RESULT_SHOULD_WAIT) { |
492 *defer = true; | 488 *defer = true; |
493 return true; | 489 return true; |
494 } | 490 } |
495 if (result != MOJO_RESULT_OK) | 491 if (result != MOJO_RESULT_OK) |
496 return false; | 492 return false; |
493 DCHECK_GT(available, 0u); | |
497 *buf = new WriterIOBuffer(shared_writer_, data, available); | 494 *buf = new WriterIOBuffer(shared_writer_, data, available); |
498 return true; | 495 return true; |
499 } | 496 } |
500 | 497 |
501 bool MojoAsyncResourceHandler::CheckForSufficientResource() { | 498 bool MojoAsyncResourceHandler::CheckForSufficientResource() { |
502 if (has_checked_for_sufficient_resources_) | 499 if (has_checked_for_sufficient_resources_) |
503 return true; | 500 return true; |
504 has_checked_for_sufficient_resources_ = true; | 501 has_checked_for_sufficient_resources_ = true; |
505 | 502 |
506 if (rdh_->HasSufficientResourcesForRequest(request())) | 503 if (rdh_->HasSufficientResourcesForRequest(request())) |
507 return true; | 504 return true; |
508 | 505 |
509 return false; | 506 return false; |
510 } | 507 } |
511 | 508 |
512 void MojoAsyncResourceHandler::OnWritable(MojoResult result) { | 509 void MojoAsyncResourceHandler::OnWritable(MojoResult result) { |
510 if (did_defer_on_will_read_) { | |
511 DCHECK(has_controller()); | |
512 DCHECK(!did_defer_on_writing_); | |
513 DCHECK(!did_defer_on_redirect_); | |
514 | |
515 did_defer_on_will_read_ = false; | |
516 | |
517 scoped_refptr<net::IOBuffer>* parent_buffer = parent_buffer_; | |
518 parent_buffer_ = nullptr; | |
519 int* parent_buffer_size = parent_buffer_size_; | |
520 parent_buffer_size_ = nullptr; | |
521 OnWillRead(parent_buffer, parent_buffer_size, ReleaseController()); | |
522 return; | |
523 } | |
524 | |
513 if (!did_defer_on_writing_) | 525 if (!did_defer_on_writing_) |
514 return; | 526 return; |
515 DCHECK(has_controller()); | 527 DCHECK(has_controller()); |
516 DCHECK(!did_defer_on_redirect_); | 528 DCHECK(!did_defer_on_redirect_); |
517 did_defer_on_writing_ = false; | 529 did_defer_on_writing_ = false; |
518 | 530 |
519 if (is_using_io_buffer_not_from_writer_) { | 531 DCHECK(is_using_io_buffer_not_from_writer_); |
520 // |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents | 532 // |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents |
521 // to the data pipe. | 533 // to the data pipe. |
522 DCHECK_GT(buffer_bytes_read_, 0u); | 534 DCHECK_GT(buffer_bytes_read_, 0u); |
523 if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) { | 535 if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) { |
524 CancelWithError(net::ERR_FAILED); | 536 CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
525 return; | 537 return; |
526 } | |
527 } else { | |
528 // Allocate a buffer for the next OnWillRead call here. | |
529 if (!AllocateWriterIOBuffer(&buffer_, &did_defer_on_writing_)) { | |
530 CancelWithError(net::ERR_FAILED); | |
531 return; | |
532 } | |
533 } | 538 } |
534 | 539 |
535 if (did_defer_on_writing_) { | 540 if (did_defer_on_writing_) { |
536 // Continue waiting. | 541 // Continue waiting. |
537 return; | 542 return; |
538 } | 543 } |
539 request()->LogUnblocked(); | 544 request()->LogUnblocked(); |
540 Resume(); | 545 Resume(); |
541 } | 546 } |
542 | 547 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
584 base::Bind(&MojoAsyncResourceHandler::OnUploadProgressACK, | 589 base::Bind(&MojoAsyncResourceHandler::OnUploadProgressACK, |
585 weak_factory_.GetWeakPtr())); | 590 weak_factory_.GetWeakPtr())); |
586 } | 591 } |
587 | 592 |
588 void MojoAsyncResourceHandler::OnUploadProgressACK() { | 593 void MojoAsyncResourceHandler::OnUploadProgressACK() { |
589 if (upload_progress_tracker_) | 594 if (upload_progress_tracker_) |
590 upload_progress_tracker_->OnAckReceived(); | 595 upload_progress_tracker_->OnAckReceived(); |
591 } | 596 } |
592 | 597 |
593 } // namespace content | 598 } // namespace content |
OLD | NEW |