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 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
48 #include "url/origin.h" | 48 #include "url/origin.h" |
49 | 49 |
50 namespace content { | 50 namespace content { |
51 namespace { | 51 namespace { |
52 | 52 |
53 scoped_ptr<UrlDownloader, BrowserThread::DeleteOnIOThread> BeginDownload( | 53 scoped_ptr<UrlDownloader, BrowserThread::DeleteOnIOThread> BeginDownload( |
54 scoped_ptr<DownloadUrlParameters> params, | 54 scoped_ptr<DownloadUrlParameters> params, |
55 uint32_t download_id, | 55 uint32_t download_id, |
56 base::WeakPtr<DownloadManagerImpl> download_manager) { | 56 base::WeakPtr<DownloadManagerImpl> download_manager) { |
57 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 57 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
58 // ResourceDispatcherHost{Base} is-not-a URLRequest::Delegate, and | 58 |
59 // DownloadUrlParameters can-not include resource_dispatcher_host_impl.h, so | 59 scoped_ptr<net::URLRequest> url_request = |
60 // we must down cast. RDHI is the only subclass of RDH as of 2012 May 4. | 60 DownloadRequestCore::CreateRequestOnIOThread(download_id, params.get()); |
61 scoped_ptr<net::URLRequest> request( | 61 |
62 params->resource_context()->GetRequestContext()->CreateRequest( | 62 // If there's a valid renderer process associated with the request, then the |
63 params->url(), net::DEFAULT_PRIORITY, NULL)); | 63 // request should be driven by the ResourceLoader. Pass it over to the |
64 request->set_method(params->method()); | 64 // ResourceDispatcherHostImpl which will in turn pass it along to the |
65 if (!params->post_body().empty()) { | 65 // ResourceLoader. |
66 const std::string& body = params->post_body(); | 66 if (params->render_process_host_id() != -1) { |
67 scoped_ptr<net::UploadElementReader> reader( | 67 DownloadInterruptReason reason = |
68 net::UploadOwnedBytesElementReader::CreateWithString(body)); | 68 ResourceDispatcherHostImpl::Get()->BeginDownload( |
69 request->set_upload( | 69 std::move(url_request), params->referrer(), |
70 net::ElementsUploadDataStream::CreateWithReader(std::move(reader), 0)); | 70 params->content_initiated(), params->resource_context(), |
71 } | 71 params->render_process_host_id(), |
72 if (params->post_id() >= 0) { | 72 params->render_view_host_routing_id(), |
73 // The POST in this case does not have an actual body, and only works | 73 params->render_frame_host_routing_id(), |
74 // when retrieving data from cache. This is done because we don't want | 74 params->do_not_prompt_for_login()); |
75 // to do a re-POST without user consent, and currently don't have a good | 75 |
76 // plan on how to display the UI for that. | 76 // If the download was accepted, the DownloadResourceHandler is now |
77 DCHECK(params->prefer_cache()); | 77 // responsible for driving the request to completion. |
78 DCHECK_EQ("POST", params->method()); | 78 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) |
79 std::vector<scoped_ptr<net::UploadElementReader>> element_readers; | 79 return nullptr; |
80 request->set_upload(make_scoped_ptr(new net::ElementsUploadDataStream( | 80 |
81 std::move(element_readers), params->post_id()))); | 81 // Otherwise, create an interrupted download. |
82 scoped_ptr<DownloadCreateInfo> failed_created_info( | |
83 new DownloadCreateInfo(base::Time::Now(), net::BoundNetLog(), | |
84 make_scoped_ptr(new DownloadSaveInfo))); | |
85 failed_created_info->url_chain.push_back(params->url()); | |
86 failed_created_info->result = reason; | |
87 scoped_ptr<ByteStreamReader> empty_byte_stream; | |
88 BrowserThread::PostTask( | |
89 BrowserThread::UI, FROM_HERE, | |
90 base::Bind(&DownloadManager::StartDownload, download_manager, | |
91 base::Passed(&failed_created_info), | |
92 base::Passed(&empty_byte_stream), params->callback())); | |
93 return nullptr; | |
82 } | 94 } |
83 | 95 |
84 // If we're not at the beginning of the file, retrieve only the remaining | |
85 // portion. | |
86 bool has_last_modified = !params->last_modified().empty(); | |
87 bool has_etag = !params->etag().empty(); | |
88 | |
89 // If we've asked for a range, we want to make sure that we only | |
90 // get that range if our current copy of the information is good. | |
91 // We shouldn't be asked to continue if we don't have a verifier. | |
92 DCHECK(params->offset() == 0 || has_etag || has_last_modified); | |
93 | |
94 if (params->offset() > 0 && (has_etag || has_last_modified)) { | |
95 request->SetExtraRequestHeaderByName( | |
96 "Range", | |
97 base::StringPrintf("bytes=%" PRId64 "-", params->offset()), | |
98 true); | |
99 | |
100 // In accordance with RFC 2616 Section 14.27, use If-Range to specify that | |
101 // the server return the entire entity if the validator doesn't match. | |
102 // Last-Modified can be used in the absence of ETag as a validator if the | |
103 // response headers satisfied the HttpUtil::HasStrongValidators() predicate. | |
104 // | |
105 // This function assumes that HasStrongValidators() was true and that the | |
106 // ETag and Last-Modified header values supplied are valid. | |
107 request->SetExtraRequestHeaderByName( | |
108 "If-Range", has_etag ? params->etag() : params->last_modified(), true); | |
109 } | |
110 | |
111 for (DownloadUrlParameters::RequestHeadersType::const_iterator iter | |
112 = params->request_headers_begin(); | |
113 iter != params->request_headers_end(); | |
114 ++iter) { | |
115 request->SetExtraRequestHeaderByName( | |
116 iter->first, iter->second, false /*overwrite*/); | |
117 } | |
118 | |
119 scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo()); | |
120 save_info->file_path = params->file_path(); | |
121 save_info->suggested_name = params->suggested_name(); | |
122 save_info->offset = params->offset(); | |
123 save_info->hash_state = params->hash_state(); | |
124 save_info->prompt_for_save_location = params->prompt(); | |
125 save_info->file = params->GetFile(); | |
126 | |
127 if (params->render_process_host_id() != -1) { | |
128 ResourceDispatcherHost::Get()->BeginDownload( | |
129 std::move(request), params->referrer(), params->content_initiated(), | |
130 params->resource_context(), params->render_process_host_id(), | |
131 params->render_view_host_routing_id(), | |
132 params->render_frame_host_routing_id(), params->prefer_cache(), | |
133 params->do_not_prompt_for_login(), std::move(save_info), download_id, | |
134 params->callback()); | |
135 return nullptr; | |
136 } | |
137 return scoped_ptr<UrlDownloader, BrowserThread::DeleteOnIOThread>( | 96 return scoped_ptr<UrlDownloader, BrowserThread::DeleteOnIOThread>( |
138 UrlDownloader::BeginDownload(download_manager, std::move(request), | 97 UrlDownloader::BeginDownload(download_manager, std::move(url_request), |
139 params->referrer(), params->prefer_cache(), | 98 params->referrer()) |
140 std::move(save_info), download_id, | |
141 params->callback()) | |
142 .release()); | 99 .release()); |
143 } | 100 } |
144 | 101 |
145 class DownloadItemFactoryImpl : public DownloadItemFactory { | 102 class DownloadItemFactoryImpl : public DownloadItemFactory { |
146 public: | 103 public: |
147 DownloadItemFactoryImpl() {} | 104 DownloadItemFactoryImpl() {} |
148 ~DownloadItemFactoryImpl() override {} | 105 ~DownloadItemFactoryImpl() override {} |
149 | 106 |
150 DownloadItemImpl* CreatePersistedItem( | 107 DownloadItemImpl* CreatePersistedItem( |
151 DownloadItemImplDelegate* delegate, | 108 DownloadItemImplDelegate* delegate, |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
332 url_downloaders_.clear(); | 289 url_downloaders_.clear(); |
333 | 290 |
334 // We'll have nothing more to report to the observers after this point. | 291 // We'll have nothing more to report to the observers after this point. |
335 observers_.Clear(); | 292 observers_.Clear(); |
336 | 293 |
337 if (delegate_) | 294 if (delegate_) |
338 delegate_->Shutdown(); | 295 delegate_->Shutdown(); |
339 delegate_ = NULL; | 296 delegate_ = NULL; |
340 } | 297 } |
341 | 298 |
342 void DownloadManagerImpl::StartDownload( | 299 void DownloadManagerImpl::StartDownload( |
Randy Smith (Not in Mondays)
2016/02/10 21:48:45
Suggestion: I find myself wondering if we should c
asanka
2016/02/11 03:43:07
DII::Start() is, I think, OK since it starts the s
| |
343 scoped_ptr<DownloadCreateInfo> info, | 300 scoped_ptr<DownloadCreateInfo> info, |
344 scoped_ptr<ByteStreamReader> stream, | 301 scoped_ptr<ByteStreamReader> stream, |
345 const DownloadUrlParameters::OnStartedCallback& on_started) { | 302 const DownloadUrlParameters::OnStartedCallback& on_started) { |
346 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 303 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
347 DCHECK(info); | 304 DCHECK(info); |
305 // |stream| is only non-nil if the download request was successful. | |
306 DCHECK(info->result != DOWNLOAD_INTERRUPT_REASON_NONE || stream.get()); | |
Randy Smith (Not in Mondays)
2016/02/05 00:51:41
Should this be an XOR? I..e shouldn't result != N
asanka
2016/02/11 03:43:07
Done.
| |
307 DVLOG(20) << __FUNCTION__ << "()" | |
308 << " result=" << DownloadInterruptReasonToString(info->result); | |
348 uint32_t download_id = info->download_id; | 309 uint32_t download_id = info->download_id; |
349 const bool new_download = (download_id == content::DownloadItem::kInvalidId); | 310 const bool new_download = (download_id == content::DownloadItem::kInvalidId); |
350 base::Callback<void(uint32_t)> got_id(base::Bind( | 311 base::Callback<void(uint32_t)> got_id(base::Bind( |
351 &DownloadManagerImpl::StartDownloadWithId, weak_factory_.GetWeakPtr(), | 312 &DownloadManagerImpl::StartDownloadWithId, weak_factory_.GetWeakPtr(), |
352 base::Passed(&info), base::Passed(&stream), on_started, new_download)); | 313 base::Passed(&info), base::Passed(&stream), on_started, new_download)); |
353 if (new_download) { | 314 if (new_download) { |
354 GetNextId(got_id); | 315 GetNextId(got_id); |
355 } else { | 316 } else { |
356 got_id.Run(download_id); | 317 got_id.Run(download_id); |
357 } | 318 } |
(...skipping 15 matching lines...) Expand all Loading... | |
373 // Trying to resume an interrupted download. | 334 // Trying to resume an interrupted download. |
374 if (item_iterator == downloads_.end() || | 335 if (item_iterator == downloads_.end() || |
375 (item_iterator->second->GetState() == DownloadItem::CANCELLED)) { | 336 (item_iterator->second->GetState() == DownloadItem::CANCELLED)) { |
376 // If the download is no longer known to the DownloadManager, then it was | 337 // If the download is no longer known to the DownloadManager, then it was |
377 // removed after it was resumed. Ignore. If the download is cancelled | 338 // removed after it was resumed. Ignore. If the download is cancelled |
378 // while resuming, then also ignore the request. | 339 // while resuming, then also ignore the request. |
379 info->request_handle->CancelRequest(); | 340 info->request_handle->CancelRequest(); |
380 if (!on_started.is_null()) | 341 if (!on_started.is_null()) |
381 on_started.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); | 342 on_started.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); |
382 // The ByteStreamReader lives and dies on the FILE thread. | 343 // The ByteStreamReader lives and dies on the FILE thread. |
383 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, | 344 if (stream) |
384 stream.release()); | 345 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, |
346 stream.release()); | |
385 return; | 347 return; |
386 } | 348 } |
387 download = item_iterator->second; | 349 download = item_iterator->second; |
388 DCHECK_EQ(download->GetState(), DownloadItem::IN_PROGRESS); | |
389 download->MergeOriginInfoOnResume(*info); | |
390 } | 350 } |
391 | 351 |
392 base::FilePath default_download_directory; | 352 base::FilePath default_download_directory; |
393 if (delegate_) { | 353 if (delegate_) { |
394 base::FilePath website_save_directory; // Unused | 354 base::FilePath website_save_directory; // Unused |
395 bool skip_dir_check = false; // Unused | 355 bool skip_dir_check = false; // Unused |
396 delegate_->GetSaveDir(GetBrowserContext(), &website_save_directory, | 356 delegate_->GetSaveDir(GetBrowserContext(), &website_save_directory, |
397 &default_download_directory, &skip_dir_check); | 357 &default_download_directory, &skip_dir_check); |
398 } | 358 } |
399 | 359 |
400 // Create the download file and start the download. | 360 scoped_ptr<DownloadFile> download_file; |
401 scoped_ptr<DownloadFile> download_file(file_factory_->CreateFile( | |
402 std::move(info->save_info), default_download_directory, info->url(), | |
403 info->referrer_url, delegate_ && delegate_->GenerateFileHash(), | |
404 std::move(stream), download->GetBoundNetLog(), | |
405 download->DestinationObserverAsWeakPtr())); | |
406 | 361 |
407 // Attach the client ID identifying the app to the AV system. | 362 if (info->result == DOWNLOAD_INTERRUPT_REASON_NONE) { |
Randy Smith (Not in Mondays)
2016/02/05 00:51:41
nit, suggestion: I think this test is equivalent t
asanka
2016/02/11 03:43:07
Got it. Changed the other test to if(result == NON
| |
408 if (download_file.get() && delegate_) { | 363 DCHECK(stream.get()); |
Randy Smith (Not in Mondays)
2016/02/11 22:08:08
Hmmm. Was there a specific reason to removing thi
Randy Smith (Not in Mondays)
2016/02/12 18:01:18
Ping?
asanka
2016/02/12 18:31:46
It was redundant with the DCHECK at the top of the
Randy Smith (Not in Mondays)
2016/02/12 18:58:10
Nah, I'm good. Thanks for the pointer.
| |
409 download_file->SetClientGuid( | 364 // Create the download file and start the download. |
Randy Smith (Not in Mondays)
2016/02/05 00:51:41
nit: The placement of this comment makes me feel l
asanka
2016/02/11 03:43:07
I removed the extra comments which I thought were
| |
410 delegate_->ApplicationClientIdForFileScanning()); | 365 download_file.reset(file_factory_->CreateFile( |
366 *info->save_info, default_download_directory, info->url(), | |
367 info->referrer_url, delegate_ && delegate_->GenerateFileHash(), | |
368 std::move(info->save_info->file), std::move(stream), | |
369 download->GetBoundNetLog(), download->DestinationObserverAsWeakPtr())); | |
370 | |
371 // Attach the client ID identifying the app to the AV system. | |
372 if (download_file.get() && delegate_) { | |
Randy Smith (Not in Mondays)
2016/02/11 22:08:08
nit: My understanding of the style guide is that c
Randy Smith (Not in Mondays)
2016/02/12 18:01:18
Ping?
asanka
2016/02/12 18:31:46
Ah. Done.
| |
373 download_file->SetClientGuid( | |
374 delegate_->ApplicationClientIdForFileScanning()); | |
375 } | |
411 } | 376 } |
412 | 377 |
413 download->Start(std::move(download_file), std::move(info->request_handle)); | 378 download->Start(std::move(download_file), std::move(info->request_handle), |
379 *info); | |
414 | 380 |
415 // For interrupted downloads, Start() will transition the state to | 381 // For interrupted downloads, Start() will transition the state to |
416 // IN_PROGRESS and consumers will be notified via OnDownloadUpdated(). | 382 // IN_PROGRESS and consumers will be notified via OnDownloadUpdated(). |
417 // For new downloads, we notify here, rather than earlier, so that | 383 // For new downloads, we notify here, rather than earlier, so that |
418 // the download_file is bound to download and all the usual | 384 // the download_file is bound to download and all the usual |
419 // setters (e.g. Cancel) work. | 385 // setters (e.g. Cancel) work. |
420 if (new_download) | 386 if (new_download) |
421 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, download)); | 387 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, download)); |
422 | 388 |
423 if (!on_started.is_null()) | 389 if (!on_started.is_null()) |
424 on_started.Run(download, DOWNLOAD_INTERRUPT_REASON_NONE); | 390 on_started.Run(download, info->result); |
425 } | 391 } |
426 | 392 |
427 void DownloadManagerImpl::CheckForHistoryFilesRemoval() { | 393 void DownloadManagerImpl::CheckForHistoryFilesRemoval() { |
428 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 394 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
429 for (DownloadMap::iterator it = downloads_.begin(); | 395 for (DownloadMap::iterator it = downloads_.begin(); |
430 it != downloads_.end(); ++it) { | 396 it != downloads_.end(); ++it) { |
431 DownloadItemImpl* item = it->second; | 397 DownloadItemImpl* item = it->second; |
432 CheckForFileRemoval(item); | 398 CheckForFileRemoval(item); |
433 } | 399 } |
434 } | 400 } |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
739 if (delegate_) | 705 if (delegate_) |
740 delegate_->OpenDownload(download); | 706 delegate_->OpenDownload(download); |
741 } | 707 } |
742 | 708 |
743 void DownloadManagerImpl::ShowDownloadInShell(DownloadItemImpl* download) { | 709 void DownloadManagerImpl::ShowDownloadInShell(DownloadItemImpl* download) { |
744 if (delegate_) | 710 if (delegate_) |
745 delegate_->ShowDownloadInShell(download); | 711 delegate_->ShowDownloadInShell(download); |
746 } | 712 } |
747 | 713 |
748 } // namespace content | 714 } // namespace content |
OLD | NEW |