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

Side by Side Diff: content/browser/download/download_resource_handler.cc

Issue 10332130: Use defer out-params instead of ResourceDispatcherHostImpl::PauseRequest(...true) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 7 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 | Annotate | Revision Log
OLDNEW
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/download/download_resource_handler.h" 5 #include "content/browser/download/download_resource_handler.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 const content::DownloadSaveInfo& save_info) 62 const content::DownloadSaveInfo& save_info)
63 : download_id_(DownloadId::Invalid()), 63 : download_id_(DownloadId::Invalid()),
64 global_id_(render_process_host_id, request_id), 64 global_id_(render_process_host_id, request_id),
65 render_view_id_(render_view_id), 65 render_view_id_(render_view_id),
66 content_length_(0), 66 content_length_(0),
67 download_file_manager_(download_file_manager), 67 download_file_manager_(download_file_manager),
68 request_(request), 68 request_(request),
69 started_cb_(started_cb), 69 started_cb_(started_cb),
70 save_info_(save_info), 70 save_info_(save_info),
71 buffer_(new content::DownloadBuffer), 71 buffer_(new content::DownloadBuffer),
72 is_paused_(false),
73 last_buffer_size_(0), 72 last_buffer_size_(0),
74 bytes_read_(0) { 73 bytes_read_(0),
74 pause_count_(0),
75 was_deferred_(false) {
75 download_stats::RecordDownloadCount(download_stats::UNTHROTTLED_COUNT); 76 download_stats::RecordDownloadCount(download_stats::UNTHROTTLED_COUNT);
76 } 77 }
77 78
78 bool DownloadResourceHandler::OnUploadProgress(int request_id, 79 bool DownloadResourceHandler::OnUploadProgress(int request_id,
79 uint64 position, 80 uint64 position,
80 uint64 size) { 81 uint64 size) {
81 return true; 82 return true;
82 } 83 }
83 84
84 // Not needed, as this event handler ought to be the final resource. 85 // Not needed, as this event handler ought to be the final resource.
85 bool DownloadResourceHandler::OnRequestRedirected( 86 bool DownloadResourceHandler::OnRequestRedirected(
86 int request_id, 87 int request_id,
87 const GURL& url, 88 const GURL& url,
88 content::ResourceResponse* response, 89 content::ResourceResponse* response,
89 bool* defer) { 90 bool* defer) {
90 return true; 91 return true;
91 } 92 }
92 93
93 // Send the download creation information to the download thread. 94 // Send the download creation information to the download thread.
94 bool DownloadResourceHandler::OnResponseStarted( 95 bool DownloadResourceHandler::OnResponseStarted(
95 int request_id, 96 int request_id,
96 content::ResourceResponse* response) { 97 content::ResourceResponse* response,
98 bool* defer) {
97 VLOG(20) << __FUNCTION__ << "()" << DebugString() 99 VLOG(20) << __FUNCTION__ << "()" << DebugString()
98 << " request_id = " << request_id; 100 << " request_id = " << request_id;
99 download_start_time_ = base::TimeTicks::Now(); 101 download_start_time_ = base::TimeTicks::Now();
100 102
101 // If it's a download, we don't want to poison the cache with it. 103 // If it's a download, we don't want to poison the cache with it.
102 request_->StopCaching(); 104 request_->StopCaching();
103 105
104 std::string content_disposition; 106 std::string content_disposition;
105 request_->GetResponseHeaderByName("content-disposition", 107 request_->GetResponseHeaderByName("content-disposition",
106 &content_disposition); 108 &content_disposition);
107 set_content_disposition(content_disposition); 109 SetContentDisposition(content_disposition);
108 set_content_length(response->content_length); 110 SetContentLength(response->content_length);
109 111
110 const ResourceRequestInfoImpl* request_info = 112 const ResourceRequestInfoImpl* request_info =
111 ResourceRequestInfoImpl::ForRequest(request_); 113 ResourceRequestInfoImpl::ForRequest(request_);
112 114
113 // Deleted in DownloadManager. 115 // Deleted in DownloadManager.
114 scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo( 116 scoped_ptr<DownloadCreateInfo> info(new DownloadCreateInfo(
115 base::Time::Now(), 0, content_length_, DownloadItem::IN_PROGRESS, 117 base::Time::Now(), 0, content_length_, DownloadItem::IN_PROGRESS,
116 request_->net_log(), request_info->has_user_gesture(), 118 request_->net_log(), request_info->has_user_gesture(),
117 request_info->transition_type())); 119 request_info->transition_type()));
118 info->url_chain = request_->url_chain(); 120 info->url_chain = request_->url_chain();
119 info->referrer_url = GURL(request_->referrer()); 121 info->referrer_url = GURL(request_->referrer());
120 info->start_time = base::Time::Now(); 122 info->start_time = base::Time::Now();
121 info->received_bytes = save_info_.offset; 123 info->received_bytes = save_info_.offset;
122 info->total_bytes = content_length_; 124 info->total_bytes = content_length_;
123 info->state = DownloadItem::IN_PROGRESS; 125 info->state = DownloadItem::IN_PROGRESS;
124 info->has_user_gesture = request_info->has_user_gesture(); 126 info->has_user_gesture = request_info->has_user_gesture();
125 info->content_disposition = content_disposition_; 127 info->content_disposition = content_disposition_;
126 info->mime_type = response->mime_type; 128 info->mime_type = response->mime_type;
127 info->remote_address = request_->GetSocketAddress().host(); 129 info->remote_address = request_->GetSocketAddress().host();
128 download_stats::RecordDownloadMimeType(info->mime_type); 130 download_stats::RecordDownloadMimeType(info->mime_type);
129 131
130 DownloadRequestHandle request_handle(global_id_.child_id, 132 DownloadRequestHandle request_handle(this, global_id_.child_id,
131 render_view_id_, global_id_.request_id); 133 render_view_id_, global_id_.request_id);
132 134
133 // Get the last modified time and etag. 135 // Get the last modified time and etag.
134 const net::HttpResponseHeaders* headers = request_->response_headers(); 136 const net::HttpResponseHeaders* headers = request_->response_headers();
135 if (headers) { 137 if (headers) {
136 std::string last_modified_hdr; 138 std::string last_modified_hdr;
137 std::string etag; 139 std::string etag;
138 if (headers->EnumerateHeader(NULL, "Last-Modified", &last_modified_hdr)) 140 if (headers->EnumerateHeader(NULL, "Last-Modified", &last_modified_hdr))
139 info->last_modified = last_modified_hdr; 141 info->last_modified = last_modified_hdr;
140 if (headers->EnumerateHeader(NULL, "ETag", &etag)) 142 if (headers->EnumerateHeader(NULL, "ETag", &etag))
(...skipping 11 matching lines...) Expand all
152 "Accept-Ranges", 154 "Accept-Ranges",
153 &accept_ranges_)) { 155 &accept_ranges_)) {
154 accept_ranges_ = ""; 156 accept_ranges_ = "";
155 } 157 }
156 158
157 info->prompt_user_for_save_location = 159 info->prompt_user_for_save_location =
158 save_info_.prompt_for_save_location && save_info_.file_path.empty(); 160 save_info_.prompt_for_save_location && save_info_.file_path.empty();
159 info->referrer_charset = request_->context()->referrer_charset(); 161 info->referrer_charset = request_->context()->referrer_charset();
160 info->save_info = save_info_; 162 info->save_info = save_info_;
161 163
162
163 BrowserThread::PostTask( 164 BrowserThread::PostTask(
164 BrowserThread::UI, FROM_HERE, 165 BrowserThread::UI, FROM_HERE,
165 base::Bind(&DownloadResourceHandler::StartOnUIThread, this, 166 base::Bind(&DownloadResourceHandler::StartOnUIThread, this,
166 base::Passed(&info), request_handle)); 167 base::Passed(&info), request_handle));
167 168
168 // We can't start saving the data before we create the file on disk and have a
169 // download id. The request will be un-paused in
170 // DownloadFileManager::CreateDownloadFile.
171 ResourceDispatcherHostImpl::Get()->PauseRequest(global_id_.child_id,
172 global_id_.request_id,
173 true);
174
175 return true; 169 return true;
176 } 170 }
177 171
178 void DownloadResourceHandler::CallStartedCB(DownloadId id, net::Error error) { 172 void DownloadResourceHandler::CallStartedCB(DownloadId id, net::Error error) {
179 if (started_cb_.is_null()) 173 if (started_cb_.is_null())
180 return; 174 return;
181 BrowserThread::PostTask( 175 BrowserThread::PostTask(
182 BrowserThread::UI, FROM_HERE, 176 BrowserThread::UI, FROM_HERE,
183 base::Bind(&CallStartedCBOnUIThread, started_cb_, id, error)); 177 base::Bind(&CallStartedCBOnUIThread, started_cb_, id, error));
184 started_cb_.Reset(); 178 started_cb_.Reset();
(...skipping 13 matching lines...) Expand all
198 if (!read_buffer_) { 192 if (!read_buffer_) {
199 *buf_size = min_size < 0 ? kReadBufSize : min_size; 193 *buf_size = min_size < 0 ? kReadBufSize : min_size;
200 last_buffer_size_ = *buf_size; 194 last_buffer_size_ = *buf_size;
201 read_buffer_ = new net::IOBuffer(*buf_size); 195 read_buffer_ = new net::IOBuffer(*buf_size);
202 } 196 }
203 *buf = read_buffer_.get(); 197 *buf = read_buffer_.get();
204 return true; 198 return true;
205 } 199 }
206 200
207 // Pass the buffer to the download file writer. 201 // Pass the buffer to the download file writer.
208 bool DownloadResourceHandler::OnReadCompleted(int request_id, int* bytes_read) { 202 bool DownloadResourceHandler::OnReadCompleted(int request_id, int* bytes_read,
203 bool* defer) {
204 if (!read_buffer_) {
205 // Ignore spurious OnReadCompleted! Deferring from OnReadCompleted tells
206 // the ResourceDispatcherHost that we did not consume the data.
207 // ResumeDeferredRequest then repeats the last OnReadCompleted call.
208 // TODO(darin): Fix the ResourceDispatcherHost to avoid this hack!
209 return true;
210 }
211
212 if (pause_count_ > 0) {
213 *defer = was_deferred_ = true;
214 return true;
215 }
216
217 if (download_id_ == DownloadId::Invalid()) {
218 // We can't start saving the data before we create the file on disk and
219 // have a download id. The request will be un-paused in
220 // DownloadFileManager::CreateDownloadFile.
221 *defer = was_deferred_ = true;
222 return true;
223 }
224
209 base::TimeTicks now(base::TimeTicks::Now()); 225 base::TimeTicks now(base::TimeTicks::Now());
210 if (!last_read_time_.is_null()) { 226 if (!last_read_time_.is_null()) {
211 double seconds_since_last_read = (now - last_read_time_).InSecondsF(); 227 double seconds_since_last_read = (now - last_read_time_).InSecondsF();
212 if (now == last_read_time_) 228 if (now == last_read_time_)
213 // Use 1/10 ms as a "very small number" so that we avoid 229 // Use 1/10 ms as a "very small number" so that we avoid
214 // divide-by-zero error and still record a very high potential bandwidth. 230 // divide-by-zero error and still record a very high potential bandwidth.
215 seconds_since_last_read = 0.00001; 231 seconds_since_last_read = 0.00001;
216 232
217 double actual_bandwidth = (*bytes_read)/seconds_since_last_read; 233 double actual_bandwidth = (*bytes_read)/seconds_since_last_read;
218 double potential_bandwidth = last_buffer_size_/seconds_since_last_read; 234 double potential_bandwidth = last_buffer_size_/seconds_since_last_read;
(...skipping 14 matching lines...) Expand all
233 // We are passing ownership of this buffer to the download file manager. 249 // We are passing ownership of this buffer to the download file manager.
234 if (need_update) { 250 if (need_update) {
235 BrowserThread::PostTask( 251 BrowserThread::PostTask(
236 BrowserThread::FILE, FROM_HERE, 252 BrowserThread::FILE, FROM_HERE,
237 base::Bind(&DownloadFileManager::UpdateDownload, 253 base::Bind(&DownloadFileManager::UpdateDownload,
238 download_file_manager_, download_id_, buffer_)); 254 download_file_manager_, download_id_, buffer_));
239 } 255 }
240 256
241 // We schedule a pause outside of the read loop if there is too much file 257 // We schedule a pause outside of the read loop if there is too much file
242 // writing work to do. 258 // writing work to do.
243 if (vector_size > kLoadsToWrite) 259 if (vector_size > kLoadsToWrite) {
244 StartPauseTimer(); 260 *defer = was_deferred_ = true;
261 CheckWriteProgressLater();
262 }
245 263
246 return true; 264 return true;
247 } 265 }
248 266
249 bool DownloadResourceHandler::OnResponseCompleted( 267 bool DownloadResourceHandler::OnResponseCompleted(
250 int request_id, 268 int request_id,
251 const net::URLRequestStatus& status, 269 const net::URLRequestStatus& status,
252 const std::string& security_info) { 270 const std::string& security_info) {
253 VLOG(20) << __FUNCTION__ << "()" << DebugString() 271 VLOG(20) << __FUNCTION__ << "()" << DebugString()
254 << " request_id = " << request_id 272 << " request_id = " << request_id
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 const DownloadRequestHandle& handle) { 366 const DownloadRequestHandle& handle) {
349 DownloadManager* download_manager = handle.GetDownloadManager(); 367 DownloadManager* download_manager = handle.GetDownloadManager();
350 if (!download_manager) { 368 if (!download_manager) {
351 // NULL in unittests or if the page closed right after starting the 369 // NULL in unittests or if the page closed right after starting the
352 // download. 370 // download.
353 CallStartedCB(download_id_, net::ERR_ACCESS_DENIED); 371 CallStartedCB(download_id_, net::ERR_ACCESS_DENIED);
354 return; 372 return;
355 } 373 }
356 DownloadId download_id = download_manager->delegate()->GetNextId(); 374 DownloadId download_id = download_manager->delegate()->GetNextId();
357 info->download_id = download_id; 375 info->download_id = download_id;
376
377 // NOTE: StartDownload triggers creation of the download destination file
378 // that will hold the downloaded data. SetDownloadID unblocks the
379 // DownloadResourceHandler to begin forwarding network data to the download
380 // destination file. The sequence of these two steps is critical as creation
381 // of the downloaded destination file has to happen before we attempt to
382 // append data to it. Both of those operations happen on the FILE thread.
Randy Smith (Not in Mondays) 2012/05/17 15:53:48 So just to be explicit, the ordering semantics you
darin (slow to review) 2012/05/17 21:17:57 Yes, you are understanding correctly. This enable
383
384 download_file_manager_->StartDownload(info.release(), handle);
385
358 BrowserThread::PostTask( 386 BrowserThread::PostTask(
359 BrowserThread::IO, FROM_HERE, 387 BrowserThread::IO, FROM_HERE,
360 base::Bind(&DownloadResourceHandler::set_download_id, this, 388 base::Bind(&DownloadResourceHandler::SetDownloadID, this,
361 info->download_id)); 389 download_id));
362 // It's safe to continue on with download initiation before we have 390
363 // confirmation that that download_id_ has been set on the IO thread, as any
364 // messages generated by the UI thread that affect the IO thread will be
365 // behind the message posted above.
366 download_file_manager_->StartDownload(info.release(), handle);
367 CallStartedCB(download_id, net::OK); 391 CallStartedCB(download_id, net::OK);
368 } 392 }
369 393
370 void DownloadResourceHandler::set_download_id(content::DownloadId id) { 394 void DownloadResourceHandler::SetDownloadID(content::DownloadId id) {
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 395 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
396
372 download_id_ = id; 397 download_id_ = id;
398 MaybeResumeRequest();
373 } 399 }
374 400
375 // If the content-length header is not present (or contains something other 401 // If the content-length header is not present (or contains something other
376 // than numbers), the incoming content_length is -1 (unknown size). 402 // than numbers), the incoming content_length is -1 (unknown size).
377 // Set the content length to 0 to indicate unknown size to DownloadManager. 403 // Set the content length to 0 to indicate unknown size to DownloadManager.
378 void DownloadResourceHandler::set_content_length(const int64& content_length) { 404 void DownloadResourceHandler::SetContentLength(const int64& content_length) {
379 content_length_ = 0; 405 content_length_ = 0;
380 if (content_length > 0) 406 if (content_length > 0)
381 content_length_ = content_length; 407 content_length_ = content_length;
382 } 408 }
383 409
384 void DownloadResourceHandler::set_content_disposition( 410 void DownloadResourceHandler::SetContentDisposition(
385 const std::string& content_disposition) { 411 const std::string& content_disposition) {
386 content_disposition_ = content_disposition; 412 content_disposition_ = content_disposition;
387 } 413 }
388 414
389 void DownloadResourceHandler::CheckWriteProgress() { 415 void DownloadResourceHandler::CheckWriteProgress() {
390 if (!buffer_.get()) 416 if (!buffer_.get())
391 return; // The download completed while we were waiting to run. 417 return; // The download completed while we were waiting to run.
392 418
393 size_t contents_size = buffer_->size(); 419 if (buffer_->size() > kLoadsToWrite) {
420 // We'll come back later and see if it's okay to unpause the request.
421 CheckWriteProgressLater();
422 return;
423 }
394 424
395 bool should_pause = contents_size > kLoadsToWrite; 425 MaybeResumeRequest();
426 }
396 427
397 // We'll come back later and see if it's okay to unpause the request. 428 void DownloadResourceHandler::PauseRequest() {
398 if (should_pause) 429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
399 StartPauseTimer();
400 430
401 if (is_paused_ != should_pause) { 431 ++pause_count_;
402 ResourceDispatcherHostImpl::Get()->PauseRequest(global_id_.child_id, 432 }
403 global_id_.request_id, 433
404 should_pause); 434 void DownloadResourceHandler::ResumeRequest() {
405 is_paused_ = should_pause; 435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
406 } 436 DCHECK_LT(0, pause_count_);
437
438 --pause_count_;
439 MaybeResumeRequest();
440 }
441
442 void DownloadResourceHandler::CancelRequest() {
443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
444
445 ResourceDispatcherHostImpl::Get()->CancelRequest(
446 global_id_.child_id,
447 global_id_.request_id,
448 false);
407 } 449 }
408 450
409 DownloadResourceHandler::~DownloadResourceHandler() { 451 DownloadResourceHandler::~DownloadResourceHandler() {
410 // This won't do anything if the callback was called before. 452 // This won't do anything if the callback was called before.
411 // If it goes through, it will likely be because OnWillStart() returned 453 // If it goes through, it will likely be because OnWillStart() returned
412 // false somewhere in the chain of resource handlers. 454 // false somewhere in the chain of resource handlers.
413 CallStartedCB(download_id_, net::ERR_ACCESS_DENIED); 455 CallStartedCB(download_id_, net::ERR_ACCESS_DENIED);
414 } 456 }
415 457
416 void DownloadResourceHandler::StartPauseTimer() { 458 void DownloadResourceHandler::CheckWriteProgressLater() {
417 if (!pause_timer_.IsRunning()) 459 if (!check_write_progress_timer_.IsRunning()) {
418 pause_timer_.Start(FROM_HERE, 460 check_write_progress_timer_.Start(
419 base::TimeDelta::FromMilliseconds(kThrottleTimeMs), this, 461 FROM_HERE,
420 &DownloadResourceHandler::CheckWriteProgress); 462 base::TimeDelta::FromMilliseconds(kThrottleTimeMs),
463 this,
464 &DownloadResourceHandler::CheckWriteProgress);
465 }
466 }
467
468 void DownloadResourceHandler::MaybeResumeRequest() {
469 if (!was_deferred_)
470 return;
471
472 if (pause_count_ > 0)
473 return;
474 if (download_id_ == DownloadId::Invalid())
475 return;
476 if (buffer_.get() && (buffer_->size() > kLoadsToWrite))
477 return;
478
479 was_deferred_ = false;
480 ResourceDispatcherHostImpl::Get()->ResumeDeferredRequest(
481 global_id_.child_id,
482 global_id_.request_id);
421 } 483 }
422 484
423 std::string DownloadResourceHandler::DebugString() const { 485 std::string DownloadResourceHandler::DebugString() const {
424 return base::StringPrintf("{" 486 return base::StringPrintf("{"
425 " url_ = " "\"%s\"" 487 " url_ = " "\"%s\""
426 " download_id_ = " "%d" 488 " download_id_ = " "%d"
427 " global_id_ = {" 489 " global_id_ = {"
428 " child_id = " "%d" 490 " child_id = " "%d"
429 " request_id = " "%d" 491 " request_id = " "%d"
430 " }" 492 " }"
431 " render_view_id_ = " "%d" 493 " render_view_id_ = " "%d"
432 " save_info_.file_path = \"%" PRFilePath "\"" 494 " save_info_.file_path = \"%" PRFilePath "\""
433 " }", 495 " }",
434 request_ ? 496 request_ ?
435 request_->url().spec().c_str() : 497 request_->url().spec().c_str() :
436 "<NULL request>", 498 "<NULL request>",
437 download_id_.local(), 499 download_id_.local(),
438 global_id_.child_id, 500 global_id_.child_id,
439 global_id_.request_id, 501 global_id_.request_id,
440 render_view_id_, 502 render_view_id_,
441 save_info_.file_path.value().c_str()); 503 save_info_.file_path.value().c_str());
442 } 504 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698