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

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

Issue 10392111: Use ByteStream in downloads system to decouple source and sink. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync'd to LKGR. Created 8 years, 6 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_file_manager.h" 5 #include "content/browser/download/download_file_manager.h"
6 6
7 #include <set> 7 #include <set>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/file_util.h" 11 #include "base/file_util.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/stl_util.h" 13 #include "base/stl_util.h"
14 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
15 #include "content/browser/download/base_file.h" 15 #include "content/browser/download/base_file.h"
16 #include "content/browser/download/download_buffer.h"
17 #include "content/browser/download/download_create_info.h" 16 #include "content/browser/download/download_create_info.h"
18 #include "content/browser/download/download_file_impl.h" 17 #include "content/browser/download/download_file_impl.h"
19 #include "content/browser/download/download_interrupt_reasons_impl.h" 18 #include "content/browser/download/download_interrupt_reasons_impl.h"
20 #include "content/browser/download/download_request_handle.h" 19 #include "content/browser/download/download_request_handle.h"
21 #include "content/browser/download/download_stats.h" 20 #include "content/browser/download/download_stats.h"
22 #include "content/browser/power_save_blocker.h" 21 #include "content/browser/power_save_blocker.h"
23 #include "content/browser/web_contents/web_contents_impl.h" 22 #include "content/browser/web_contents/web_contents_impl.h"
24 #include "content/public/browser/browser_thread.h" 23 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/download_manager.h" 24 #include "content/public/browser/download_manager.h"
26 #include "content/public/browser/download_manager_delegate.h" 25 #include "content/public/browser/download_manager_delegate.h"
27 #include "googleurl/src/gurl.h" 26 #include "googleurl/src/gurl.h"
28 #include "net/base/io_buffer.h" 27 #include "net/base/io_buffer.h"
29 28
30 using content::BrowserThread; 29 using content::BrowserThread;
31 using content::DownloadFile; 30 using content::DownloadFile;
32 using content::DownloadId; 31 using content::DownloadId;
33 using content::DownloadManager; 32 using content::DownloadManager;
34 33
35 namespace { 34 namespace {
36 35
37 class DownloadFileFactoryImpl 36 class DownloadFileFactoryImpl
38 : public DownloadFileManager::DownloadFileFactory { 37 : public DownloadFileManager::DownloadFileFactory {
39 public: 38 public:
40 DownloadFileFactoryImpl() {} 39 DownloadFileFactoryImpl() {}
41 40
42 virtual content::DownloadFile* CreateFile( 41 virtual content::DownloadFile* CreateFile(
43 DownloadCreateInfo* info, 42 DownloadCreateInfo* info,
43 scoped_ptr<content::ByteStreamReader> stream,
44 const DownloadRequestHandle& request_handle, 44 const DownloadRequestHandle& request_handle,
45 DownloadManager* download_manager, 45 DownloadManager* download_manager,
46 bool calculate_hash, 46 bool calculate_hash,
47 const net::BoundNetLog& bound_net_log) OVERRIDE; 47 const net::BoundNetLog& bound_net_log) OVERRIDE;
48 }; 48 };
49 49
50 DownloadFile* DownloadFileFactoryImpl::CreateFile( 50 DownloadFile* DownloadFileFactoryImpl::CreateFile(
51 DownloadCreateInfo* info, 51 DownloadCreateInfo* info,
52 scoped_ptr<content::ByteStreamReader> stream,
52 const DownloadRequestHandle& request_handle, 53 const DownloadRequestHandle& request_handle,
53 DownloadManager* download_manager, 54 DownloadManager* download_manager,
54 bool calculate_hash, 55 bool calculate_hash,
55 const net::BoundNetLog& bound_net_log) { 56 const net::BoundNetLog& bound_net_log) {
56 return new DownloadFileImpl( 57 return new DownloadFileImpl(
57 info, new DownloadRequestHandle(request_handle), 58 info, stream.Pass(), new DownloadRequestHandle(request_handle),
58 download_manager, calculate_hash, 59 download_manager, calculate_hash,
59 scoped_ptr<PowerSaveBlocker>( 60 scoped_ptr<PowerSaveBlocker>(
60 new PowerSaveBlocker( 61 new PowerSaveBlocker(
61 PowerSaveBlocker::kPowerSaveBlockPreventSystemSleep)).Pass(), 62 PowerSaveBlocker::kPowerSaveBlockPreventSystemSleep)).Pass(),
62 bound_net_log); 63 bound_net_log);
63 } 64 }
64 65
65 } // namespace 66 } // namespace
66 67
67 DownloadFileManager::DownloadFileManager(DownloadFileFactory* factory) 68 DownloadFileManager::DownloadFileManager(DownloadFileFactory* factory)
(...skipping 12 matching lines...) Expand all
80 BrowserThread::FILE, FROM_HERE, 81 BrowserThread::FILE, FROM_HERE,
81 base::Bind(&DownloadFileManager::OnShutdown, this)); 82 base::Bind(&DownloadFileManager::OnShutdown, this));
82 } 83 }
83 84
84 void DownloadFileManager::OnShutdown() { 85 void DownloadFileManager::OnShutdown() {
85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
86 STLDeleteValues(&downloads_); 87 STLDeleteValues(&downloads_);
87 } 88 }
88 89
89 void DownloadFileManager::CreateDownloadFile( 90 void DownloadFileManager::CreateDownloadFile(
90 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle, 91 scoped_ptr<DownloadCreateInfo> info,
92 scoped_ptr<content::ByteStreamReader> stream,
93 const DownloadRequestHandle& request_handle,
91 DownloadManager* download_manager, bool get_hash, 94 DownloadManager* download_manager, bool get_hash,
92 const net::BoundNetLog& bound_net_log) { 95 const net::BoundNetLog& bound_net_log) {
93 DCHECK(info); 96 DCHECK(info.get());
94 VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); 97 VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString();
95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
96 99
97 // Life of |info| ends here. No more references to it after this method.
98 scoped_ptr<DownloadCreateInfo> infop(info);
99
100 // Create the download file. 100 // Create the download file.
101 scoped_ptr<DownloadFile> download_file(download_file_factory_->CreateFile( 101 scoped_ptr<DownloadFile> download_file(download_file_factory_->CreateFile(
102 info, request_handle, download_manager, get_hash, bound_net_log)); 102 info.get(), stream.Pass(), request_handle, download_manager,
103 get_hash, bound_net_log));
103 104
104 net::Error init_result = download_file->Initialize(); 105 net::Error init_result = download_file->Initialize();
105 if (net::OK != init_result) { 106 if (net::OK != init_result) {
106 // Error: Handle via download manager/item. 107 // Error: Handle via download manager/item.
107 BrowserThread::PostTask( 108 BrowserThread::PostTask(
108 BrowserThread::UI, 109 BrowserThread::UI,
109 FROM_HERE, 110 FROM_HERE,
110 base::Bind( 111 base::Bind(
111 &DownloadManager::OnDownloadInterrupted, 112 &DownloadManager::OnDownloadInterrupted,
112 download_manager, 113 download_manager,
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 manager, 146 manager,
146 global_id.local(), 147 global_id.local(),
147 download_file->BytesSoFar(), 148 download_file->BytesSoFar(),
148 download_file->CurrentSpeed(), 149 download_file->CurrentSpeed(),
149 download_file->GetHashState())); 150 download_file->GetHashState()));
150 } 151 }
151 } 152 }
152 } 153 }
153 154
154 void DownloadFileManager::StartDownload( 155 void DownloadFileManager::StartDownload(
155 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) { 156 scoped_ptr<DownloadCreateInfo> info,
157 scoped_ptr<content::ByteStreamReader> stream,
158 const DownloadRequestHandle& request_handle) {
156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
157 DCHECK(info); 160 DCHECK(info.get());
158 161
159 DownloadManager* manager = request_handle.GetDownloadManager(); 162 DownloadManager* manager = request_handle.GetDownloadManager();
160 DCHECK(manager); // Checked in |DownloadResourceHandler::StartOnUIThread()|. 163 DCHECK(manager); // Checked in |DownloadResourceHandler::StartOnUIThread()|.
161 164
162 // |bound_net_log| will be used for logging the both the download item's and 165 // |bound_net_log| will be used for logging the both the download item's and
163 // the download file's events. 166 // the download file's events.
164 net::BoundNetLog bound_net_log = 167 net::BoundNetLog bound_net_log =
165 manager->CreateDownloadItem(info, request_handle); 168 manager->CreateDownloadItem(info.get(), request_handle);
166 bool hash_needed = manager->GenerateFileHash(); 169 bool hash_needed = manager->GenerateFileHash();
167 170
168 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 171 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
169 base::Bind(&DownloadFileManager::CreateDownloadFile, this, 172 base::Bind(&DownloadFileManager::CreateDownloadFile, this,
170 info, request_handle, make_scoped_refptr(manager), 173 base::Passed(info.Pass()), base::Passed(stream.Pass()),
174 request_handle,
175 make_scoped_refptr(manager),
171 hash_needed, bound_net_log)); 176 hash_needed, bound_net_log));
172 } 177 }
173 178
174 // We don't forward an update to the UI thread here, since we want to throttle
175 // the UI update rate via a periodic timer. If the user has cancelled the
176 // download (in the UI thread), we may receive a few more updates before the IO
177 // thread gets the cancel message: we just delete the data since the
178 // DownloadFile has been deleted.
179 void DownloadFileManager::UpdateDownload(
180 DownloadId global_id, content::DownloadBuffer* buffer) {
181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
182 scoped_ptr<content::ContentVector> contents(buffer->ReleaseContents());
183
184 download_stats::RecordFileThreadReceiveBuffers(contents->size());
185
186 DownloadFile* download_file = GetDownloadFile(global_id);
187 bool had_error = false;
188 for (size_t i = 0; i < contents->size(); ++i) {
189 net::IOBuffer* data = (*contents)[i].first;
190 const int data_len = (*contents)[i].second;
191 if (!had_error && download_file) {
192 net::Error write_result =
193 download_file->AppendDataToFile(data->data(), data_len);
194 if (write_result != net::OK) {
195 // Write failed: interrupt the download.
196 DownloadManager* download_manager =
197 download_file->GetDownloadManager();
198 had_error = true;
199
200 int64 bytes_downloaded = download_file->BytesSoFar();
201 std::string hash_state(download_file->GetHashState());
202
203 // Calling this here in case we get more data, to avoid
204 // processing data after an error. That could lead to
205 // files that are corrupted if the later processing succeeded.
206 CancelDownload(global_id);
207 download_file = NULL; // Was deleted in |CancelDownload|.
208
209 if (download_manager) {
210 BrowserThread::PostTask(
211 BrowserThread::UI, FROM_HERE,
212 base::Bind(&DownloadManager::OnDownloadInterrupted,
213 download_manager,
214 global_id.local(),
215 bytes_downloaded,
216 hash_state,
217 content::ConvertNetErrorToInterruptReason(
218 write_result,
219 content::DOWNLOAD_INTERRUPT_FROM_DISK)));
220 }
221 }
222 }
223 data->Release();
224 }
225 }
226
227 void DownloadFileManager::OnResponseCompleted(
228 DownloadId global_id,
229 content::DownloadInterruptReason reason,
230 const std::string& security_info) {
231 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id
232 << " reason = " << InterruptReasonDebugString(reason)
233 << " security_info = \"" << security_info << "\"";
234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
235 DownloadFile* download_file = GetDownloadFile(global_id);
236 if (!download_file)
237 return;
238
239 download_file->Finish();
240
241 DownloadManager* download_manager = download_file->GetDownloadManager();
242 if (!download_manager) {
243 CancelDownload(global_id);
244 return;
245 }
246
247 if (reason == content::DOWNLOAD_INTERRUPT_REASON_NONE) {
248 std::string hash;
249 if (!download_file->GetHash(&hash) ||
250 BaseFile::IsEmptyHash(hash)) {
251 hash.clear();
252 }
253
254 BrowserThread::PostTask(
255 BrowserThread::UI, FROM_HERE,
256 base::Bind(&DownloadManager::OnResponseCompleted,
257 download_manager, global_id.local(),
258 download_file->BytesSoFar(), hash));
259 } else {
260 BrowserThread::PostTask(
261 BrowserThread::UI, FROM_HERE,
262 base::Bind(&DownloadManager::OnDownloadInterrupted,
263 download_manager,
264 global_id.local(),
265 download_file->BytesSoFar(),
266 download_file->GetHashState(),
267 reason));
268 }
269 // We need to keep the download around until the UI thread has finalized
270 // the name.
271 }
272
273 // This method will be sent via a user action, or shutdown on the UI thread, and 179 // This method will be sent via a user action, or shutdown on the UI thread, and
274 // run on the download thread. Since this message has been sent from the UI 180 // run on the download thread. Since this message has been sent from the UI
275 // thread, the download may have already completed and won't exist in our map. 181 // thread, the download may have already completed and won't exist in our map.
276 void DownloadFileManager::CancelDownload(DownloadId global_id) { 182 void DownloadFileManager::CancelDownload(DownloadId global_id) {
277 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id; 183 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id;
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
279 DownloadFileMap::iterator it = downloads_.find(global_id); 185 DownloadFileMap::iterator it = downloads_.find(global_id);
280 if (it == downloads_.end()) 186 if (it == downloads_.end())
281 return; 187 return;
282 188
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 DownloadFile* download_file = downloads_[global_id]; 389 DownloadFile* download_file = downloads_[global_id];
484 390
485 VLOG(20) << " " << __FUNCTION__ << "()" 391 VLOG(20) << " " << __FUNCTION__ << "()"
486 << " id = " << global_id 392 << " id = " << global_id
487 << " download_file = " << download_file->DebugString(); 393 << " download_file = " << download_file->DebugString();
488 394
489 downloads_.erase(global_id); 395 downloads_.erase(global_id);
490 396
491 delete download_file; 397 delete download_file;
492 } 398 }
OLDNEW
« no previous file with comments | « content/browser/download/download_file_manager.h ('k') | content/browser/download/download_file_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698