| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/async_resource_handler.h" | 5 #include "content/browser/loader/async_resource_handler.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/containers/hash_tables.h" | 11 #include "base/containers/hash_tables.h" |
| 12 #include "base/debug/alias.h" | 12 #include "base/debug/alias.h" |
| 13 #include "base/feature_list.h" | 13 #include "base/feature_list.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/memory/ptr_util.h" |
| 16 #include "base/memory/shared_memory.h" | 17 #include "base/memory/shared_memory.h" |
| 17 #include "base/metrics/histogram_macros.h" | 18 #include "base/metrics/histogram_macros.h" |
| 18 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
| 19 #include "base/time/time.h" | 20 #include "base/time/time.h" |
| 20 #include "content/browser/loader/netlog_observer.h" | 21 #include "content/browser/loader/netlog_observer.h" |
| 21 #include "content/browser/loader/resource_buffer.h" | 22 #include "content/browser/loader/resource_buffer.h" |
| 22 #include "content/browser/loader/resource_controller.h" | 23 #include "content/browser/loader/resource_controller.h" |
| 23 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 24 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| 24 #include "content/browser/loader/resource_message_filter.h" | 25 #include "content/browser/loader/resource_message_filter.h" |
| 25 #include "content/browser/loader/resource_request_info_impl.h" | 26 #include "content/browser/loader/resource_request_info_impl.h" |
| 27 #include "content/browser/loader/upload_progress_tracker.h" |
| 26 #include "content/common/resource_messages.h" | 28 #include "content/common/resource_messages.h" |
| 27 #include "content/common/resource_request_completion_status.h" | 29 #include "content/common/resource_request_completion_status.h" |
| 28 #include "content/common/view_messages.h" | 30 #include "content/common/view_messages.h" |
| 29 #include "content/public/browser/resource_dispatcher_host_delegate.h" | 31 #include "content/public/browser/resource_dispatcher_host_delegate.h" |
| 30 #include "content/public/common/content_features.h" | 32 #include "content/public/common/content_features.h" |
| 31 #include "content/public/common/resource_response.h" | 33 #include "content/public/common/resource_response.h" |
| 32 #include "ipc/ipc_message_macros.h" | 34 #include "ipc/ipc_message_macros.h" |
| 33 #include "net/base/io_buffer.h" | 35 #include "net/base/io_buffer.h" |
| 34 #include "net/base/load_flags.h" | 36 #include "net/base/load_flags.h" |
| 35 #include "net/url_request/redirect_info.h" | 37 #include "net/url_request/redirect_info.h" |
| 36 | 38 |
| 37 using base::TimeDelta; | 39 using base::TimeDelta; |
| 38 using base::TimeTicks; | 40 using base::TimeTicks; |
| 39 | 41 |
| 40 namespace content { | 42 namespace content { |
| 41 namespace { | 43 namespace { |
| 42 | 44 |
| 43 static int kBufferSize = 1024 * 512; | 45 static int kBufferSize = 1024 * 512; |
| 44 static int kMinAllocationSize = 1024 * 4; | 46 static int kMinAllocationSize = 1024 * 4; |
| 45 static int kMaxAllocationSize = 1024 * 32; | 47 static int kMaxAllocationSize = 1024 * 32; |
| 46 // The interval for calls to ReportUploadProgress. | |
| 47 static int kUploadProgressIntervalMsec = 100; | |
| 48 | 48 |
| 49 // Used when kOptimizeLoadingIPCForSmallResources is enabled. | 49 // Used when kOptimizeLoadingIPCForSmallResources is enabled. |
| 50 // Small resource typically issues two Read call: one for the content itself | 50 // Small resource typically issues two Read call: one for the content itself |
| 51 // and another for getting zero response to detect EOF. | 51 // and another for getting zero response to detect EOF. |
| 52 // Inline these two into the IPC message to avoid allocating an expensive | 52 // Inline these two into the IPC message to avoid allocating an expensive |
| 53 // SharedMemory for small resources. | 53 // SharedMemory for small resources. |
| 54 const int kNumLeadingChunk = 2; | 54 const int kNumLeadingChunk = 2; |
| 55 const int kInlinedLeadingChunkSize = 2048; | 55 const int kInlinedLeadingChunkSize = 2048; |
| 56 | 56 |
| 57 void GetNumericArg(const std::string& name, int* result) { | 57 void GetNumericArg(const std::string& name, int* result) { |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 : ResourceHandler(request), | 197 : ResourceHandler(request), |
| 198 ResourceMessageDelegate(request), | 198 ResourceMessageDelegate(request), |
| 199 rdh_(rdh), | 199 rdh_(rdh), |
| 200 pending_data_count_(0), | 200 pending_data_count_(0), |
| 201 allocation_size_(0), | 201 allocation_size_(0), |
| 202 did_defer_(false), | 202 did_defer_(false), |
| 203 has_checked_for_sufficient_resources_(false), | 203 has_checked_for_sufficient_resources_(false), |
| 204 sent_received_response_msg_(false), | 204 sent_received_response_msg_(false), |
| 205 sent_data_buffer_msg_(false), | 205 sent_data_buffer_msg_(false), |
| 206 inlining_helper_(new InliningHelper), | 206 inlining_helper_(new InliningHelper), |
| 207 last_upload_position_(0), | |
| 208 waiting_for_upload_progress_ack_(false), | |
| 209 reported_transfer_size_(0) { | 207 reported_transfer_size_(0) { |
| 210 DCHECK(GetRequestInfo()->requester_info()->IsRenderer()); | 208 DCHECK(GetRequestInfo()->requester_info()->IsRenderer()); |
| 211 InitializeResourceBufferConstants(); | 209 InitializeResourceBufferConstants(); |
| 212 } | 210 } |
| 213 | 211 |
| 214 AsyncResourceHandler::~AsyncResourceHandler() { | 212 AsyncResourceHandler::~AsyncResourceHandler() { |
| 215 if (has_checked_for_sufficient_resources_) | 213 if (has_checked_for_sufficient_resources_) |
| 216 rdh_->FinishedWithResourcesForRequest(request()); | 214 rdh_->FinishedWithResourcesForRequest(request()); |
| 217 } | 215 } |
| 218 | 216 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 240 if (pending_data_count_) { | 238 if (pending_data_count_) { |
| 241 --pending_data_count_; | 239 --pending_data_count_; |
| 242 | 240 |
| 243 buffer_->RecycleLeastRecentlyAllocated(); | 241 buffer_->RecycleLeastRecentlyAllocated(); |
| 244 if (buffer_->CanAllocate()) | 242 if (buffer_->CanAllocate()) |
| 245 ResumeIfDeferred(); | 243 ResumeIfDeferred(); |
| 246 } | 244 } |
| 247 } | 245 } |
| 248 | 246 |
| 249 void AsyncResourceHandler::OnUploadProgressACK(int request_id) { | 247 void AsyncResourceHandler::OnUploadProgressACK(int request_id) { |
| 250 waiting_for_upload_progress_ack_ = false; | 248 if (upload_progress_tracker_) |
| 251 } | 249 upload_progress_tracker_->OnAckReceived(); |
| 252 | |
| 253 void AsyncResourceHandler::ReportUploadProgress() { | |
| 254 DCHECK(GetRequestInfo()->is_upload_progress_enabled()); | |
| 255 if (waiting_for_upload_progress_ack_) | |
| 256 return; // Send one progress event at a time. | |
| 257 | |
| 258 net::UploadProgress progress = request()->GetUploadProgress(); | |
| 259 if (!progress.size()) | |
| 260 return; // Nothing to upload. | |
| 261 | |
| 262 if (progress.position() == last_upload_position_) | |
| 263 return; // No progress made since last time. | |
| 264 | |
| 265 const uint64_t kHalfPercentIncrements = 200; | |
| 266 const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000); | |
| 267 | |
| 268 uint64_t amt_since_last = progress.position() - last_upload_position_; | |
| 269 TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_; | |
| 270 | |
| 271 bool is_finished = (progress.size() == progress.position()); | |
| 272 bool enough_new_progress = | |
| 273 (amt_since_last > (progress.size() / kHalfPercentIncrements)); | |
| 274 bool too_much_time_passed = time_since_last > kOneSecond; | |
| 275 | |
| 276 if (is_finished || enough_new_progress || too_much_time_passed) { | |
| 277 ResourceMessageFilter* filter = GetFilter(); | |
| 278 if (filter) { | |
| 279 filter->Send( | |
| 280 new ResourceMsg_UploadProgress(GetRequestID(), | |
| 281 progress.position(), | |
| 282 progress.size())); | |
| 283 } | |
| 284 waiting_for_upload_progress_ack_ = true; | |
| 285 last_upload_ticks_ = TimeTicks::Now(); | |
| 286 last_upload_position_ = progress.position(); | |
| 287 } | |
| 288 } | 250 } |
| 289 | 251 |
| 290 bool AsyncResourceHandler::OnRequestRedirected( | 252 bool AsyncResourceHandler::OnRequestRedirected( |
| 291 const net::RedirectInfo& redirect_info, | 253 const net::RedirectInfo& redirect_info, |
| 292 ResourceResponse* response, | 254 ResourceResponse* response, |
| 293 bool* defer) { | 255 bool* defer) { |
| 294 ResourceMessageFilter* filter = GetFilter(); | 256 ResourceMessageFilter* filter = GetFilter(); |
| 295 if (!filter) | 257 if (!filter) |
| 296 return false; | 258 return false; |
| 297 | 259 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 314 bool AsyncResourceHandler::OnResponseStarted(ResourceResponse* response, | 276 bool AsyncResourceHandler::OnResponseStarted(ResourceResponse* response, |
| 315 bool* defer) { | 277 bool* defer) { |
| 316 // For changes to the main frame, inform the renderer of the new URL's | 278 // For changes to the main frame, inform the renderer of the new URL's |
| 317 // per-host settings before the request actually commits. This way the | 279 // per-host settings before the request actually commits. This way the |
| 318 // renderer will be able to set these precisely at the time the | 280 // renderer will be able to set these precisely at the time the |
| 319 // request commits, avoiding the possibility of e.g. zooming the old content | 281 // request commits, avoiding the possibility of e.g. zooming the old content |
| 320 // or of having to layout the new content twice. | 282 // or of having to layout the new content twice. |
| 321 | 283 |
| 322 response_started_ticks_ = base::TimeTicks::Now(); | 284 response_started_ticks_ = base::TimeTicks::Now(); |
| 323 | 285 |
| 324 progress_timer_.Stop(); | |
| 325 ResourceMessageFilter* filter = GetFilter(); | |
| 326 if (!filter) | |
| 327 return false; | |
| 328 | |
| 329 const ResourceRequestInfoImpl* info = GetRequestInfo(); | |
| 330 // We want to send a final upload progress message prior to sending the | 286 // We want to send a final upload progress message prior to sending the |
| 331 // response complete message even if we're waiting for an ack to to a | 287 // response complete message even if we're waiting for an ack to to a |
| 332 // previous upload progress message. | 288 // previous upload progress message. |
| 333 if (info->is_upload_progress_enabled()) { | 289 if (upload_progress_tracker_) { |
| 334 waiting_for_upload_progress_ack_ = false; | 290 upload_progress_tracker_->OnUploadCompleted(); |
| 335 ReportUploadProgress(); | 291 upload_progress_tracker_ = nullptr; |
| 336 } | 292 } |
| 337 | 293 |
| 294 const ResourceRequestInfoImpl* info = GetRequestInfo(); |
| 338 if (rdh_->delegate()) { | 295 if (rdh_->delegate()) { |
| 339 rdh_->delegate()->OnResponseStarted(request(), info->GetContext(), | 296 rdh_->delegate()->OnResponseStarted(request(), info->GetContext(), |
| 340 response); | 297 response); |
| 341 } | 298 } |
| 342 | 299 |
| 300 ResourceMessageFilter* filter = GetFilter(); |
| 301 if (!filter) |
| 302 return false; |
| 303 |
| 343 NetLogObserver::PopulateResponseInfo(request(), response); | 304 NetLogObserver::PopulateResponseInfo(request(), response); |
| 344 response->head.encoded_data_length = request()->raw_header_size(); | 305 response->head.encoded_data_length = request()->raw_header_size(); |
| 345 | 306 |
| 346 // If the parent handler downloaded the resource to a file, grant the child | 307 // If the parent handler downloaded the resource to a file, grant the child |
| 347 // read permissions on it. | 308 // read permissions on it. |
| 348 if (!response->head.download_file_path.empty()) { | 309 if (!response->head.download_file_path.empty()) { |
| 349 rdh_->RegisterDownloadedTempFile( | 310 rdh_->RegisterDownloadedTempFile( |
| 350 info->GetChildID(), info->GetRequestID(), | 311 info->GetChildID(), info->GetRequestID(), |
| 351 response->head.download_file_path); | 312 response->head.download_file_path); |
| 352 } | 313 } |
| 353 | 314 |
| 354 response->head.request_start = request()->creation_time(); | 315 response->head.request_start = request()->creation_time(); |
| 355 response->head.response_start = TimeTicks::Now(); | 316 response->head.response_start = TimeTicks::Now(); |
| 356 filter->Send( | 317 filter->Send( |
| 357 new ResourceMsg_ReceivedResponse(GetRequestID(), response->head)); | 318 new ResourceMsg_ReceivedResponse(GetRequestID(), response->head)); |
| 358 sent_received_response_msg_ = true; | 319 sent_received_response_msg_ = true; |
| 359 | 320 |
| 360 if (request()->response_info().metadata.get()) { | 321 if (request()->response_info().metadata.get()) { |
| 361 std::vector<char> copy(request()->response_info().metadata->data(), | 322 std::vector<char> copy(request()->response_info().metadata->data(), |
| 362 request()->response_info().metadata->data() + | 323 request()->response_info().metadata->data() + |
| 363 request()->response_info().metadata->size()); | 324 request()->response_info().metadata->size()); |
| 364 filter->Send(new ResourceMsg_ReceivedCachedMetadata(GetRequestID(), copy)); | 325 filter->Send(new ResourceMsg_ReceivedCachedMetadata(GetRequestID(), copy)); |
| 365 } | 326 } |
| 366 | 327 |
| 367 inlining_helper_->OnResponseReceived(*response); | 328 inlining_helper_->OnResponseReceived(*response); |
| 368 return true; | 329 return true; |
| 369 } | 330 } |
| 370 | 331 |
| 371 bool AsyncResourceHandler::OnWillStart(const GURL& url, bool* defer) { | 332 bool AsyncResourceHandler::OnWillStart(const GURL& url, bool* defer) { |
| 333 ResourceMessageFilter* filter = GetFilter(); |
| 334 if (!filter) |
| 335 return false; |
| 336 |
| 372 if (GetRequestInfo()->is_upload_progress_enabled() && | 337 if (GetRequestInfo()->is_upload_progress_enabled() && |
| 373 request()->has_upload()) { | 338 request()->has_upload()) { |
| 374 ReportUploadProgress(); | 339 upload_progress_tracker_ = base::MakeUnique<UploadProgressTracker>( |
| 375 progress_timer_.Start( | |
| 376 FROM_HERE, | 340 FROM_HERE, |
| 377 base::TimeDelta::FromMilliseconds(kUploadProgressIntervalMsec), | 341 base::BindRepeating(&AsyncResourceHandler::SendUploadProgress, |
| 378 this, | 342 base::Unretained(this)), |
| 379 &AsyncResourceHandler::ReportUploadProgress); | 343 request()); |
| 380 } | 344 } |
| 381 return true; | 345 return true; |
| 382 } | 346 } |
| 383 | 347 |
| 384 bool AsyncResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, | 348 bool AsyncResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, |
| 385 int* buf_size, | 349 int* buf_size, |
| 386 int min_size) { | 350 int min_size) { |
| 387 DCHECK_EQ(-1, min_size); | 351 DCHECK_EQ(-1, min_size); |
| 388 | 352 |
| 389 if (!CheckForSufficientResource()) | 353 if (!CheckForSufficientResource()) |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 466 } | 430 } |
| 467 } | 431 } |
| 468 | 432 |
| 469 void AsyncResourceHandler::OnResponseCompleted( | 433 void AsyncResourceHandler::OnResponseCompleted( |
| 470 const net::URLRequestStatus& status, | 434 const net::URLRequestStatus& status, |
| 471 bool* defer) { | 435 bool* defer) { |
| 472 ResourceMessageFilter* filter = GetFilter(); | 436 ResourceMessageFilter* filter = GetFilter(); |
| 473 if (!filter) | 437 if (!filter) |
| 474 return; | 438 return; |
| 475 | 439 |
| 440 // Ensure sending the final upload progress message here, since |
| 441 // OnResponseCompleted can be called without OnResponseStarted on cancellation |
| 442 // or error cases. |
| 443 if (upload_progress_tracker_) { |
| 444 upload_progress_tracker_->OnUploadCompleted(); |
| 445 upload_progress_tracker_ = nullptr; |
| 446 } |
| 447 |
| 476 // If we crash here, figure out what URL the renderer was requesting. | 448 // If we crash here, figure out what URL the renderer was requesting. |
| 477 // http://crbug.com/107692 | 449 // http://crbug.com/107692 |
| 478 char url_buf[128]; | 450 char url_buf[128]; |
| 479 base::strlcpy(url_buf, request()->url().spec().c_str(), arraysize(url_buf)); | 451 base::strlcpy(url_buf, request()->url().spec().c_str(), arraysize(url_buf)); |
| 480 base::debug::Alias(url_buf); | 452 base::debug::Alias(url_buf); |
| 481 | 453 |
| 482 // TODO(gavinp): Remove this CHECK when we figure out the cause of | 454 // TODO(gavinp): Remove this CHECK when we figure out the cause of |
| 483 // http://crbug.com/124680 . This check mirrors closely check in | 455 // http://crbug.com/124680 . This check mirrors closely check in |
| 484 // WebURLLoaderImpl::OnCompletedRequest that routes this message to a WebCore | 456 // WebURLLoaderImpl::OnCompletedRequest that routes this message to a WebCore |
| 485 // ResourceHandleInternal which asserts on its state and crashes. By crashing | 457 // ResourceHandleInternal which asserts on its state and crashes. By crashing |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 elapsed_time, 1, 100000, 100); | 546 elapsed_time, 1, 100000, 100); |
| 575 } else { | 547 } else { |
| 576 UMA_HISTOGRAM_CUSTOM_COUNTS( | 548 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 577 "Net.ResourceLoader.ResponseStartToEnd.Over_512kB", | 549 "Net.ResourceLoader.ResponseStartToEnd.Over_512kB", |
| 578 elapsed_time, 1, 100000, 100); | 550 elapsed_time, 1, 100000, 100); |
| 579 } | 551 } |
| 580 | 552 |
| 581 inlining_helper_->RecordHistogram(elapsed_time); | 553 inlining_helper_->RecordHistogram(elapsed_time); |
| 582 } | 554 } |
| 583 | 555 |
| 556 void AsyncResourceHandler::SendUploadProgress(int64_t current_position, |
| 557 int64_t total_size) { |
| 558 ResourceMessageFilter* filter = GetFilter(); |
| 559 if (!filter) |
| 560 return; |
| 561 filter->Send(new ResourceMsg_UploadProgress( |
| 562 GetRequestID(), current_position, total_size)); |
| 563 } |
| 564 |
| 584 } // namespace content | 565 } // namespace content |
| OLD | NEW |