| 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/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 28 matching lines...) Expand all Loading... |
| 39 GURL tab_url; | 39 GURL tab_url; |
| 40 GURL tab_referrer_url; | 40 GURL tab_referrer_url; |
| 41 }; | 41 }; |
| 42 | 42 |
| 43 namespace { | 43 namespace { |
| 44 | 44 |
| 45 void CallStartedCBOnUIThread( | 45 void CallStartedCBOnUIThread( |
| 46 const DownloadUrlParameters::OnStartedCallback& started_cb, | 46 const DownloadUrlParameters::OnStartedCallback& started_cb, |
| 47 DownloadItem* item, | 47 DownloadItem* item, |
| 48 DownloadInterruptReason interrupt_reason) { | 48 DownloadInterruptReason interrupt_reason) { |
| 49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 49 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 50 | 50 |
| 51 if (started_cb.is_null()) | 51 if (started_cb.is_null()) |
| 52 return; | 52 return; |
| 53 started_cb.Run(item, interrupt_reason); | 53 started_cb.Run(item, interrupt_reason); |
| 54 } | 54 } |
| 55 | 55 |
| 56 // Static function in order to prevent any accidental accesses to | 56 // Static function in order to prevent any accidental accesses to |
| 57 // DownloadResourceHandler members from the UI thread. | 57 // DownloadResourceHandler members from the UI thread. |
| 58 static void StartOnUIThread( | 58 static void StartOnUIThread( |
| 59 scoped_ptr<DownloadCreateInfo> info, | 59 scoped_ptr<DownloadCreateInfo> info, |
| 60 DownloadResourceHandler::DownloadTabInfo* tab_info, | 60 DownloadResourceHandler::DownloadTabInfo* tab_info, |
| 61 scoped_ptr<ByteStreamReader> stream, | 61 scoped_ptr<ByteStreamReader> stream, |
| 62 const DownloadUrlParameters::OnStartedCallback& started_cb) { | 62 const DownloadUrlParameters::OnStartedCallback& started_cb) { |
| 63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 63 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 64 | 64 |
| 65 DownloadManager* download_manager = info->request_handle.GetDownloadManager(); | 65 DownloadManager* download_manager = info->request_handle.GetDownloadManager(); |
| 66 if (!download_manager) { | 66 if (!download_manager) { |
| 67 // NULL in unittests or if the page closed right after starting the | 67 // NULL in unittests or if the page closed right after starting the |
| 68 // download. | 68 // download. |
| 69 if (!started_cb.is_null()) | 69 if (!started_cb.is_null()) |
| 70 started_cb.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); | 70 started_cb.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); |
| 71 | 71 |
| 72 // |stream| gets deleted on non-FILE thread, but it's ok since | 72 // |stream| gets deleted on non-FILE thread, but it's ok since |
| 73 // we're not using stream_writer_ yet. | 73 // we're not using stream_writer_ yet. |
| 74 | 74 |
| 75 return; | 75 return; |
| 76 } | 76 } |
| 77 | 77 |
| 78 info->tab_url = tab_info->tab_url; | 78 info->tab_url = tab_info->tab_url; |
| 79 info->tab_referrer_url = tab_info->tab_referrer_url; | 79 info->tab_referrer_url = tab_info->tab_referrer_url; |
| 80 | 80 |
| 81 download_manager->StartDownload(info.Pass(), stream.Pass(), started_cb); | 81 download_manager->StartDownload(info.Pass(), stream.Pass(), started_cb); |
| 82 } | 82 } |
| 83 | 83 |
| 84 void InitializeDownloadTabInfoOnUIThread( | 84 void InitializeDownloadTabInfoOnUIThread( |
| 85 const DownloadRequestHandle& request_handle, | 85 const DownloadRequestHandle& request_handle, |
| 86 DownloadResourceHandler::DownloadTabInfo* tab_info) { | 86 DownloadResourceHandler::DownloadTabInfo* tab_info) { |
| 87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 87 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 88 | 88 |
| 89 WebContents* web_contents = request_handle.GetWebContents(); | 89 WebContents* web_contents = request_handle.GetWebContents(); |
| 90 if (web_contents) { | 90 if (web_contents) { |
| 91 NavigationEntry* entry = web_contents->GetController().GetVisibleEntry(); | 91 NavigationEntry* entry = web_contents->GetController().GetVisibleEntry(); |
| 92 if (entry) { | 92 if (entry) { |
| 93 tab_info->tab_url = entry->GetURL(); | 93 tab_info->tab_url = entry->GetURL(); |
| 94 tab_info->tab_referrer_url = entry->GetReferrer().url; | 94 tab_info->tab_referrer_url = entry->GetReferrer().url; |
| 95 } | 95 } |
| 96 } | 96 } |
| 97 } | 97 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 const net::RedirectInfo& redirect_info, | 143 const net::RedirectInfo& redirect_info, |
| 144 ResourceResponse* response, | 144 ResourceResponse* response, |
| 145 bool* defer) { | 145 bool* defer) { |
| 146 return true; | 146 return true; |
| 147 } | 147 } |
| 148 | 148 |
| 149 // Send the download creation information to the download thread. | 149 // Send the download creation information to the download thread. |
| 150 bool DownloadResourceHandler::OnResponseStarted( | 150 bool DownloadResourceHandler::OnResponseStarted( |
| 151 ResourceResponse* response, | 151 ResourceResponse* response, |
| 152 bool* defer) { | 152 bool* defer) { |
| 153 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 153 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 154 // There can be only one (call) | 154 // There can be only one (call) |
| 155 DCHECK(!on_response_started_called_); | 155 DCHECK(!on_response_started_called_); |
| 156 on_response_started_called_ = true; | 156 on_response_started_called_ = true; |
| 157 | 157 |
| 158 DVLOG(20) << __FUNCTION__ << "()" << DebugString(); | 158 DVLOG(20) << __FUNCTION__ << "()" << DebugString(); |
| 159 download_start_time_ = base::TimeTicks::Now(); | 159 download_start_time_ = base::TimeTicks::Now(); |
| 160 | 160 |
| 161 // If it's a download, we don't want to poison the cache with it. | 161 // If it's a download, we don't want to poison the cache with it. |
| 162 request()->StopCaching(); | 162 request()->StopCaching(); |
| 163 | 163 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 tab_info_ = NULL; | 253 tab_info_ = NULL; |
| 254 // Guaranteed to be called in StartOnUIThread | 254 // Guaranteed to be called in StartOnUIThread |
| 255 started_cb_.Reset(); | 255 started_cb_.Reset(); |
| 256 | 256 |
| 257 return true; | 257 return true; |
| 258 } | 258 } |
| 259 | 259 |
| 260 void DownloadResourceHandler::CallStartedCB( | 260 void DownloadResourceHandler::CallStartedCB( |
| 261 DownloadItem* item, | 261 DownloadItem* item, |
| 262 DownloadInterruptReason interrupt_reason) { | 262 DownloadInterruptReason interrupt_reason) { |
| 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 263 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 264 if (started_cb_.is_null()) | 264 if (started_cb_.is_null()) |
| 265 return; | 265 return; |
| 266 BrowserThread::PostTask( | 266 BrowserThread::PostTask( |
| 267 BrowserThread::UI, | 267 BrowserThread::UI, |
| 268 FROM_HERE, | 268 FROM_HERE, |
| 269 base::Bind( | 269 base::Bind( |
| 270 &CallStartedCBOnUIThread, started_cb_, item, interrupt_reason)); | 270 &CallStartedCBOnUIThread, started_cb_, item, interrupt_reason)); |
| 271 started_cb_.Reset(); | 271 started_cb_.Reset(); |
| 272 } | 272 } |
| 273 | 273 |
| 274 bool DownloadResourceHandler::OnWillStart(const GURL& url, bool* defer) { | 274 bool DownloadResourceHandler::OnWillStart(const GURL& url, bool* defer) { |
| 275 return true; | 275 return true; |
| 276 } | 276 } |
| 277 | 277 |
| 278 bool DownloadResourceHandler::OnBeforeNetworkStart(const GURL& url, | 278 bool DownloadResourceHandler::OnBeforeNetworkStart(const GURL& url, |
| 279 bool* defer) { | 279 bool* defer) { |
| 280 return true; | 280 return true; |
| 281 } | 281 } |
| 282 | 282 |
| 283 // Create a new buffer, which will be handed to the download thread for file | 283 // Create a new buffer, which will be handed to the download thread for file |
| 284 // writing and deletion. | 284 // writing and deletion. |
| 285 bool DownloadResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, | 285 bool DownloadResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, |
| 286 int* buf_size, | 286 int* buf_size, |
| 287 int min_size) { | 287 int min_size) { |
| 288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 288 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 289 DCHECK(buf && buf_size); | 289 DCHECK(buf && buf_size); |
| 290 DCHECK(!read_buffer_.get()); | 290 DCHECK(!read_buffer_.get()); |
| 291 | 291 |
| 292 *buf_size = min_size < 0 ? kReadBufSize : min_size; | 292 *buf_size = min_size < 0 ? kReadBufSize : min_size; |
| 293 last_buffer_size_ = *buf_size; | 293 last_buffer_size_ = *buf_size; |
| 294 read_buffer_ = new net::IOBuffer(*buf_size); | 294 read_buffer_ = new net::IOBuffer(*buf_size); |
| 295 *buf = read_buffer_.get(); | 295 *buf = read_buffer_.get(); |
| 296 return true; | 296 return true; |
| 297 } | 297 } |
| 298 | 298 |
| 299 // Pass the buffer to the download file writer. | 299 // Pass the buffer to the download file writer. |
| 300 bool DownloadResourceHandler::OnReadCompleted(int bytes_read, bool* defer) { | 300 bool DownloadResourceHandler::OnReadCompleted(int bytes_read, bool* defer) { |
| 301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 301 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 302 DCHECK(read_buffer_.get()); | 302 DCHECK(read_buffer_.get()); |
| 303 | 303 |
| 304 base::TimeTicks now(base::TimeTicks::Now()); | 304 base::TimeTicks now(base::TimeTicks::Now()); |
| 305 if (!last_read_time_.is_null()) { | 305 if (!last_read_time_.is_null()) { |
| 306 double seconds_since_last_read = (now - last_read_time_).InSecondsF(); | 306 double seconds_since_last_read = (now - last_read_time_).InSecondsF(); |
| 307 if (now == last_read_time_) | 307 if (now == last_read_time_) |
| 308 // Use 1/10 ms as a "very small number" so that we avoid | 308 // Use 1/10 ms as a "very small number" so that we avoid |
| 309 // divide-by-zero error and still record a very high potential bandwidth. | 309 // divide-by-zero error and still record a very high potential bandwidth. |
| 310 seconds_since_last_read = 0.00001; | 310 seconds_since_last_read = 0.00001; |
| 311 | 311 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 333 if (pause_count_ > 0) | 333 if (pause_count_ > 0) |
| 334 *defer = was_deferred_ = true; | 334 *defer = was_deferred_ = true; |
| 335 | 335 |
| 336 return true; | 336 return true; |
| 337 } | 337 } |
| 338 | 338 |
| 339 void DownloadResourceHandler::OnResponseCompleted( | 339 void DownloadResourceHandler::OnResponseCompleted( |
| 340 const net::URLRequestStatus& status, | 340 const net::URLRequestStatus& status, |
| 341 const std::string& security_info, | 341 const std::string& security_info, |
| 342 bool* defer) { | 342 bool* defer) { |
| 343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 343 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 344 int response_code = status.is_success() ? request()->GetResponseCode() : 0; | 344 int response_code = status.is_success() ? request()->GetResponseCode() : 0; |
| 345 DVLOG(20) << __FUNCTION__ << "()" << DebugString() | 345 DVLOG(20) << __FUNCTION__ << "()" << DebugString() |
| 346 << " status.status() = " << status.status() | 346 << " status.status() = " << status.status() |
| 347 << " status.error() = " << status.error() | 347 << " status.error() = " << status.error() |
| 348 << " response_code = " << response_code; | 348 << " response_code = " << response_code; |
| 349 | 349 |
| 350 net::Error error_code = net::OK; | 350 net::Error error_code = net::OK; |
| 351 if (status.status() == net::URLRequestStatus::FAILED || | 351 if (status.status() == net::URLRequestStatus::FAILED || |
| 352 // Note cancels as failures too. | 352 // Note cancels as failures too. |
| 353 status.status() == net::URLRequestStatus::CANCELED) { | 353 status.status() == net::URLRequestStatus::CANCELED) { |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 | 456 |
| 457 stream_writer_.reset(); // We no longer need the stream. | 457 stream_writer_.reset(); // We no longer need the stream. |
| 458 read_buffer_ = NULL; | 458 read_buffer_ = NULL; |
| 459 } | 459 } |
| 460 | 460 |
| 461 void DownloadResourceHandler::OnDataDownloaded(int bytes_downloaded) { | 461 void DownloadResourceHandler::OnDataDownloaded(int bytes_downloaded) { |
| 462 NOTREACHED(); | 462 NOTREACHED(); |
| 463 } | 463 } |
| 464 | 464 |
| 465 void DownloadResourceHandler::PauseRequest() { | 465 void DownloadResourceHandler::PauseRequest() { |
| 466 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 466 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 467 | 467 |
| 468 ++pause_count_; | 468 ++pause_count_; |
| 469 } | 469 } |
| 470 | 470 |
| 471 void DownloadResourceHandler::ResumeRequest() { | 471 void DownloadResourceHandler::ResumeRequest() { |
| 472 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 472 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 473 DCHECK_LT(0, pause_count_); | 473 DCHECK_LT(0, pause_count_); |
| 474 | 474 |
| 475 --pause_count_; | 475 --pause_count_; |
| 476 | 476 |
| 477 if (!was_deferred_) | 477 if (!was_deferred_) |
| 478 return; | 478 return; |
| 479 if (pause_count_ > 0) | 479 if (pause_count_ > 0) |
| 480 return; | 480 return; |
| 481 | 481 |
| 482 was_deferred_ = false; | 482 was_deferred_ = false; |
| 483 if (!last_stream_pause_time_.is_null()) { | 483 if (!last_stream_pause_time_.is_null()) { |
| 484 total_pause_time_ += (base::TimeTicks::Now() - last_stream_pause_time_); | 484 total_pause_time_ += (base::TimeTicks::Now() - last_stream_pause_time_); |
| 485 last_stream_pause_time_ = base::TimeTicks(); | 485 last_stream_pause_time_ = base::TimeTicks(); |
| 486 } | 486 } |
| 487 | 487 |
| 488 controller()->Resume(); | 488 controller()->Resume(); |
| 489 } | 489 } |
| 490 | 490 |
| 491 void DownloadResourceHandler::CancelRequest() { | 491 void DownloadResourceHandler::CancelRequest() { |
| 492 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 492 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 493 | 493 |
| 494 const ResourceRequestInfo* info = GetRequestInfo(); | 494 const ResourceRequestInfo* info = GetRequestInfo(); |
| 495 ResourceDispatcherHostImpl::Get()->CancelRequest( | 495 ResourceDispatcherHostImpl::Get()->CancelRequest( |
| 496 info->GetChildID(), | 496 info->GetChildID(), |
| 497 info->GetRequestID()); | 497 info->GetRequestID()); |
| 498 // This object has been deleted. | 498 // This object has been deleted. |
| 499 } | 499 } |
| 500 | 500 |
| 501 std::string DownloadResourceHandler::DebugString() const { | 501 std::string DownloadResourceHandler::DebugString() const { |
| 502 const ResourceRequestInfo* info = GetRequestInfo(); | 502 const ResourceRequestInfo* info = GetRequestInfo(); |
| 503 return base::StringPrintf("{" | 503 return base::StringPrintf("{" |
| 504 " url_ = " "\"%s\"" | 504 " url_ = " "\"%s\"" |
| 505 " info = {" | 505 " info = {" |
| 506 " child_id = " "%d" | 506 " child_id = " "%d" |
| 507 " request_id = " "%d" | 507 " request_id = " "%d" |
| 508 " route_id = " "%d" | 508 " route_id = " "%d" |
| 509 " }" | 509 " }" |
| 510 " }", | 510 " }", |
| 511 request() ? | 511 request() ? |
| 512 request()->url().spec().c_str() : | 512 request()->url().spec().c_str() : |
| 513 "<NULL request>", | 513 "<NULL request>", |
| 514 info->GetChildID(), | 514 info->GetChildID(), |
| 515 info->GetRequestID(), | 515 info->GetRequestID(), |
| 516 info->GetRouteID()); | 516 info->GetRouteID()); |
| 517 } | 517 } |
| 518 | 518 |
| 519 DownloadResourceHandler::~DownloadResourceHandler() { | 519 DownloadResourceHandler::~DownloadResourceHandler() { |
| 520 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 520 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 521 | 521 |
| 522 // This won't do anything if the callback was called before. | 522 // This won't do anything if the callback was called before. |
| 523 // If it goes through, it will likely be because OnWillStart() returned | 523 // If it goes through, it will likely be because OnWillStart() returned |
| 524 // false somewhere in the chain of resource handlers. | 524 // false somewhere in the chain of resource handlers. |
| 525 CallStartedCB(NULL, DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED); | 525 CallStartedCB(NULL, DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED); |
| 526 | 526 |
| 527 // Remove output stream callback if a stream exists. | 527 // Remove output stream callback if a stream exists. |
| 528 if (stream_writer_) | 528 if (stream_writer_) |
| 529 stream_writer_->RegisterCallback(base::Closure()); | 529 stream_writer_->RegisterCallback(base::Closure()); |
| 530 | 530 |
| 531 // tab_info_ must be destroyed on UI thread, since | 531 // tab_info_ must be destroyed on UI thread, since |
| 532 // InitializeDownloadTabInfoOnUIThread might still be using it. | 532 // InitializeDownloadTabInfoOnUIThread might still be using it. |
| 533 if (tab_info_) | 533 if (tab_info_) |
| 534 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, tab_info_); | 534 BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, tab_info_); |
| 535 | 535 |
| 536 UMA_HISTOGRAM_TIMES("SB2.DownloadDuration", | 536 UMA_HISTOGRAM_TIMES("SB2.DownloadDuration", |
| 537 base::TimeTicks::Now() - download_start_time_); | 537 base::TimeTicks::Now() - download_start_time_); |
| 538 } | 538 } |
| 539 | 539 |
| 540 } // namespace content | 540 } // namespace content |
| OLD | NEW |