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_file_impl.h" | 5 #include "content/browser/download/download_file_impl.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
| 9 #include "base/bind.h" |
9 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 11 #include "base/message_loop_proxy.h" |
10 #include "content/browser/download/download_create_info.h" | 12 #include "content/browser/download/download_create_info.h" |
11 #include "content/public/browser/browser_thread.h" | 13 #include "content/public/browser/browser_thread.h" |
| 14 #include "content/browser/download/download_interrupt_reasons_impl.h" |
12 #include "content/public/browser/download_manager.h" | 15 #include "content/public/browser/download_manager.h" |
| 16 #include "content/browser/download/download_stats.h" |
| 17 #include "net/base/io_buffer.h" |
13 | 18 |
14 using content::BrowserThread; | 19 using content::BrowserThread; |
15 using content::DownloadId; | 20 using content::DownloadId; |
16 using content::DownloadManager; | 21 using content::DownloadManager; |
17 | 22 |
18 DownloadFileImpl::DownloadFileImpl( | 23 DownloadFileImpl::DownloadFileImpl( |
19 const DownloadCreateInfo* info, | 24 const DownloadCreateInfo* info, |
20 DownloadRequestHandleInterface* request_handle, | 25 DownloadRequestHandleInterface* request_handle, |
21 DownloadManager* download_manager, | 26 DownloadManager* download_manager, |
22 bool calculate_hash, | 27 bool calculate_hash, |
23 const net::BoundNetLog& bound_net_log) | 28 const net::BoundNetLog& bound_net_log) |
24 : file_(info->save_info.file_path, | 29 : file_(info->save_info.file_path, |
25 info->url(), | 30 info->url(), |
26 info->referrer_url, | 31 info->referrer_url, |
27 info->received_bytes, | 32 info->received_bytes, |
28 calculate_hash, | 33 calculate_hash, |
29 info->save_info.hash_state, | 34 info->save_info.hash_state, |
30 info->save_info.file_stream, | 35 info->save_info.file_stream, |
31 bound_net_log), | 36 bound_net_log), |
| 37 input_pipe_(info->pipe), |
32 id_(info->download_id), | 38 id_(info->download_id), |
33 request_handle_(request_handle), | 39 request_handle_(request_handle), |
34 download_manager_(download_manager) { | 40 download_manager_(download_manager) { |
35 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
36 } | 42 } |
37 | 43 |
38 DownloadFileImpl::~DownloadFileImpl() { | 44 DownloadFileImpl::~DownloadFileImpl() { |
39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 46 // Prevent any future callbacks from reaching us. |
| 47 if (input_pipe_.get()) |
| 48 input_pipe_->RegisterSinkCallback(scoped_refptr<base::TaskRunner>(), |
| 49 base::Closure()); |
40 } | 50 } |
41 | 51 |
42 // BaseFile delegated functions. | 52 // BaseFile delegated functions. |
43 net::Error DownloadFileImpl::Initialize() { | 53 net::Error DownloadFileImpl::Initialize() { |
44 return file_.Initialize(); | 54 net::Error result = file_.Initialize(); |
| 55 if (result != net::OK) |
| 56 return result; |
| 57 |
| 58 input_pipe_->RegisterSinkCallback( |
| 59 base::MessageLoopProxy::current(), |
| 60 // Unretained is safe because the callback is nulled in the |
| 61 // destructor. |
| 62 base::Bind(&DownloadFileImpl::PipeActive, base::Unretained(this))); |
| 63 |
| 64 // Initial pull from the straw. |
| 65 PipeActive(); |
| 66 |
| 67 return result; |
45 } | 68 } |
46 | 69 |
47 net::Error DownloadFileImpl::AppendDataToFile(const char* data, | 70 net::Error DownloadFileImpl::AppendDataToFile(const char* data, |
48 size_t data_len) { | 71 size_t data_len) { |
49 return file_.AppendDataToFile(data, data_len); | 72 return file_.AppendDataToFile(data, data_len); |
50 } | 73 } |
51 | 74 |
52 net::Error DownloadFileImpl::Rename(const FilePath& full_path) { | 75 net::Error DownloadFileImpl::Rename(const FilePath& full_path) { |
53 return file_.Rename(full_path); | 76 return file_.Rename(full_path); |
54 } | 77 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 std::string DownloadFileImpl::DebugString() const { | 138 std::string DownloadFileImpl::DebugString() const { |
116 return base::StringPrintf("{" | 139 return base::StringPrintf("{" |
117 " id_ = " "%d" | 140 " id_ = " "%d" |
118 " request_handle = %s" | 141 " request_handle = %s" |
119 " Base File = %s" | 142 " Base File = %s" |
120 " }", | 143 " }", |
121 id_.local(), | 144 id_.local(), |
122 request_handle_->DebugString().c_str(), | 145 request_handle_->DebugString().c_str(), |
123 file_.DebugString().c_str()); | 146 file_.DebugString().c_str()); |
124 } | 147 } |
| 148 |
| 149 void DownloadFileImpl::PipeActive() { |
| 150 scoped_refptr<net::IOBuffer> incoming_data; |
| 151 size_t length = 0; |
| 152 size_t total_length = 0; |
| 153 content::ByteStream::StreamState state(content::ByteStream::STREAM_EMPTY); |
| 154 content::DownloadInterruptReason reason = |
| 155 content::DOWNLOAD_INTERRUPT_REASON_NONE; |
| 156 |
| 157 // Take care of any file local activity required. |
| 158 do { |
| 159 state = input_pipe_->GetData(&incoming_data, &length); |
| 160 |
| 161 net::Error result = net::OK; |
| 162 switch (state) { |
| 163 case content::ByteStream::STREAM_EMPTY: |
| 164 break; |
| 165 case content::ByteStream::STREAM_NON_EMPTY: |
| 166 result = AppendDataToFile(incoming_data.get()->data(), length); |
| 167 total_length += length; |
| 168 reason = content::ConvertNetErrorToInterruptReason( |
| 169 result, content::DOWNLOAD_INTERRUPT_FROM_DISK); |
| 170 break; |
| 171 case content::ByteStream::STREAM_COMPLETE: |
| 172 reason = input_pipe_->GetSourceResult(); |
| 173 if (reason != content::DOWNLOAD_INTERRUPT_REASON_NONE) |
| 174 Finish(); |
| 175 break; |
| 176 default: |
| 177 NOTREACHED(); |
| 178 break; |
| 179 } |
| 180 } while (state == content::ByteStream::STREAM_NON_EMPTY && |
| 181 reason == content::DOWNLOAD_INTERRUPT_REASON_NONE); |
| 182 |
| 183 if (total_length) |
| 184 download_stats::RecordFileThreadReceiveBuffers(total_length); |
| 185 |
| 186 // Take care of communication with our controller. |
| 187 if (reason != content::DOWNLOAD_INTERRUPT_REASON_NONE) { |
| 188 // Error case for both upstream source and file write. |
| 189 // Shut down processing and signal an error to our controller. |
| 190 // Our controller will clean us up. |
| 191 input_pipe_->RegisterSinkCallback(scoped_refptr<base::TaskRunner>(), |
| 192 base::Closure()); |
| 193 if (download_manager_.get()) { |
| 194 BrowserThread::PostTask( |
| 195 BrowserThread::UI, FROM_HERE, |
| 196 base::Bind(&DownloadManager::OnDownloadInterrupted, |
| 197 download_manager_, id_.local(), |
| 198 BytesSoFar(), GetHashState(), reason)); |
| 199 } |
| 200 } else if (state == content::ByteStream::STREAM_COMPLETE) { |
| 201 // Signal successful completion. Processing shutdown shouldn't |
| 202 // be necessary, but it can't hurt to make sure. |
| 203 input_pipe_->RegisterSinkCallback(scoped_refptr<base::TaskRunner>(), |
| 204 base::Closure()); |
| 205 if (download_manager_.get()) { |
| 206 std::string hash; |
| 207 if (!GetHash(&hash) || file_.IsEmptyHash(hash)) |
| 208 hash.clear(); |
| 209 BrowserThread::PostTask( |
| 210 BrowserThread::UI, FROM_HERE, |
| 211 base::Bind(&DownloadManager::OnResponseCompleted, |
| 212 download_manager_, id_.local(), |
| 213 BytesSoFar(), hash)); |
| 214 } |
| 215 } |
| 216 } |
OLD | NEW |