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

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: Added some histogram statistics. Created 8 years, 7 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::ByteStreamOutput> pipe,
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::ByteStreamOutput> pipe,
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, pipe.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::ByteStreamOutput> pipe,
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(), pipe.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,
113 info->download_id.local(), 114 info->download_id.local(),
114 0, 115 0,
115 "", 116 "",
116 content::ConvertNetErrorToInterruptReason( 117 content::ConvertNetErrorToInterruptReason(
117 init_result, content::DOWNLOAD_INTERRUPT_FROM_DISK))); 118 init_result, content::DOWNLOAD_INTERRUPT_FROM_DISK)));
118 } else { 119 } else {
119 DCHECK(GetDownloadFile(info->download_id) == NULL); 120 DCHECK(GetDownloadFile(info->download_id) == NULL);
120 downloads_[info->download_id] = download_file.release(); 121 downloads_[info->download_id] = download_file.release();
121
122 // The file is now ready, we can un-pause the request and start saving data.
123 request_handle.ResumeRequest();
124 } 122 }
125 123
126 BrowserThread::PostTask( 124 BrowserThread::PostTask(
127 BrowserThread::UI, FROM_HERE, 125 BrowserThread::UI, FROM_HERE,
128 base::Bind(&DownloadManager::StartDownload, download_manager, 126 base::Bind(&DownloadManager::StartDownload, download_manager,
129 info->download_id.local())); 127 info->download_id.local()));
130 } 128 }
131 129
132 DownloadFile* DownloadFileManager::GetDownloadFile( 130 DownloadFile* DownloadFileManager::GetDownloadFile(
133 DownloadId global_id) { 131 DownloadId global_id) {
(...skipping 14 matching lines...) Expand all
148 manager, 146 manager,
149 global_id.local(), 147 global_id.local(),
150 download_file->BytesSoFar(), 148 download_file->BytesSoFar(),
151 download_file->CurrentSpeed(), 149 download_file->CurrentSpeed(),
152 download_file->GetHashState())); 150 download_file->GetHashState()));
153 } 151 }
154 } 152 }
155 } 153 }
156 154
157 void DownloadFileManager::StartDownload( 155 void DownloadFileManager::StartDownload(
158 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) { 156 scoped_ptr<DownloadCreateInfo> info,
157 scoped_ptr<content::ByteStreamOutput> pipe,
158 const DownloadRequestHandle& request_handle) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
160 DCHECK(info); 160 DCHECK(info.get());
161 161
162 DownloadManager* manager = request_handle.GetDownloadManager(); 162 DownloadManager* manager = request_handle.GetDownloadManager();
163 DCHECK(manager); // Checked in |DownloadResourceHandler::StartOnUIThread()|. 163 DCHECK(manager); // Checked in |DownloadResourceHandler::StartOnUIThread()|.
164 164
165 // |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
166 // the download file's events. 166 // the download file's events.
167 net::BoundNetLog bound_net_log = 167 net::BoundNetLog bound_net_log =
168 manager->CreateDownloadItem(info, request_handle); 168 manager->CreateDownloadItem(info.get(), request_handle);
169 bool hash_needed = manager->GenerateFileHash(); 169 bool hash_needed = manager->GenerateFileHash();
170 170
171 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 171 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
172 base::Bind(&DownloadFileManager::CreateDownloadFile, this, 172 base::Bind(&DownloadFileManager::CreateDownloadFile, this,
173 info, request_handle, make_scoped_refptr(manager), 173 base::Passed(info.Pass()), base::Passed(pipe.Pass()),
174 request_handle,
175 make_scoped_refptr(manager),
174 hash_needed, bound_net_log)); 176 hash_needed, bound_net_log));
175 } 177 }
176 178
177 // We don't forward an update to the UI thread here, since we want to throttle
178 // the UI update rate via a periodic timer. If the user has cancelled the
179 // download (in the UI thread), we may receive a few more updates before the IO
180 // thread gets the cancel message: we just delete the data since the
181 // DownloadFile has been deleted.
182 void DownloadFileManager::UpdateDownload(
183 DownloadId global_id, content::DownloadBuffer* buffer) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
185 scoped_ptr<content::ContentVector> contents(buffer->ReleaseContents());
186
187 download_stats::RecordFileThreadReceiveBuffers(contents->size());
188
189 DownloadFile* download_file = GetDownloadFile(global_id);
190 bool had_error = false;
191 for (size_t i = 0; i < contents->size(); ++i) {
192 net::IOBuffer* data = (*contents)[i].first;
193 const int data_len = (*contents)[i].second;
194 if (!had_error && download_file) {
195 net::Error write_result =
196 download_file->AppendDataToFile(data->data(), data_len);
197 if (write_result != net::OK) {
198 // Write failed: interrupt the download.
199 DownloadManager* download_manager =
200 download_file->GetDownloadManager();
201 had_error = true;
202
203 int64 bytes_downloaded = download_file->BytesSoFar();
204 std::string hash_state(download_file->GetHashState());
205
206 // Calling this here in case we get more data, to avoid
207 // processing data after an error. That could lead to
208 // files that are corrupted if the later processing succeeded.
209 CancelDownload(global_id);
210 download_file = NULL; // Was deleted in |CancelDownload|.
211
212 if (download_manager) {
213 BrowserThread::PostTask(
214 BrowserThread::UI, FROM_HERE,
215 base::Bind(&DownloadManager::OnDownloadInterrupted,
216 download_manager,
217 global_id.local(),
218 bytes_downloaded,
219 hash_state,
220 content::ConvertNetErrorToInterruptReason(
221 write_result,
222 content::DOWNLOAD_INTERRUPT_FROM_DISK)));
223 }
224 }
225 }
226 data->Release();
227 }
228 }
229
230 void DownloadFileManager::OnResponseCompleted(
231 DownloadId global_id,
232 content::DownloadInterruptReason reason,
233 const std::string& security_info) {
234 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id
235 << " reason = " << InterruptReasonDebugString(reason)
236 << " security_info = \"" << security_info << "\"";
237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
238 DownloadFile* download_file = GetDownloadFile(global_id);
239 if (!download_file)
240 return;
241
242 download_file->Finish();
243
244 DownloadManager* download_manager = download_file->GetDownloadManager();
245 if (!download_manager) {
246 CancelDownload(global_id);
247 return;
248 }
249
250 if (reason == content::DOWNLOAD_INTERRUPT_REASON_NONE) {
251 std::string hash;
252 if (!download_file->GetHash(&hash) ||
253 BaseFile::IsEmptyHash(hash)) {
254 hash.clear();
255 }
256
257 BrowserThread::PostTask(
258 BrowserThread::UI, FROM_HERE,
259 base::Bind(&DownloadManager::OnResponseCompleted,
260 download_manager, global_id.local(),
261 download_file->BytesSoFar(), hash));
262 } else {
263 BrowserThread::PostTask(
264 BrowserThread::UI, FROM_HERE,
265 base::Bind(&DownloadManager::OnDownloadInterrupted,
266 download_manager,
267 global_id.local(),
268 download_file->BytesSoFar(),
269 download_file->GetHashState(),
270 reason));
271 }
272 // We need to keep the download around until the UI thread has finalized
273 // the name.
274 }
275
276 // 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
277 // 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
278 // 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.
279 void DownloadFileManager::CancelDownload(DownloadId global_id) { 182 void DownloadFileManager::CancelDownload(DownloadId global_id) {
280 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id; 183 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id;
281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
282 DownloadFileMap::iterator it = downloads_.find(global_id); 185 DownloadFileMap::iterator it = downloads_.find(global_id);
283 if (it == downloads_.end()) 186 if (it == downloads_.end())
284 return; 187 return;
285 188
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 DownloadFile* download_file = downloads_[global_id]; 367 DownloadFile* download_file = downloads_[global_id];
465 368
466 VLOG(20) << " " << __FUNCTION__ << "()" 369 VLOG(20) << " " << __FUNCTION__ << "()"
467 << " id = " << global_id 370 << " id = " << global_id
468 << " download_file = " << download_file->DebugString(); 371 << " download_file = " << download_file->DebugString();
469 372
470 downloads_.erase(global_id); 373 downloads_.erase(global_id);
471 374
472 delete download_file; 375 delete download_file;
473 } 376 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698