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_manager_impl.h" | 5 #include "content/browser/download/download_manager_impl.h" |
6 | 6 |
7 #include <iterator> | 7 #include <iterator> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 21 matching lines...) Expand all Loading... | |
32 #include "content/public/browser/browser_thread.h" | 32 #include "content/public/browser/browser_thread.h" |
33 #include "content/public/browser/content_browser_client.h" | 33 #include "content/public/browser/content_browser_client.h" |
34 #include "content/public/browser/download_interrupt_reasons.h" | 34 #include "content/public/browser/download_interrupt_reasons.h" |
35 #include "content/public/browser/download_manager_delegate.h" | 35 #include "content/public/browser/download_manager_delegate.h" |
36 #include "content/public/browser/download_url_parameters.h" | 36 #include "content/public/browser/download_url_parameters.h" |
37 #include "content/public/browser/notification_service.h" | 37 #include "content/public/browser/notification_service.h" |
38 #include "content/public/browser/notification_types.h" | 38 #include "content/public/browser/notification_types.h" |
39 #include "content/public/browser/render_process_host.h" | 39 #include "content/public/browser/render_process_host.h" |
40 #include "content/public/browser/resource_context.h" | 40 #include "content/public/browser/resource_context.h" |
41 #include "content/public/browser/web_contents_delegate.h" | 41 #include "content/public/browser/web_contents_delegate.h" |
42 #include "content/public/common/referrer.h" | |
42 #include "net/base/load_flags.h" | 43 #include "net/base/load_flags.h" |
43 #include "net/base/upload_bytes_element_reader.h" | 44 #include "net/base/upload_bytes_element_reader.h" |
44 #include "net/base/upload_data_stream.h" | 45 #include "net/base/upload_data_stream.h" |
45 #include "net/url_request/url_request_context.h" | 46 #include "net/url_request/url_request_context.h" |
46 #include "webkit/glue/webkit_glue.h" | 47 #include "webkit/glue/webkit_glue.h" |
47 | 48 |
48 namespace content { | 49 namespace content { |
49 namespace { | 50 namespace { |
50 | 51 |
51 void BeginDownload(scoped_ptr<DownloadUrlParameters> params) { | 52 void BeginDownload(scoped_ptr<DownloadUrlParameters> params, |
53 DownloadId download_id) { | |
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
53 // ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and | 55 // ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and |
54 // DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so | 56 // DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so |
55 // we must down cast. RDHI is the only subclass of RDH as of 2012 May 4. | 57 // we must down cast. RDHI is the only subclass of RDH as of 2012 May 4. |
56 scoped_ptr<net::URLRequest> request( | 58 scoped_ptr<net::URLRequest> request( |
57 params->resource_context()->GetRequestContext()->CreateRequest( | 59 params->resource_context()->GetRequestContext()->CreateRequest( |
58 params->url(), NULL)); | 60 params->url(), NULL)); |
59 request->set_referrer(params->referrer().url.spec()); | 61 request->set_referrer(params->referrer().url.spec()); |
60 webkit_glue::ConfigureURLRequestForReferrerPolicy( | 62 webkit_glue::ConfigureURLRequestForReferrerPolicy( |
61 request.get(), params->referrer().policy); | 63 request.get(), params->referrer().policy); |
(...skipping 10 matching lines...) Expand all Loading... | |
72 // The POST in this case does not have an actual body, and only works | 74 // The POST in this case does not have an actual body, and only works |
73 // when retrieving data from cache. This is done because we don't want | 75 // when retrieving data from cache. This is done because we don't want |
74 // to do a re-POST without user consent, and currently don't have a good | 76 // to do a re-POST without user consent, and currently don't have a good |
75 // plan on how to display the UI for that. | 77 // plan on how to display the UI for that. |
76 DCHECK(params->prefer_cache()); | 78 DCHECK(params->prefer_cache()); |
77 DCHECK(params->method() == "POST"); | 79 DCHECK(params->method() == "POST"); |
78 ScopedVector<net::UploadElementReader> element_readers; | 80 ScopedVector<net::UploadElementReader> element_readers; |
79 request->set_upload(make_scoped_ptr( | 81 request->set_upload(make_scoped_ptr( |
80 new net::UploadDataStream(&element_readers, params->post_id()))); | 82 new net::UploadDataStream(&element_readers, params->post_id()))); |
81 } | 83 } |
84 | |
85 // If we're not at the beginning of the file, retrieve only the remaining | |
86 // portion. | |
87 if (params->offset() > 0) { | |
88 request->SetExtraRequestHeaderByName( | |
89 "Range", | |
90 StringPrintf("bytes=%" PRId64 "-", params->offset()), | |
91 true); | |
92 | |
93 // If we've asked for a range, we want to make sure that we only | |
94 // get that range if our current copy of the information is good. | |
95 if (!params->last_modified().empty()) { | |
96 request->SetExtraRequestHeaderByName("If-Unmodified-Since", | |
97 params->last_modified(), | |
98 true); | |
99 } | |
100 if (!params->etag().empty()) { | |
101 request->SetExtraRequestHeaderByName("If-Match", params->etag(), true); | |
102 } | |
103 } | |
104 | |
82 for (DownloadUrlParameters::RequestHeadersType::const_iterator iter | 105 for (DownloadUrlParameters::RequestHeadersType::const_iterator iter |
83 = params->request_headers_begin(); | 106 = params->request_headers_begin(); |
84 iter != params->request_headers_end(); | 107 iter != params->request_headers_end(); |
85 ++iter) { | 108 ++iter) { |
86 request->SetExtraRequestHeaderByName( | 109 request->SetExtraRequestHeaderByName( |
87 iter->first, iter->second, false/*overwrite*/); | 110 iter->first, iter->second, false/*overwrite*/); |
88 } | 111 } |
89 | 112 |
90 scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo()); | 113 scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo()); |
91 save_info->file_path = params->file_path(); | 114 save_info->file_path = params->file_path(); |
92 save_info->suggested_name = params->suggested_name(); | 115 save_info->suggested_name = params->suggested_name(); |
93 save_info->offset = params->offset(); | 116 save_info->offset = params->offset(); |
94 save_info->hash_state = params->hash_state(); | 117 save_info->hash_state = params->hash_state(); |
95 save_info->prompt_for_save_location = params->prompt(); | 118 save_info->prompt_for_save_location = params->prompt(); |
96 save_info->file_stream = params->GetFileStream(); | 119 save_info->file_stream = params->GetFileStream(); |
97 | 120 |
98 params->resource_dispatcher_host()->BeginDownload( | 121 params->resource_dispatcher_host()->BeginDownload( |
99 request.Pass(), | 122 request.Pass(), |
100 params->content_initiated(), | 123 params->content_initiated(), |
101 params->resource_context(), | 124 params->resource_context(), |
102 params->render_process_host_id(), | 125 params->render_process_host_id(), |
103 params->render_view_host_routing_id(), | 126 params->render_view_host_routing_id(), |
104 params->prefer_cache(), | 127 params->prefer_cache(), |
105 save_info.Pass(), | 128 save_info.Pass(), |
129 download_id, | |
106 params->callback()); | 130 params->callback()); |
107 } | 131 } |
108 | 132 |
109 class MapValueIteratorAdapter { | 133 class MapValueIteratorAdapter { |
110 public: | 134 public: |
111 explicit MapValueIteratorAdapter( | 135 explicit MapValueIteratorAdapter( |
112 base::hash_map<int64, DownloadItem*>::const_iterator iter) | 136 base::hash_map<int64, DownloadItem*>::const_iterator iter) |
113 : iter_(iter) { | 137 : iter_(iter) { |
114 } | 138 } |
115 ~MapValueIteratorAdapter() {} | 139 ~MapValueIteratorAdapter() {} |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
166 received_bytes, | 190 received_bytes, |
167 total_bytes, | 191 total_bytes, |
168 state, | 192 state, |
169 opened, | 193 opened, |
170 bound_net_log); | 194 bound_net_log); |
171 } | 195 } |
172 | 196 |
173 virtual DownloadItemImpl* CreateActiveItem( | 197 virtual DownloadItemImpl* CreateActiveItem( |
174 DownloadItemImplDelegate* delegate, | 198 DownloadItemImplDelegate* delegate, |
175 const DownloadCreateInfo& info, | 199 const DownloadCreateInfo& info, |
176 scoped_ptr<DownloadRequestHandleInterface> request_handle, | |
177 const net::BoundNetLog& bound_net_log) OVERRIDE { | 200 const net::BoundNetLog& bound_net_log) OVERRIDE { |
178 return new DownloadItemImpl(delegate, info, request_handle.Pass(), | 201 return new DownloadItemImpl(delegate, info, bound_net_log); |
179 bound_net_log); | |
180 } | 202 } |
181 | 203 |
182 virtual DownloadItemImpl* CreateSavePageItem( | 204 virtual DownloadItemImpl* CreateSavePageItem( |
183 DownloadItemImplDelegate* delegate, | 205 DownloadItemImplDelegate* delegate, |
184 const FilePath& path, | 206 const FilePath& path, |
185 const GURL& url, | 207 const GURL& url, |
186 DownloadId download_id, | 208 DownloadId download_id, |
187 const std::string& mime_type, | 209 const std::string& mime_type, |
188 const net::BoundNetLog& bound_net_log) OVERRIDE { | 210 const net::BoundNetLog& bound_net_log) OVERRIDE { |
189 return new DownloadItemImpl(delegate, path, url, download_id, | 211 return new DownloadItemImpl(delegate, path, url, download_id, |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
333 browser_context_ = browser_context; | 355 browser_context_ = browser_context; |
334 | 356 |
335 return true; | 357 return true; |
336 } | 358 } |
337 | 359 |
338 DownloadItem* DownloadManagerImpl::StartDownload( | 360 DownloadItem* DownloadManagerImpl::StartDownload( |
339 scoped_ptr<DownloadCreateInfo> info, | 361 scoped_ptr<DownloadCreateInfo> info, |
340 scoped_ptr<ByteStreamReader> stream) { | 362 scoped_ptr<ByteStreamReader> stream) { |
341 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 363 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
342 | 364 |
343 net::BoundNetLog bound_net_log = | |
344 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD); | |
345 | |
346 FilePath default_download_directory; | 365 FilePath default_download_directory; |
347 if (delegate_) { | 366 if (delegate_) { |
348 FilePath website_save_directory; // Unused | 367 FilePath website_save_directory; // Unused |
349 bool skip_dir_check = false; // Unused | 368 bool skip_dir_check = false; // Unused |
350 delegate_->GetSaveDir(GetBrowserContext(), &website_save_directory, | 369 delegate_->GetSaveDir(GetBrowserContext(), &website_save_directory, |
351 &default_download_directory, &skip_dir_check); | 370 &default_download_directory, &skip_dir_check); |
352 } | 371 } |
353 | 372 |
354 // We create the DownloadItem before the DownloadFile because the | 373 // We create the DownloadItem before the DownloadFile because the |
355 // DownloadItem already needs to handle a state in which there is | 374 // DownloadItem already needs to handle a state in which there is |
356 // no associated DownloadFile (history downloads, !IN_PROGRESS downloads) | 375 // no associated DownloadFile (history downloads, !IN_PROGRESS downloads) |
357 DownloadItemImpl* download = | 376 DownloadItemImpl* download = GetOrCreateDownloadItem(info.get()); |
358 CreateDownloadItem(info.get(), bound_net_log); | |
359 scoped_ptr<DownloadFile> download_file( | 377 scoped_ptr<DownloadFile> download_file( |
360 file_factory_->CreateFile( | 378 file_factory_->CreateFile( |
361 info->save_info.Pass(), default_download_directory, | 379 info->save_info.Pass(), default_download_directory, |
362 info->url(), info->referrer_url, | 380 info->url(), info->referrer_url, |
363 delegate_->GenerateFileHash(), | 381 delegate_->GenerateFileHash(), |
364 stream.Pass(), bound_net_log, | 382 stream.Pass(), download->GetBoundNetLog(), |
365 download->DestinationObserverAsWeakPtr())); | 383 download->DestinationObserverAsWeakPtr())); |
366 download->Start(download_file.Pass()); | 384 scoped_ptr<DownloadRequestHandleInterface> req_handle( |
385 new DownloadRequestHandle(info->request_handle)); | |
386 download->Start(download_file.Pass(), req_handle.Pass()); | |
367 | 387 |
368 // Delay notification until after Start() so that download_file is bound | 388 // Delay notification until after Start() so that download_file is bound |
369 // to download and all the usual setters (e.g. Cancel) work. | 389 // to download and all the usual setters (e.g. Cancel) work. |
370 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, download)); | 390 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, download)); |
371 | 391 |
372 return download; | 392 return download; |
373 } | 393 } |
374 | 394 |
375 void DownloadManagerImpl::CheckForHistoryFilesRemoval() { | 395 void DownloadManagerImpl::CheckForHistoryFilesRemoval() { |
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 396 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
408 void DownloadManagerImpl::OnFileRemovalDetected(int32 download_id) { | 428 void DownloadManagerImpl::OnFileRemovalDetected(int32 download_id) { |
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 429 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
410 if (ContainsKey(downloads_, download_id)) | 430 if (ContainsKey(downloads_, download_id)) |
411 downloads_[download_id]->OnDownloadedFileRemoved(); | 431 downloads_[download_id]->OnDownloadedFileRemoved(); |
412 } | 432 } |
413 | 433 |
414 BrowserContext* DownloadManagerImpl::GetBrowserContext() const { | 434 BrowserContext* DownloadManagerImpl::GetBrowserContext() const { |
415 return browser_context_; | 435 return browser_context_; |
416 } | 436 } |
417 | 437 |
418 DownloadItemImpl* DownloadManagerImpl::CreateDownloadItem( | 438 DownloadItemImpl* DownloadManagerImpl::GetOrCreateDownloadItem( |
419 DownloadCreateInfo* info, const net::BoundNetLog& bound_net_log) { | 439 DownloadCreateInfo* info) { |
420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 440 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
421 | 441 |
422 if (!info->download_id.IsValid()) | 442 if (!info->download_id.IsValid()) |
benjhayden
2013/01/08 16:41:17
Just to be clear, this allows mischievous callers
Randy Smith (Not in Mondays)
2013/01/09 22:34:37
That's why I didn't want it as part of the Downloa
| |
423 info->download_id = GetNextId(); | 443 info->download_id = GetNextId(); |
424 DownloadItemImpl* download = item_factory_->CreateActiveItem( | |
425 this, *info, | |
426 scoped_ptr<DownloadRequestHandleInterface>( | |
427 new DownloadRequestHandle(info->request_handle)).Pass(), | |
428 bound_net_log); | |
429 | 444 |
430 DCHECK(!ContainsKey(downloads_, download->GetId())); | 445 DownloadItemImpl* download = NULL; |
431 downloads_[download->GetId()] = download; | 446 if (ContainsKey(downloads_, info->download_id.local())) { |
447 // Resuming an existing download. | |
448 download = downloads_[info->download_id.local()]; | |
449 DCHECK(download->IsInterrupted()); | |
450 } else { | |
451 // New download | |
452 net::BoundNetLog bound_net_log = | |
453 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD); | |
454 download = item_factory_->CreateActiveItem(this, *info, bound_net_log); | |
455 downloads_[download->GetId()] = download; | |
456 } | |
457 | |
432 return download; | 458 return download; |
433 } | 459 } |
434 | 460 |
435 DownloadItemImpl* DownloadManagerImpl::CreateSavePackageDownloadItem( | 461 DownloadItemImpl* DownloadManagerImpl::CreateSavePackageDownloadItem( |
436 const FilePath& main_file_path, | 462 const FilePath& main_file_path, |
437 const GURL& page_url, | 463 const GURL& page_url, |
438 const std::string& mime_type, | 464 const std::string& mime_type, |
439 DownloadItem::Observer* observer) { | 465 DownloadItem::Observer* observer) { |
440 net::BoundNetLog bound_net_log = | 466 net::BoundNetLog bound_net_log = |
441 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD); | 467 net::BoundNetLog::Make(net_log_, net::NetLog::SOURCE_DOWNLOAD); |
(...skipping 17 matching lines...) Expand all Loading... | |
459 return download_item; | 485 return download_item; |
460 } | 486 } |
461 | 487 |
462 void DownloadManagerImpl::CancelDownload(int32 download_id) { | 488 void DownloadManagerImpl::CancelDownload(int32 download_id) { |
463 DownloadItem* download = GetDownload(download_id); | 489 DownloadItem* download = GetDownload(download_id); |
464 if (!download || !download->IsInProgress()) | 490 if (!download || !download->IsInProgress()) |
465 return; | 491 return; |
466 download->Cancel(true); | 492 download->Cancel(true); |
467 } | 493 } |
468 | 494 |
495 // Resume a download of a specific URL. We send the request to the | |
496 // ResourceDispatcherHost, and let it send us responses like a regular | |
497 // download. | |
498 void DownloadManagerImpl::ResumeInterruptedDownload( | |
499 scoped_ptr<content::DownloadUrlParameters> params, | |
500 content::DownloadId id) { | |
501 BrowserThread::PostTask( | |
502 BrowserThread::IO, | |
503 FROM_HERE, | |
504 base::Bind(&BeginDownload, base::Passed(params.Pass()), id)); | |
505 } | |
506 | |
469 void DownloadManagerImpl::SetDownloadItemFactoryForTesting( | 507 void DownloadManagerImpl::SetDownloadItemFactoryForTesting( |
470 scoped_ptr<DownloadItemFactory> item_factory) { | 508 scoped_ptr<DownloadItemFactory> item_factory) { |
471 item_factory_ = item_factory.Pass(); | 509 item_factory_ = item_factory.Pass(); |
472 } | 510 } |
473 | 511 |
474 void DownloadManagerImpl::SetDownloadFileFactoryForTesting( | 512 void DownloadManagerImpl::SetDownloadFileFactoryForTesting( |
475 scoped_ptr<DownloadFileFactory> file_factory) { | 513 scoped_ptr<DownloadFileFactory> file_factory) { |
476 file_factory_ = file_factory.Pass(); | 514 file_factory_ = file_factory.Pass(); |
477 } | 515 } |
478 | 516 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
538 } | 576 } |
539 | 577 |
540 void DownloadManagerImpl::DownloadUrl( | 578 void DownloadManagerImpl::DownloadUrl( |
541 scoped_ptr<DownloadUrlParameters> params) { | 579 scoped_ptr<DownloadUrlParameters> params) { |
542 if (params->post_id() >= 0) { | 580 if (params->post_id() >= 0) { |
543 // Check this here so that the traceback is more useful. | 581 // Check this here so that the traceback is more useful. |
544 DCHECK(params->prefer_cache()); | 582 DCHECK(params->prefer_cache()); |
545 DCHECK(params->method() == "POST"); | 583 DCHECK(params->method() == "POST"); |
546 } | 584 } |
547 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( | 585 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind( |
548 &BeginDownload, base::Passed(¶ms))); | 586 &BeginDownload, base::Passed(¶ms), DownloadId())); |
549 } | 587 } |
550 | 588 |
551 void DownloadManagerImpl::AddObserver(Observer* observer) { | 589 void DownloadManagerImpl::AddObserver(Observer* observer) { |
552 observers_.AddObserver(observer); | 590 observers_.AddObserver(observer); |
553 } | 591 } |
554 | 592 |
555 void DownloadManagerImpl::RemoveObserver(Observer* observer) { | 593 void DownloadManagerImpl::RemoveObserver(Observer* observer) { |
556 observers_.RemoveObserver(observer); | 594 observers_.RemoveObserver(observer); |
557 } | 595 } |
558 | 596 |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
628 it != downloads_.end(); ++it) { | 666 it != downloads_.end(); ++it) { |
629 DownloadItemImpl* item = it->second; | 667 DownloadItemImpl* item = it->second; |
630 if (item->IsComplete() && | 668 if (item->IsComplete() && |
631 !item->GetOpened()) | 669 !item->GetOpened()) |
632 ++num_unopened; | 670 ++num_unopened; |
633 } | 671 } |
634 RecordOpensOutstanding(num_unopened); | 672 RecordOpensOutstanding(num_unopened); |
635 } | 673 } |
636 | 674 |
637 } // namespace content | 675 } // namespace content |
OLD | NEW |