Chromium Code Reviews| Index: content/browser/loader/async_resource_handler.cc |
| diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc |
| index f0268e71d5f1a6457e8e1b07103a08774e4588c3..2eace36852ea9a048c8a6dd6f77135619b42752a 100644 |
| --- a/content/browser/loader/async_resource_handler.cc |
| +++ b/content/browser/loader/async_resource_handler.cc |
| @@ -32,6 +32,7 @@ |
| #include "net/log/net_log.h" |
| #include "net/url_request/redirect_info.h" |
| +using base::TimeDelta; |
| using base::TimeTicks; |
| namespace content { |
| @@ -40,6 +41,8 @@ namespace { |
| static int kBufferSize = 1024 * 512; |
| static int kMinAllocationSize = 1024 * 4; |
| static int kMaxAllocationSize = 1024 * 32; |
| +// The interval for calls to ReportUploadProgress. |
| +static int kUploadProgressIntervalMsec = 10; |
| void GetNumericArg(const std::string& name, int* result) { |
| const std::string& value = |
| @@ -84,6 +87,8 @@ AsyncResourceHandler::AsyncResourceHandler( |
| has_checked_for_sufficient_resources_(false), |
| sent_received_response_msg_(false), |
| sent_first_data_msg_(false), |
| + last_upload_position_(0), |
| + waiting_for_upload_progress_ack_(false), |
| reported_transfer_size_(0) { |
| InitializeResourceBufferConstants(); |
| } |
| @@ -98,6 +103,7 @@ bool AsyncResourceHandler::OnMessageReceived(const IPC::Message& message) { |
| IPC_BEGIN_MESSAGE_MAP(AsyncResourceHandler, message) |
| IPC_MESSAGE_HANDLER(ResourceHostMsg_FollowRedirect, OnFollowRedirect) |
| IPC_MESSAGE_HANDLER(ResourceHostMsg_DataReceived_ACK, OnDataReceivedACK) |
| + IPC_MESSAGE_HANDLER(ResourceHostMsg_UploadProgress_ACK, OnUploadProgressACK) |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| return handled; |
| @@ -122,13 +128,45 @@ void AsyncResourceHandler::OnDataReceivedACK(int request_id) { |
| } |
| } |
| -bool AsyncResourceHandler::OnUploadProgress(uint64 position, |
| - uint64 size) { |
| - ResourceMessageFilter* filter = GetFilter(); |
| - if (!filter) |
| - return false; |
| - return filter->Send( |
| - new ResourceMsg_UploadProgress(GetRequestID(), position, size)); |
| +void AsyncResourceHandler::OnUploadProgressACK(int request_id) { |
| + waiting_for_upload_progress_ack_ = false; |
| +} |
| + |
| +void AsyncResourceHandler::ReportUploadProgress() { |
| + DCHECK(GetRequestInfo()->is_upload_progress_enabled()); |
| + if (waiting_for_upload_progress_ack_) |
| + return; // Send one progress event at a time. |
| + |
| + net::UploadProgress progress = request()->GetUploadProgress(); |
| + if (!progress.size()) |
| + return; // Nothing to upload. |
| + |
| + if (progress.position() == last_upload_position_) |
| + return; // No progress made since last time. |
| + |
| + const uint64 kHalfPercentIncrements = 200; |
| + const TimeDelta kOneSecond = TimeDelta::FromMilliseconds(1000); |
| + |
| + uint64 amt_since_last = progress.position() - last_upload_position_; |
| + TimeDelta time_since_last = TimeTicks::Now() - last_upload_ticks_; |
| + |
| + bool is_finished = (progress.size() == progress.position()); |
| + bool enough_new_progress = |
| + (amt_since_last > (progress.size() / kHalfPercentIncrements)); |
| + bool too_much_time_passed = time_since_last > kOneSecond; |
| + |
| + if (is_finished || enough_new_progress || too_much_time_passed) { |
| + ResourceMessageFilter* filter = GetFilter(); |
| + if (filter) { |
|
mmenke
2015/08/27 17:21:28
A bit unrelated to this CL, but if filter is false
|
| + filter->Send( |
| + new ResourceMsg_UploadProgress(GetRequestID(), |
| + progress.position(), |
| + progress.size())); |
| + } |
| + waiting_for_upload_progress_ack_ = true; |
| + last_upload_ticks_ = TimeTicks::Now(); |
| + last_upload_position_ = progress.position(); |
| + } |
| } |
| bool AsyncResourceHandler::OnRequestRedirected( |
| @@ -168,10 +206,19 @@ bool AsyncResourceHandler::OnResponseStarted(ResourceResponse* response, |
| // request commits, avoiding the possibility of e.g. zooming the old content |
| // or of having to layout the new content twice. |
| + progress_timer_.Stop(); |
| const ResourceRequestInfoImpl* info = GetRequestInfo(); |
| if (!info->filter()) |
| return false; |
| + // We want to send a final upload progress message prior to sending the |
| + // response complete message even if we're waiting for an ack to to a |
| + // previous upload progress message. |
| + if (info->is_upload_progress_enabled()) { |
| + waiting_for_upload_progress_ack_ = false; |
| + ReportUploadProgress(); |
| + } |
| + |
| if (rdh_->delegate()) { |
| rdh_->delegate()->OnResponseStarted( |
| request(), info->GetContext(), response, info->filter()); |
| @@ -220,6 +267,15 @@ bool AsyncResourceHandler::OnResponseStarted(ResourceResponse* response, |
| } |
| bool AsyncResourceHandler::OnWillStart(const GURL& url, bool* defer) { |
| + if (GetRequestInfo()->is_upload_progress_enabled() && |
| + request()->has_upload()) { |
| + ReportUploadProgress(); |
| + progress_timer_.Start( |
| + FROM_HERE, |
| + base::TimeDelta::FromMilliseconds(kUploadProgressIntervalMsec), |
| + this, |
| + &AsyncResourceHandler::ReportUploadProgress); |
| + } |
| return true; |
| } |