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 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 delegate_->Shutdown(); | 294 delegate_->Shutdown(); |
338 delegate_ = NULL; | 295 delegate_ = NULL; |
339 } | 296 } |
340 | 297 |
341 void DownloadManagerImpl::StartDownload( | 298 void DownloadManagerImpl::StartDownload( |
342 scoped_ptr<DownloadCreateInfo> info, | 299 scoped_ptr<DownloadCreateInfo> info, |
343 scoped_ptr<ByteStreamReader> stream, | 300 scoped_ptr<ByteStreamReader> stream, |
344 const DownloadUrlParameters::OnStartedCallback& on_started) { | 301 const DownloadUrlParameters::OnStartedCallback& on_started) { |
345 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 302 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
346 DCHECK(info); | 303 DCHECK(info); |
| 304 // |stream| is only non-nil if the download request was successful. |
| 305 DCHECK((info->result == DOWNLOAD_INTERRUPT_REASON_NONE && stream.get()) || |
| 306 (info->result != DOWNLOAD_INTERRUPT_REASON_NONE && !stream.get())); |
| 307 DVLOG(20) << __FUNCTION__ << "()" |
| 308 << " result=" << DownloadInterruptReasonToString(info->result); |
347 uint32_t download_id = info->download_id; | 309 uint32_t download_id = info->download_id; |
348 const bool new_download = (download_id == content::DownloadItem::kInvalidId); | 310 const bool new_download = (download_id == content::DownloadItem::kInvalidId); |
349 base::Callback<void(uint32_t)> got_id(base::Bind( | 311 base::Callback<void(uint32_t)> got_id(base::Bind( |
350 &DownloadManagerImpl::StartDownloadWithId, weak_factory_.GetWeakPtr(), | 312 &DownloadManagerImpl::StartDownloadWithId, weak_factory_.GetWeakPtr(), |
351 base::Passed(&info), base::Passed(&stream), on_started, new_download)); | 313 base::Passed(&info), base::Passed(&stream), on_started, new_download)); |
352 if (new_download) { | 314 if (new_download) { |
353 GetNextId(got_id); | 315 GetNextId(got_id); |
354 } else { | 316 } else { |
355 got_id.Run(download_id); | 317 got_id.Run(download_id); |
356 } | 318 } |
(...skipping 15 matching lines...) Expand all Loading... |
372 // Trying to resume an interrupted download. | 334 // Trying to resume an interrupted download. |
373 if (item_iterator == downloads_.end() || | 335 if (item_iterator == downloads_.end() || |
374 (item_iterator->second->GetState() == DownloadItem::CANCELLED)) { | 336 (item_iterator->second->GetState() == DownloadItem::CANCELLED)) { |
375 // 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 |
376 // removed after it was resumed. Ignore. If the download is cancelled | 338 // removed after it was resumed. Ignore. If the download is cancelled |
377 // while resuming, then also ignore the request. | 339 // while resuming, then also ignore the request. |
378 info->request_handle->CancelRequest(); | 340 info->request_handle->CancelRequest(); |
379 if (!on_started.is_null()) | 341 if (!on_started.is_null()) |
380 on_started.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); | 342 on_started.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); |
381 // The ByteStreamReader lives and dies on the FILE thread. | 343 // The ByteStreamReader lives and dies on the FILE thread. |
382 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, | 344 if (info->result == DOWNLOAD_INTERRUPT_REASON_NONE) |
383 stream.release()); | 345 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, |
| 346 stream.release()); |
384 return; | 347 return; |
385 } | 348 } |
386 download = item_iterator->second; | 349 download = item_iterator->second; |
387 DCHECK_EQ(download->GetState(), DownloadItem::IN_PROGRESS); | |
388 download->MergeOriginInfoOnResume(*info); | |
389 } | 350 } |
390 | 351 |
391 base::FilePath default_download_directory; | 352 base::FilePath default_download_directory; |
392 if (delegate_) { | 353 if (delegate_) { |
393 base::FilePath website_save_directory; // Unused | 354 base::FilePath website_save_directory; // Unused |
394 bool skip_dir_check = false; // Unused | 355 bool skip_dir_check = false; // Unused |
395 delegate_->GetSaveDir(GetBrowserContext(), &website_save_directory, | 356 delegate_->GetSaveDir(GetBrowserContext(), &website_save_directory, |
396 &default_download_directory, &skip_dir_check); | 357 &default_download_directory, &skip_dir_check); |
397 } | 358 } |
398 | 359 |
399 // Create the download file and start the download. | 360 scoped_ptr<DownloadFile> download_file; |
400 scoped_ptr<DownloadFile> download_file(file_factory_->CreateFile( | |
401 std::move(info->save_info), default_download_directory, info->url(), | |
402 info->referrer_url, delegate_ && delegate_->GenerateFileHash(), | |
403 std::move(stream), download->GetBoundNetLog(), | |
404 download->DestinationObserverAsWeakPtr())); | |
405 | 361 |
406 // Attach the client ID identifying the app to the AV system. | 362 if (info->result == DOWNLOAD_INTERRUPT_REASON_NONE) { |
407 if (download_file.get() && delegate_) { | 363 DCHECK(stream.get()); |
408 download_file->SetClientGuid( | 364 download_file.reset(file_factory_->CreateFile( |
409 delegate_->ApplicationClientIdForFileScanning()); | 365 *info->save_info, default_download_directory, info->url(), |
| 366 info->referrer_url, delegate_ && delegate_->GenerateFileHash(), |
| 367 std::move(info->save_info->file), std::move(stream), |
| 368 download->GetBoundNetLog(), download->DestinationObserverAsWeakPtr())); |
| 369 |
| 370 if (download_file.get() && delegate_) { |
| 371 download_file->SetClientGuid( |
| 372 delegate_->ApplicationClientIdForFileScanning()); |
| 373 } |
410 } | 374 } |
411 | 375 |
412 download->Start(std::move(download_file), std::move(info->request_handle)); | 376 download->Start(std::move(download_file), std::move(info->request_handle), |
| 377 *info); |
413 | 378 |
414 // For interrupted downloads, Start() will transition the state to | 379 // For interrupted downloads, Start() will transition the state to |
415 // IN_PROGRESS and consumers will be notified via OnDownloadUpdated(). | 380 // IN_PROGRESS and consumers will be notified via OnDownloadUpdated(). |
416 // For new downloads, we notify here, rather than earlier, so that | 381 // For new downloads, we notify here, rather than earlier, so that |
417 // the download_file is bound to download and all the usual | 382 // the download_file is bound to download and all the usual |
418 // setters (e.g. Cancel) work. | 383 // setters (e.g. Cancel) work. |
419 if (new_download) | 384 if (new_download) |
420 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, download)); | 385 FOR_EACH_OBSERVER(Observer, observers_, OnDownloadCreated(this, download)); |
421 | 386 |
422 if (!on_started.is_null()) | 387 if (!on_started.is_null()) |
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
729 if (delegate_) | 694 if (delegate_) |
730 delegate_->OpenDownload(download); | 695 delegate_->OpenDownload(download); |
731 } | 696 } |
732 | 697 |
733 void DownloadManagerImpl::ShowDownloadInShell(DownloadItemImpl* download) { | 698 void DownloadManagerImpl::ShowDownloadInShell(DownloadItemImpl* download) { |
734 if (delegate_) | 699 if (delegate_) |
735 delegate_->ShowDownloadInShell(download); | 700 delegate_->ShowDownloadInShell(download); |
736 } | 701 } |
737 | 702 |
738 } // namespace content | 703 } // namespace content |
OLD | NEW |