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 10 matching lines...) Expand all Loading... |
21 #include "content/browser/loader/resource_controller.h" | 21 #include "content/browser/loader/resource_controller.h" |
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/common/resource_response.h" | 28 #include "content/public/common/resource_response.h" |
29 #include "mojo/public/c/system/data_pipe.h" | 29 #include "mojo/public/c/system/data_pipe.h" |
30 #include "mojo/public/cpp/bindings/message.h" | 30 #include "mojo/public/cpp/bindings/message.h" |
31 #include "net/base/mime_sniffer.h" | |
32 #include "net/base/net_errors.h" | 31 #include "net/base/net_errors.h" |
33 #include "net/url_request/redirect_info.h" | 32 #include "net/url_request/redirect_info.h" |
34 | 33 |
35 namespace content { | 34 namespace content { |
36 namespace { | 35 namespace { |
37 | 36 |
38 int g_allocation_size = MojoAsyncResourceHandler::kDefaultAllocationSize; | 37 int g_allocation_size = MojoAsyncResourceHandler::kDefaultAllocationSize; |
39 | 38 |
40 // MimeTypeResourceHandler *implicitly* requires that the buffer size | |
41 // returned from OnWillRead should be larger than certain size. | |
42 // TODO(yhirano): Fix MimeTypeResourceHandler. | |
43 constexpr size_t kMinAllocationSize = 2 * net::kMaxBytesToSniff; | |
44 | |
45 constexpr size_t kMaxChunkSize = 32 * 1024; | 39 constexpr size_t kMaxChunkSize = 32 * 1024; |
46 | 40 |
47 void GetNumericArg(const std::string& name, int* result) { | 41 void GetNumericArg(const std::string& name, int* result) { |
48 const std::string& value = | 42 const std::string& value = |
49 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name); | 43 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name); |
50 if (!value.empty()) | 44 if (!value.empty()) |
51 base::StringToInt(value, result); | 45 base::StringToInt(value, result); |
52 } | 46 } |
53 | 47 |
54 void InitializeResourceBufferConstants() { | 48 void InitializeResourceBufferConstants() { |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 // final 0-byte read, so this DCHECK will also catch OnWillRead being called | 225 // final 0-byte read, so this DCHECK will also catch OnWillRead being called |
232 // after OnReadCompelted(0)). | 226 // after OnReadCompelted(0)). |
233 DCHECK(!buffer_); | 227 DCHECK(!buffer_); |
234 DCHECK_EQ(0u, buffer_offset_); | 228 DCHECK_EQ(0u, buffer_offset_); |
235 | 229 |
236 if (!CheckForSufficientResource()) { | 230 if (!CheckForSufficientResource()) { |
237 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); | 231 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); |
238 return; | 232 return; |
239 } | 233 } |
240 | 234 |
241 bool first_call = false; | |
242 if (!shared_writer_) { | 235 if (!shared_writer_) { |
243 first_call = true; | |
244 MojoCreateDataPipeOptions options; | 236 MojoCreateDataPipeOptions options; |
245 options.struct_size = sizeof(MojoCreateDataPipeOptions); | 237 options.struct_size = sizeof(MojoCreateDataPipeOptions); |
246 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; | 238 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; |
247 options.element_num_bytes = 1; | 239 options.element_num_bytes = 1; |
248 options.capacity_num_bytes = g_allocation_size; | 240 options.capacity_num_bytes = g_allocation_size; |
249 mojo::DataPipe data_pipe(options); | 241 mojo::DataPipe data_pipe(options); |
250 | 242 |
251 DCHECK(data_pipe.producer_handle.is_valid()); | 243 DCHECK(data_pipe.producer_handle.is_valid()); |
252 DCHECK(data_pipe.consumer_handle.is_valid()); | 244 DCHECK(data_pipe.consumer_handle.is_valid()); |
253 | 245 |
(...skipping 14 matching lines...) Expand all Loading... |
268 if (defer) { | 260 if (defer) { |
269 DCHECK(!buffer_); | 261 DCHECK(!buffer_); |
270 parent_buffer_ = buf; | 262 parent_buffer_ = buf; |
271 parent_buffer_size_ = buf_size; | 263 parent_buffer_size_ = buf_size; |
272 HoldController(std::move(controller)); | 264 HoldController(std::move(controller)); |
273 request()->LogBlockedBy("MojoAsyncResourceHandler"); | 265 request()->LogBlockedBy("MojoAsyncResourceHandler"); |
274 did_defer_on_will_read_ = true; | 266 did_defer_on_will_read_ = true; |
275 return; | 267 return; |
276 } | 268 } |
277 | 269 |
278 // The first call to OnWillRead must return a buffer of at least | |
279 // kMinAllocationSize. If the Mojo buffer is too small, need to allocate an | |
280 // intermediary buffer. | |
281 if (first_call && static_cast<size_t>(buffer_->size()) < kMinAllocationSize) { | |
282 // The allocated buffer is too small, so need to create an intermediary one. | |
283 if (EndWrite(0) != MOJO_RESULT_OK) { | |
284 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); | |
285 return; | |
286 } | |
287 DCHECK(!is_using_io_buffer_not_from_writer_); | |
288 is_using_io_buffer_not_from_writer_ = true; | |
289 buffer_ = new net::IOBufferWithSize(kMinAllocationSize); | |
290 } | |
291 | |
292 *buf = buffer_; | 270 *buf = buffer_; |
293 *buf_size = buffer_->size(); | 271 *buf_size = buffer_->size(); |
294 controller->Resume(); | 272 controller->Resume(); |
295 } | 273 } |
296 | 274 |
297 void MojoAsyncResourceHandler::OnReadCompleted( | 275 void MojoAsyncResourceHandler::OnReadCompleted( |
298 int bytes_read, | 276 int bytes_read, |
299 std::unique_ptr<ResourceController> controller) { | 277 std::unique_ptr<ResourceController> controller) { |
300 DCHECK(!has_controller()); | 278 DCHECK(!has_controller()); |
301 DCHECK_GE(bytes_read, 0); | 279 DCHECK_GE(bytes_read, 0); |
(...skipping 13 matching lines...) Expand all Loading... |
315 url_loader_client_->OnTransferSizeUpdated(transfer_size_diff); | 293 url_loader_client_->OnTransferSizeUpdated(transfer_size_diff); |
316 } | 294 } |
317 | 295 |
318 if (response_body_consumer_handle_.is_valid()) { | 296 if (response_body_consumer_handle_.is_valid()) { |
319 // Send the data pipe on the first OnReadCompleted call. | 297 // Send the data pipe on the first OnReadCompleted call. |
320 url_loader_client_->OnStartLoadingResponseBody( | 298 url_loader_client_->OnStartLoadingResponseBody( |
321 std::move(response_body_consumer_handle_)); | 299 std::move(response_body_consumer_handle_)); |
322 response_body_consumer_handle_.reset(); | 300 response_body_consumer_handle_.reset(); |
323 } | 301 } |
324 | 302 |
325 if (is_using_io_buffer_not_from_writer_) { | |
326 // Couldn't allocate a large enough buffer on the data pipe in OnWillRead. | |
327 DCHECK_EQ(0u, buffer_bytes_read_); | |
328 buffer_bytes_read_ = bytes_read; | |
329 bool defer = false; | |
330 if (!CopyReadDataToDataPipe(&defer)) { | |
331 controller->CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); | |
332 return; | |
333 } | |
334 if (defer) { | |
335 request()->LogBlockedBy("MojoAsyncResourceHandler"); | |
336 did_defer_on_writing_ = true; | |
337 HoldController(std::move(controller)); | |
338 return; | |
339 } | |
340 controller->Resume(); | |
341 return; | |
342 } | |
343 | |
344 if (EndWrite(bytes_read) != MOJO_RESULT_OK) { | 303 if (EndWrite(bytes_read) != MOJO_RESULT_OK) { |
345 controller->Cancel(); | 304 controller->Cancel(); |
346 return; | 305 return; |
347 } | 306 } |
348 | 307 |
349 buffer_ = nullptr; | 308 buffer_ = nullptr; |
350 controller->Resume(); | 309 controller->Resume(); |
351 } | 310 } |
352 | 311 |
353 void MojoAsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) { | 312 void MojoAsyncResourceHandler::OnDataDownloaded(int bytes_downloaded) { |
354 url_loader_client_->OnDataDownloaded(bytes_downloaded, | 313 url_loader_client_->OnDataDownloaded(bytes_downloaded, |
355 CalculateRecentlyReceivedBytes()); | 314 CalculateRecentlyReceivedBytes()); |
356 } | 315 } |
357 | 316 |
358 void MojoAsyncResourceHandler::FollowRedirect() { | 317 void MojoAsyncResourceHandler::FollowRedirect() { |
359 if (!request()->status().is_success()) { | 318 if (!request()->status().is_success()) { |
360 DVLOG(1) << "FollowRedirect for invalid request"; | 319 DVLOG(1) << "FollowRedirect for invalid request"; |
361 return; | 320 return; |
362 } | 321 } |
363 if (!did_defer_on_redirect_) { | 322 if (!did_defer_on_redirect_) { |
364 DVLOG(1) << "Malformed FollowRedirect request"; | 323 DVLOG(1) << "Malformed FollowRedirect request"; |
365 ReportBadMessage("Malformed FollowRedirect request"); | 324 ReportBadMessage("Malformed FollowRedirect request"); |
366 return; | 325 return; |
367 } | 326 } |
368 | 327 |
369 DCHECK(!did_defer_on_will_read_); | 328 DCHECK(!did_defer_on_will_read_); |
370 DCHECK(!did_defer_on_writing_); | |
371 did_defer_on_redirect_ = false; | 329 did_defer_on_redirect_ = false; |
372 request()->LogUnblocked(); | 330 request()->LogUnblocked(); |
373 Resume(); | 331 Resume(); |
374 } | 332 } |
375 | 333 |
376 void MojoAsyncResourceHandler::SetPriority(net::RequestPriority priority, | 334 void MojoAsyncResourceHandler::SetPriority(net::RequestPriority priority, |
377 int32_t intra_priority_value) { | 335 int32_t intra_priority_value) { |
378 ResourceDispatcherHostImpl::Get()->scheduler()->ReprioritizeRequest( | 336 ResourceDispatcherHostImpl::Get()->scheduler()->ReprioritizeRequest( |
379 request(), priority, intra_priority_value); | 337 request(), priority, intra_priority_value); |
380 } | 338 } |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 request_complete_data.exists_in_cache = request()->response_info().was_cached; | 408 request_complete_data.exists_in_cache = request()->response_info().was_cached; |
451 request_complete_data.completion_time = base::TimeTicks::Now(); | 409 request_complete_data.completion_time = base::TimeTicks::Now(); |
452 request_complete_data.encoded_data_length = | 410 request_complete_data.encoded_data_length = |
453 request()->GetTotalReceivedBytes(); | 411 request()->GetTotalReceivedBytes(); |
454 request_complete_data.encoded_body_length = request()->GetRawBodyBytes(); | 412 request_complete_data.encoded_body_length = request()->GetRawBodyBytes(); |
455 | 413 |
456 url_loader_client_->OnComplete(request_complete_data); | 414 url_loader_client_->OnComplete(request_complete_data); |
457 controller->Resume(); | 415 controller->Resume(); |
458 } | 416 } |
459 | 417 |
460 bool MojoAsyncResourceHandler::CopyReadDataToDataPipe(bool* defer) { | |
461 while (buffer_bytes_read_ > 0) { | |
462 scoped_refptr<net::IOBufferWithSize> dest; | |
463 if (!AllocateWriterIOBuffer(&dest, defer)) | |
464 return false; | |
465 if (*defer) | |
466 return true; | |
467 | |
468 size_t copied_size = | |
469 std::min(buffer_bytes_read_, static_cast<size_t>(dest->size())); | |
470 memcpy(dest->data(), buffer_->data() + buffer_offset_, copied_size); | |
471 buffer_offset_ += copied_size; | |
472 buffer_bytes_read_ -= copied_size; | |
473 if (EndWrite(copied_size) != MOJO_RESULT_OK) | |
474 return false; | |
475 } | |
476 | |
477 // All bytes are copied. | |
478 buffer_ = nullptr; | |
479 buffer_offset_ = 0; | |
480 is_using_io_buffer_not_from_writer_ = false; | |
481 return true; | |
482 } | |
483 | |
484 bool MojoAsyncResourceHandler::AllocateWriterIOBuffer( | 418 bool MojoAsyncResourceHandler::AllocateWriterIOBuffer( |
485 scoped_refptr<net::IOBufferWithSize>* buf, | 419 scoped_refptr<net::IOBufferWithSize>* buf, |
486 bool* defer) { | 420 bool* defer) { |
487 void* data = nullptr; | 421 void* data = nullptr; |
488 uint32_t available = 0; | 422 uint32_t available = 0; |
489 MojoResult result = BeginWrite(&data, &available); | 423 MojoResult result = BeginWrite(&data, &available); |
490 if (result == MOJO_RESULT_SHOULD_WAIT) { | 424 if (result == MOJO_RESULT_SHOULD_WAIT) { |
491 *defer = true; | 425 *defer = true; |
492 return true; | 426 return true; |
493 } | 427 } |
494 if (result != MOJO_RESULT_OK) | 428 if (result != MOJO_RESULT_OK) |
495 return false; | 429 return false; |
496 DCHECK_GT(available, 0u); | 430 DCHECK_GT(available, 0u); |
497 *buf = new WriterIOBuffer(shared_writer_, data, available); | 431 *buf = new WriterIOBuffer(shared_writer_, data, available); |
498 return true; | 432 return true; |
499 } | 433 } |
500 | 434 |
501 bool MojoAsyncResourceHandler::CheckForSufficientResource() { | 435 bool MojoAsyncResourceHandler::CheckForSufficientResource() { |
502 if (has_checked_for_sufficient_resources_) | 436 if (has_checked_for_sufficient_resources_) |
503 return true; | 437 return true; |
504 has_checked_for_sufficient_resources_ = true; | 438 has_checked_for_sufficient_resources_ = true; |
505 | 439 |
506 if (rdh_->HasSufficientResourcesForRequest(request())) | 440 if (rdh_->HasSufficientResourcesForRequest(request())) |
507 return true; | 441 return true; |
508 | 442 |
509 return false; | 443 return false; |
510 } | 444 } |
511 | 445 |
512 void MojoAsyncResourceHandler::OnWritable(MojoResult result) { | 446 void MojoAsyncResourceHandler::OnWritable(MojoResult result) { |
513 if (did_defer_on_will_read_) { | 447 if (!did_defer_on_will_read_) |
514 DCHECK(has_controller()); | 448 return; |
515 DCHECK(!did_defer_on_writing_); | |
516 DCHECK(!did_defer_on_redirect_); | |
517 | 449 |
518 did_defer_on_will_read_ = false; | |
519 | |
520 scoped_refptr<net::IOBuffer>* parent_buffer = parent_buffer_; | |
521 parent_buffer_ = nullptr; | |
522 int* parent_buffer_size = parent_buffer_size_; | |
523 parent_buffer_size_ = nullptr; | |
524 | |
525 request()->LogUnblocked(); | |
526 OnWillRead(parent_buffer, parent_buffer_size, ReleaseController()); | |
527 return; | |
528 } | |
529 | |
530 if (!did_defer_on_writing_) | |
531 return; | |
532 DCHECK(has_controller()); | 450 DCHECK(has_controller()); |
533 DCHECK(!did_defer_on_redirect_); | 451 DCHECK(!did_defer_on_redirect_); |
534 did_defer_on_writing_ = false; | |
535 | 452 |
536 DCHECK(is_using_io_buffer_not_from_writer_); | 453 did_defer_on_will_read_ = false; |
537 // |buffer_| is set to a net::IOBufferWithSize. Write the buffer contents | |
538 // to the data pipe. | |
539 DCHECK_GT(buffer_bytes_read_, 0u); | |
540 if (!CopyReadDataToDataPipe(&did_defer_on_writing_)) { | |
541 CancelWithError(net::ERR_INSUFFICIENT_RESOURCES); | |
542 return; | |
543 } | |
544 | 454 |
545 if (did_defer_on_writing_) { | 455 scoped_refptr<net::IOBuffer>* parent_buffer = parent_buffer_; |
546 // Continue waiting. | 456 parent_buffer_ = nullptr; |
547 return; | 457 int* parent_buffer_size = parent_buffer_size_; |
548 } | 458 parent_buffer_size_ = nullptr; |
| 459 |
549 request()->LogUnblocked(); | 460 request()->LogUnblocked(); |
550 Resume(); | 461 OnWillRead(parent_buffer, parent_buffer_size, ReleaseController()); |
551 } | 462 } |
552 | 463 |
553 void MojoAsyncResourceHandler::Cancel() { | 464 void MojoAsyncResourceHandler::Cancel() { |
554 const ResourceRequestInfoImpl* info = GetRequestInfo(); | 465 const ResourceRequestInfoImpl* info = GetRequestInfo(); |
555 ResourceDispatcherHostImpl::Get()->CancelRequestFromRenderer( | 466 ResourceDispatcherHostImpl::Get()->CancelRequestFromRenderer( |
556 GlobalRequestID(info->GetChildID(), info->GetRequestID())); | 467 GlobalRequestID(info->GetChildID(), info->GetRequestID())); |
557 } | 468 } |
558 | 469 |
559 int64_t MojoAsyncResourceHandler::CalculateRecentlyReceivedBytes() { | 470 int64_t MojoAsyncResourceHandler::CalculateRecentlyReceivedBytes() { |
560 int64_t total_received_bytes = request()->GetTotalReceivedBytes(); | 471 int64_t total_received_bytes = request()->GetTotalReceivedBytes(); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
594 base::Bind(&MojoAsyncResourceHandler::OnUploadProgressACK, | 505 base::Bind(&MojoAsyncResourceHandler::OnUploadProgressACK, |
595 weak_factory_.GetWeakPtr())); | 506 weak_factory_.GetWeakPtr())); |
596 } | 507 } |
597 | 508 |
598 void MojoAsyncResourceHandler::OnUploadProgressACK() { | 509 void MojoAsyncResourceHandler::OnUploadProgressACK() { |
599 if (upload_progress_tracker_) | 510 if (upload_progress_tracker_) |
600 upload_progress_tracker_->OnAckReceived(); | 511 upload_progress_tracker_->OnAckReceived(); |
601 } | 512 } |
602 | 513 |
603 } // namespace content | 514 } // namespace content |
OLD | NEW |