OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/download_buffer.h" | 15 #include "content/browser/download/download_buffer.h" |
16 #include "content/browser/download/download_create_info.h" | 16 #include "content/browser/download/download_create_info.h" |
17 #include "content/browser/download/download_file.h" | 17 #include "content/browser/download/download_file_impl.h" |
18 #include "content/browser/download/download_manager.h" | 18 #include "content/browser/download/download_manager.h" |
19 #include "content/browser/download/download_request_handle.h" | 19 #include "content/browser/download/download_request_handle.h" |
20 #include "content/browser/download/download_stats.h" | 20 #include "content/browser/download/download_stats.h" |
21 #include "content/browser/renderer_host/resource_dispatcher_host.h" | 21 #include "content/browser/renderer_host/resource_dispatcher_host.h" |
22 #include "content/browser/tab_contents/tab_contents.h" | 22 #include "content/browser/tab_contents/tab_contents.h" |
23 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
24 #include "content/public/browser/download_manager_delegate.h" | 24 #include "content/public/browser/download_manager_delegate.h" |
25 #include "googleurl/src/gurl.h" | 25 #include "googleurl/src/gurl.h" |
26 #include "net/base/io_buffer.h" | 26 #include "net/base/io_buffer.h" |
27 | 27 |
(...skipping 21 matching lines...) Expand all Loading... |
49 BrowserThread::FILE, FROM_HERE, | 49 BrowserThread::FILE, FROM_HERE, |
50 base::Bind(&DownloadFileManager::OnShutdown, this)); | 50 base::Bind(&DownloadFileManager::OnShutdown, this)); |
51 } | 51 } |
52 | 52 |
53 void DownloadFileManager::OnShutdown() { | 53 void DownloadFileManager::OnShutdown() { |
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
55 StopUpdateTimer(); | 55 StopUpdateTimer(); |
56 STLDeleteValues(&downloads_); | 56 STLDeleteValues(&downloads_); |
57 } | 57 } |
58 | 58 |
| 59 DownloadFile* DownloadFileManager::NewDownloadFile( |
| 60 DownloadCreateInfo* info, |
| 61 const DownloadRequestHandle& request_handle, |
| 62 DownloadManager* download_manager) { |
| 63 return new DownloadFileImpl(info, |
| 64 new DownloadRequestHandle(request_handle), |
| 65 download_manager); |
| 66 } |
| 67 |
59 void DownloadFileManager::CreateDownloadFile( | 68 void DownloadFileManager::CreateDownloadFile( |
60 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle, | 69 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle, |
61 DownloadManager* download_manager, bool get_hash) { | 70 DownloadManager* download_manager, bool get_hash) { |
62 DCHECK(info); | 71 DCHECK(info); |
63 VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); | 72 VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString(); |
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
65 | 74 |
66 // Life of |info| ends here. No more references to it after this method. | 75 // Life of |info| ends here. No more references to it after this method. |
67 scoped_ptr<DownloadCreateInfo> infop(info); | 76 scoped_ptr<DownloadCreateInfo> infop(info); |
68 | 77 |
69 scoped_ptr<DownloadFile> | 78 scoped_ptr<DownloadFile> download_file( |
70 download_file(new DownloadFile(info, | 79 NewDownloadFile(info, request_handle, download_manager)); |
71 new DownloadRequestHandle(request_handle), | |
72 download_manager)); | |
73 if (net::OK != download_file->Initialize(get_hash)) { | 80 if (net::OK != download_file->Initialize(get_hash)) { |
74 request_handle.CancelRequest(); | 81 request_handle.CancelRequest(); |
75 return; | 82 return; |
76 } | 83 } |
77 | 84 |
78 DCHECK(GetDownloadFile(info->download_id) == NULL); | 85 DCHECK(GetDownloadFile(info->download_id) == NULL); |
79 downloads_[info->download_id] = download_file.release(); | 86 downloads_[info->download_id] = download_file.release(); |
80 | 87 |
81 // The file is now ready, we can un-pause the request and start saving data. | 88 // The file is now ready, we can un-pause the request and start saving data. |
82 request_handle.ResumeRequest(); | 89 request_handle.ResumeRequest(); |
83 | 90 |
84 StartUpdateTimer(); | 91 StartUpdateTimer(); |
85 | 92 |
86 BrowserThread::PostTask( | 93 BrowserThread::PostTask( |
87 BrowserThread::UI, FROM_HERE, | 94 BrowserThread::UI, FROM_HERE, |
88 base::Bind(&DownloadManager::StartDownload, download_manager, | 95 base::Bind(&DownloadManager::StartDownload, download_manager, |
89 info->download_id.local())); | 96 info->download_id.local())); |
90 } | 97 } |
91 | 98 |
92 DownloadFile* DownloadFileManager::GetDownloadFile(DownloadId global_id) { | 99 DownloadFile* DownloadFileManager::GetDownloadFile( |
| 100 DownloadId global_id) { |
93 DownloadFileMap::iterator it = downloads_.find(global_id); | 101 DownloadFileMap::iterator it = downloads_.find(global_id); |
94 return it == downloads_.end() ? NULL : it->second; | 102 return it == downloads_.end() ? NULL : it->second; |
95 } | 103 } |
96 | 104 |
97 void DownloadFileManager::StartUpdateTimer() { | 105 void DownloadFileManager::StartUpdateTimer() { |
98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
99 if (!update_timer_.IsRunning()) { | 107 if (!update_timer_.IsRunning()) { |
100 update_timer_.Start(FROM_HERE, | 108 update_timer_.Start(FROM_HERE, |
101 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), | 109 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), |
102 this, &DownloadFileManager::UpdateInProgressDownloads); | 110 this, &DownloadFileManager::UpdateInProgressDownloads); |
103 } | 111 } |
104 } | 112 } |
105 | 113 |
106 void DownloadFileManager::StopUpdateTimer() { | 114 void DownloadFileManager::StopUpdateTimer() { |
107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
108 update_timer_.Stop(); | 116 update_timer_.Stop(); |
109 } | 117 } |
110 | 118 |
111 void DownloadFileManager::UpdateInProgressDownloads() { | 119 void DownloadFileManager::UpdateInProgressDownloads() { |
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
113 for (DownloadFileMap::iterator i = downloads_.begin(); | 121 for (DownloadFileMap::iterator i = downloads_.begin(); |
114 i != downloads_.end(); ++i) { | 122 i != downloads_.end(); ++i) { |
115 DownloadId global_id = i->first; | 123 DownloadId global_id = i->first; |
116 DownloadFile* download_file = i->second; | 124 DownloadFile* download_file = i->second; |
117 DownloadManager* manager = download_file->GetDownloadManager(); | 125 DownloadManager* manager = download_file->GetDownloadManager(); |
118 if (manager) { | 126 if (manager) { |
119 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | 127 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
120 base::Bind(&DownloadManager::UpdateDownload, manager, | 128 base::Bind(&DownloadManager::UpdateDownload, manager, |
121 global_id.local(), download_file->bytes_so_far())); | 129 global_id.local(), download_file->BytesSoFar())); |
122 } | 130 } |
123 } | 131 } |
124 } | 132 } |
125 | 133 |
126 void DownloadFileManager::StartDownload( | 134 void DownloadFileManager::StartDownload( |
127 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) { | 135 DownloadCreateInfo* info, const DownloadRequestHandle& request_handle) { |
128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
129 DCHECK(info); | 137 DCHECK(info); |
130 | 138 |
131 DownloadManager* manager = request_handle.GetDownloadManager(); | 139 DownloadManager* manager = request_handle.GetDownloadManager(); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 net::IOBuffer* data = (*contents)[i].first; | 173 net::IOBuffer* data = (*contents)[i].first; |
166 const int data_len = (*contents)[i].second; | 174 const int data_len = (*contents)[i].second; |
167 if (!had_error && download_file) { | 175 if (!had_error && download_file) { |
168 net::Error write_result = | 176 net::Error write_result = |
169 download_file->AppendDataToFile(data->data(), data_len); | 177 download_file->AppendDataToFile(data->data(), data_len); |
170 if (write_result != net::OK) { | 178 if (write_result != net::OK) { |
171 // Write failed: interrupt the download. | 179 // Write failed: interrupt the download. |
172 DownloadManager* download_manager = download_file->GetDownloadManager(); | 180 DownloadManager* download_manager = download_file->GetDownloadManager(); |
173 had_error = true; | 181 had_error = true; |
174 | 182 |
175 int64 bytes_downloaded = download_file->bytes_so_far(); | 183 int64 bytes_downloaded = download_file->BytesSoFar(); |
176 // Calling this here in case we get more data, to avoid | 184 // Calling this here in case we get more data, to avoid |
177 // processing data after an error. That could lead to | 185 // processing data after an error. That could lead to |
178 // files that are corrupted if the later processing succeeded. | 186 // files that are corrupted if the later processing succeeded. |
179 CancelDownload(global_id); | 187 CancelDownload(global_id); |
180 download_file = NULL; // Was deleted in |CancelDownload|. | 188 download_file = NULL; // Was deleted in |CancelDownload|. |
181 | 189 |
182 if (download_manager) { | 190 if (download_manager) { |
183 BrowserThread::PostTask( | 191 BrowserThread::PostTask( |
184 BrowserThread::UI, FROM_HERE, | 192 BrowserThread::UI, FROM_HERE, |
185 base::Bind(&DownloadManager::OnDownloadInterrupted, | 193 base::Bind(&DownloadManager::OnDownloadInterrupted, |
(...skipping 29 matching lines...) Expand all Loading... |
215 | 223 |
216 std::string hash; | 224 std::string hash; |
217 if (!download_file->GetSha256Hash(&hash)) | 225 if (!download_file->GetSha256Hash(&hash)) |
218 hash.clear(); | 226 hash.clear(); |
219 | 227 |
220 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) { | 228 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) { |
221 BrowserThread::PostTask( | 229 BrowserThread::PostTask( |
222 BrowserThread::UI, FROM_HERE, | 230 BrowserThread::UI, FROM_HERE, |
223 base::Bind(&DownloadManager::OnResponseCompleted, | 231 base::Bind(&DownloadManager::OnResponseCompleted, |
224 download_manager, global_id.local(), | 232 download_manager, global_id.local(), |
225 download_file->bytes_so_far(), hash)); | 233 download_file->BytesSoFar(), hash)); |
226 } else { | 234 } else { |
227 BrowserThread::PostTask( | 235 BrowserThread::PostTask( |
228 BrowserThread::UI, FROM_HERE, | 236 BrowserThread::UI, FROM_HERE, |
229 base::Bind(&DownloadManager::OnDownloadInterrupted, | 237 base::Bind(&DownloadManager::OnDownloadInterrupted, |
230 download_manager, global_id.local(), | 238 download_manager, global_id.local(), |
231 download_file->bytes_so_far(), reason)); | 239 download_file->BytesSoFar(), reason)); |
232 } | 240 } |
233 // We need to keep the download around until the UI thread has finalized | 241 // We need to keep the download around until the UI thread has finalized |
234 // the name. | 242 // the name. |
235 } | 243 } |
236 | 244 |
237 // This method will be sent via a user action, or shutdown on the UI thread, and | 245 // This method will be sent via a user action, or shutdown on the UI thread, and |
238 // run on the download thread. Since this message has been sent from the UI | 246 // run on the download thread. Since this message has been sent from the UI |
239 // thread, the download may have already completed and won't exist in our map. | 247 // thread, the download may have already completed and won't exist in our map. |
240 void DownloadFileManager::CancelDownload(DownloadId global_id) { | 248 void DownloadFileManager::CancelDownload(DownloadId global_id) { |
241 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id; | 249 VLOG(20) << __FUNCTION__ << "()" << " id = " << global_id; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 i != downloads_.end(); ++i) { | 287 i != downloads_.end(); ++i) { |
280 DownloadFile* download_file = i->second; | 288 DownloadFile* download_file = i->second; |
281 if (download_file->GetDownloadManager() == manager) { | 289 if (download_file->GetDownloadManager() == manager) { |
282 download_file->CancelDownloadRequest(); | 290 download_file->CancelDownloadRequest(); |
283 to_remove.insert(download_file); | 291 to_remove.insert(download_file); |
284 } | 292 } |
285 } | 293 } |
286 | 294 |
287 for (std::set<DownloadFile*>::iterator i = to_remove.begin(); | 295 for (std::set<DownloadFile*>::iterator i = to_remove.begin(); |
288 i != to_remove.end(); ++i) { | 296 i != to_remove.end(); ++i) { |
289 downloads_.erase((*i)->global_id()); | 297 downloads_.erase((*i)->GlobalId()); |
290 delete *i; | 298 delete *i; |
291 } | 299 } |
292 } | 300 } |
293 | 301 |
294 // Actions from the UI thread and run on the download thread | 302 // Actions from the UI thread and run on the download thread |
295 | 303 |
296 // The DownloadManager in the UI thread has provided an intermediate .crdownload | 304 // The DownloadManager in the UI thread has provided an intermediate .crdownload |
297 // name for the download specified by 'id'. Rename the in progress download. | 305 // name for the download specified by 'id'. Rename the in progress download. |
298 // | 306 // |
299 // There are 2 possible rename cases where this method can be called: | 307 // There are 2 possible rename cases where this method can be called: |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 // need to do it here. The normal path will also update the download | 407 // need to do it here. The normal path will also update the download |
400 // history before canceling the request. | 408 // history before canceling the request. |
401 download_file->CancelDownloadRequest(); | 409 download_file->CancelDownloadRequest(); |
402 return; | 410 return; |
403 } | 411 } |
404 | 412 |
405 BrowserThread::PostTask( | 413 BrowserThread::PostTask( |
406 BrowserThread::UI, FROM_HERE, | 414 BrowserThread::UI, FROM_HERE, |
407 base::Bind(&DownloadManager::OnDownloadInterrupted, | 415 base::Bind(&DownloadManager::OnDownloadInterrupted, |
408 download_manager, global_id.local(), | 416 download_manager, global_id.local(), |
409 download_file->bytes_so_far(), | 417 download_file->BytesSoFar(), |
410 ConvertNetErrorToInterruptReason( | 418 ConvertNetErrorToInterruptReason( |
411 rename_error, DOWNLOAD_INTERRUPT_FROM_DISK))); | 419 rename_error, DOWNLOAD_INTERRUPT_FROM_DISK))); |
412 } | 420 } |
413 | 421 |
414 void DownloadFileManager::EraseDownload(DownloadId global_id) { | 422 void DownloadFileManager::EraseDownload(DownloadId global_id) { |
415 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
416 | 424 |
417 if (!ContainsKey(downloads_, global_id)) | 425 if (!ContainsKey(downloads_, global_id)) |
418 return; | 426 return; |
419 | 427 |
420 DownloadFile* download_file = downloads_[global_id]; | 428 DownloadFile* download_file = downloads_[global_id]; |
421 | 429 |
422 VLOG(20) << " " << __FUNCTION__ << "()" | 430 VLOG(20) << " " << __FUNCTION__ << "()" |
423 << " id = " << global_id | 431 << " id = " << global_id |
424 << " download_file = " << download_file->DebugString(); | 432 << " download_file = " << download_file->DebugString(); |
425 | 433 |
426 downloads_.erase(global_id); | 434 downloads_.erase(global_id); |
427 | 435 |
428 delete download_file; | 436 delete download_file; |
429 | 437 |
430 if (downloads_.empty()) | 438 if (downloads_.empty()) |
431 StopUpdateTimer(); | 439 StopUpdateTimer(); |
432 } | 440 } |
OLD | NEW |