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 "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "base/task.h" | 10 #include "base/task.h" |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 // DownloadFile has been deleted. | 146 // DownloadFile has been deleted. |
147 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { | 147 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { |
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
149 std::vector<DownloadBuffer::Contents> contents; | 149 std::vector<DownloadBuffer::Contents> contents; |
150 { | 150 { |
151 base::AutoLock auto_lock(buffer->lock); | 151 base::AutoLock auto_lock(buffer->lock); |
152 contents.swap(buffer->contents); | 152 contents.swap(buffer->contents); |
153 } | 153 } |
154 | 154 |
155 DownloadFile* download_file = GetDownloadFile(id); | 155 DownloadFile* download_file = GetDownloadFile(id); |
| 156 bool had_error = false; |
156 for (size_t i = 0; i < contents.size(); ++i) { | 157 for (size_t i = 0; i < contents.size(); ++i) { |
157 net::IOBuffer* data = contents[i].first; | 158 net::IOBuffer* data = contents[i].first; |
158 const int data_len = contents[i].second; | 159 const int data_len = contents[i].second; |
159 if (download_file) | 160 if (!had_error && download_file) { |
160 download_file->AppendDataToFile(data->data(), data_len); | 161 bool write_succeeded = |
| 162 download_file->AppendDataToFile(data->data(), data_len); |
| 163 if (!write_succeeded) { |
| 164 // Write failed: interrupt the download. |
| 165 DownloadManager* download_manager = download_file->GetDownloadManager(); |
| 166 had_error = true; |
| 167 |
| 168 int64 bytes_downloaded = download_file->bytes_so_far(); |
| 169 // Calling this here in case we get more data, to avoid |
| 170 // processing data after an error. That could lead to |
| 171 // files that are corrupted if the later processing succeeded. |
| 172 CancelDownload(id); |
| 173 download_file = NULL; // Was deleted in |CancelDownload|. |
| 174 |
| 175 if (download_manager) { |
| 176 BrowserThread::PostTask( |
| 177 BrowserThread::UI, |
| 178 FROM_HERE, |
| 179 NewRunnableMethod( |
| 180 download_manager, |
| 181 &DownloadManager::OnDownloadError, |
| 182 id, |
| 183 bytes_downloaded, |
| 184 net::ERR_FAILED)); |
| 185 } |
| 186 } |
| 187 } |
161 data->Release(); | 188 data->Release(); |
162 } | 189 } |
163 } | 190 } |
164 | 191 |
165 void DownloadFileManager::OnResponseCompleted( | 192 void DownloadFileManager::OnResponseCompleted( |
166 int id, | 193 int id, |
167 DownloadBuffer* buffer, | 194 DownloadBuffer* buffer, |
168 int os_error, | 195 int net_error, |
169 const std::string& security_info) { | 196 const std::string& security_info) { |
170 VLOG(20) << __FUNCTION__ << "()" << " id = " << id | 197 VLOG(20) << __FUNCTION__ << "()" << " id = " << id |
171 << " os_error = " << os_error | 198 << " net_error = " << net_error |
172 << " security_info = \"" << security_info << "\""; | 199 << " security_info = \"" << security_info << "\""; |
173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
174 delete buffer; | 201 delete buffer; |
175 DownloadFile* download_file = GetDownloadFile(id); | 202 DownloadFile* download_file = GetDownloadFile(id); |
176 if (!download_file) | 203 if (!download_file) |
177 return; | 204 return; |
178 | 205 |
179 download_file->Finish(); | 206 download_file->Finish(); |
180 | 207 |
181 DownloadManager* download_manager = download_file->GetDownloadManager(); | 208 DownloadManager* download_manager = download_file->GetDownloadManager(); |
182 if (!download_manager) { | 209 if (!download_manager) { |
183 CancelDownload(id); | 210 CancelDownload(id); |
184 return; | 211 return; |
185 } | 212 } |
186 | 213 |
187 std::string hash; | 214 std::string hash; |
188 if (!download_file->GetSha256Hash(&hash)) | 215 if (!download_file->GetSha256Hash(&hash)) |
189 hash.clear(); | 216 hash.clear(); |
190 | 217 |
191 BrowserThread::PostTask( | 218 // ERR_CONNECTION_CLOSED is allowed since a number of servers in the wild |
192 BrowserThread::UI, FROM_HERE, | 219 // advertise a larger Content-Length than the amount of bytes in the message |
193 NewRunnableMethod( | 220 // body, and then close the connection. Other browsers - IE8, Firefox 4.0.1, |
194 download_manager, &DownloadManager::OnResponseCompleted, | 221 // and Safari 5.0.4 - treat the download as complete in this case, so we |
195 id, download_file->bytes_so_far(), os_error, hash)); | 222 // follow their lead. |
| 223 if (net_error == net::OK || net_error == net::ERR_CONNECTION_CLOSED) { |
| 224 BrowserThread::PostTask( |
| 225 BrowserThread::UI, |
| 226 FROM_HERE, |
| 227 NewRunnableMethod( |
| 228 download_manager, |
| 229 &DownloadManager::OnResponseCompleted, |
| 230 id, |
| 231 download_file->bytes_so_far(), |
| 232 hash)); |
| 233 } else { |
| 234 BrowserThread::PostTask( |
| 235 BrowserThread::UI, |
| 236 FROM_HERE, |
| 237 NewRunnableMethod( |
| 238 download_manager, |
| 239 &DownloadManager::OnDownloadError, |
| 240 id, |
| 241 download_file->bytes_so_far(), |
| 242 net_error)); |
| 243 } |
196 // We need to keep the download around until the UI thread has finalized | 244 // We need to keep the download around until the UI thread has finalized |
197 // the name. | 245 // the name. |
198 } | 246 } |
199 | 247 |
200 // This method will be sent via a user action, or shutdown on the UI thread, and | 248 // This method will be sent via a user action, or shutdown on the UI thread, and |
201 // run on the download thread. Since this message has been sent from the UI | 249 // run on the download thread. Since this message has been sent from the UI |
202 // thread, the download may have already completed and won't exist in our map. | 250 // thread, the download may have already completed and won't exist in our map. |
203 void DownloadFileManager::CancelDownload(int id) { | 251 void DownloadFileManager::CancelDownload(int id) { |
204 VLOG(20) << __FUNCTION__ << "()" << " id = " << id; | 252 VLOG(20) << __FUNCTION__ << "()" << " id = " << id; |
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 DownloadFile* download_file = GetDownloadFile(id); | 319 DownloadFile* download_file = GetDownloadFile(id); |
272 if (!download_file) | 320 if (!download_file) |
273 return; | 321 return; |
274 | 322 |
275 VLOG(20) << __FUNCTION__ << "()" | 323 VLOG(20) << __FUNCTION__ << "()" |
276 << " download_file = " << download_file->DebugString(); | 324 << " download_file = " << download_file->DebugString(); |
277 | 325 |
278 if (!download_file->Rename(full_path)) { | 326 if (!download_file->Rename(full_path)) { |
279 // Error. Between the time the UI thread generated 'full_path' to the time | 327 // Error. Between the time the UI thread generated 'full_path' to the time |
280 // this code runs, something happened that prevents us from renaming. | 328 // this code runs, something happened that prevents us from renaming. |
281 CancelDownloadOnRename(id); | 329 CancelDownloadOnRename(id, net::ERR_FAILED); |
282 } | 330 } |
283 } | 331 } |
284 | 332 |
285 // The DownloadManager in the UI thread has provided a final name for the | 333 // The DownloadManager in the UI thread has provided a final name for the |
286 // download specified by 'id'. Rename the download that's in the process | 334 // download specified by 'id'. Rename the download that's in the process |
287 // of completing. | 335 // of completing. |
288 // | 336 // |
289 // There are 2 possible rename cases where this method can be called: | 337 // There are 2 possible rename cases where this method can be called: |
290 // 1. foo.crdownload -> foo (final, safe) | 338 // 1. foo.crdownload -> foo (final, safe) |
291 // 2. Unconfirmed.xxx.crdownload -> xxx (final, validated) | 339 // 2. Unconfirmed.xxx.crdownload -> xxx (final, validated) |
(...skipping 27 matching lines...) Expand all Loading... |
319 uniquifier = DownloadFile::GetUniquePathNumber(new_path); | 367 uniquifier = DownloadFile::GetUniquePathNumber(new_path); |
320 if (uniquifier > 0) { | 368 if (uniquifier > 0) { |
321 DownloadFile::AppendNumberToPath(&new_path, uniquifier); | 369 DownloadFile::AppendNumberToPath(&new_path, uniquifier); |
322 } | 370 } |
323 } | 371 } |
324 | 372 |
325 // Rename the file, overwriting if necessary. | 373 // Rename the file, overwriting if necessary. |
326 if (!download_file->Rename(new_path)) { | 374 if (!download_file->Rename(new_path)) { |
327 // Error. Between the time the UI thread generated 'full_path' to the time | 375 // Error. Between the time the UI thread generated 'full_path' to the time |
328 // this code runs, something happened that prevents us from renaming. | 376 // this code runs, something happened that prevents us from renaming. |
329 CancelDownloadOnRename(id); | 377 CancelDownloadOnRename(id, net::ERR_FAILED); |
330 return; | 378 return; |
331 } | 379 } |
332 | 380 |
333 #if defined(OS_MACOSX) | 381 #if defined(OS_MACOSX) |
334 // Done here because we only want to do this once; see | 382 // Done here because we only want to do this once; see |
335 // http://crbug.com/13120 for details. | 383 // http://crbug.com/13120 for details. |
336 download_file->AnnotateWithSourceInformation(); | 384 download_file->AnnotateWithSourceInformation(); |
337 #endif | 385 #endif |
338 | 386 |
339 BrowserThread::PostTask( | 387 BrowserThread::PostTask( |
340 BrowserThread::UI, FROM_HERE, | 388 BrowserThread::UI, FROM_HERE, |
341 NewRunnableMethod( | 389 NewRunnableMethod( |
342 download_manager, &DownloadManager::OnDownloadRenamedToFinalName, id, | 390 download_manager, &DownloadManager::OnDownloadRenamedToFinalName, id, |
343 new_path, uniquifier)); | 391 new_path, uniquifier)); |
344 } | 392 } |
345 | 393 |
346 // Called only from RenameInProgressDownloadFile and | 394 // Called only from RenameInProgressDownloadFile and |
347 // RenameCompletingDownloadFile on the FILE thread. | 395 // RenameCompletingDownloadFile on the FILE thread. |
348 void DownloadFileManager::CancelDownloadOnRename(int id) { | 396 void DownloadFileManager::CancelDownloadOnRename(int id, int rename_error) { |
349 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 397 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
350 | 398 |
351 DownloadFile* download_file = GetDownloadFile(id); | 399 DownloadFile* download_file = GetDownloadFile(id); |
352 if (!download_file) | 400 if (!download_file) |
353 return; | 401 return; |
354 | 402 |
355 DownloadManager* download_manager = download_file->GetDownloadManager(); | 403 DownloadManager* download_manager = download_file->GetDownloadManager(); |
356 if (!download_manager) { | 404 if (!download_manager) { |
357 // Without a download manager, we can't cancel the request normally, so we | 405 // Without a download manager, we can't cancel the request normally, so we |
358 // need to do it here. The normal path will also update the download | 406 // need to do it here. The normal path will also update the download |
359 // history before cancelling the request. | 407 // history before canceling the request. |
360 download_file->CancelDownloadRequest(); | 408 download_file->CancelDownloadRequest(); |
361 return; | 409 return; |
362 } | 410 } |
363 | 411 |
364 BrowserThread::PostTask( | 412 BrowserThread::PostTask( |
365 BrowserThread::UI, FROM_HERE, | 413 BrowserThread::UI, FROM_HERE, |
366 NewRunnableMethod(download_manager, | 414 NewRunnableMethod(download_manager, |
367 &DownloadManager::DownloadCancelled, id)); | 415 &DownloadManager::OnDownloadError, |
| 416 id, |
| 417 download_file->bytes_so_far(), |
| 418 rename_error)); |
368 } | 419 } |
369 | 420 |
370 void DownloadFileManager::EraseDownload(int id) { | 421 void DownloadFileManager::EraseDownload(int id) { |
371 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 422 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
372 | 423 |
373 if (!ContainsKey(downloads_, id)) | 424 if (!ContainsKey(downloads_, id)) |
374 return; | 425 return; |
375 | 426 |
376 DownloadFile* download_file = downloads_[id]; | 427 DownloadFile* download_file = downloads_[id]; |
377 | 428 |
378 VLOG(20) << " " << __FUNCTION__ << "()" | 429 VLOG(20) << " " << __FUNCTION__ << "()" |
379 << " id = " << id | 430 << " id = " << id |
380 << " download_file = " << download_file->DebugString(); | 431 << " download_file = " << download_file->DebugString(); |
381 | 432 |
382 downloads_.erase(id); | 433 downloads_.erase(id); |
383 | 434 |
384 delete download_file; | 435 delete download_file; |
385 | 436 |
386 if (downloads_.empty()) | 437 if (downloads_.empty()) |
387 StopUpdateTimer(); | 438 StopUpdateTimer(); |
388 } | 439 } |
OLD | NEW |