Respond with QuotaExceededError when IndexedDB has no disk space on open.
[chromium-blink-merge.git] / content / browser / download / download_file_impl.cc
blob67bee81b67aec9f987c1dfc7e00ee0eba108ac50
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
3 // found in the LICENSE file.
5 #include "content/browser/download/download_file_impl.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/file_util.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/time/time.h"
14 #include "content/browser/byte_stream.h"
15 #include "content/browser/download/download_create_info.h"
16 #include "content/browser/download/download_interrupt_reasons_impl.h"
17 #include "content/browser/download/download_net_log_parameters.h"
18 #include "content/browser/download/download_stats.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/download_destination_observer.h"
21 #include "content/public/browser/power_save_blocker.h"
22 #include "net/base/io_buffer.h"
24 namespace content {
26 const int kUpdatePeriodMs = 500;
27 const int kMaxTimeBlockingFileThreadMs = 1000;
29 int DownloadFile::number_active_objects_ = 0;
31 DownloadFileImpl::DownloadFileImpl(
32 scoped_ptr<DownloadSaveInfo> save_info,
33 const base::FilePath& default_download_directory,
34 const GURL& url,
35 const GURL& referrer_url,
36 bool calculate_hash,
37 scoped_ptr<ByteStreamReader> stream,
38 const net::BoundNetLog& bound_net_log,
39 scoped_ptr<PowerSaveBlocker> power_save_blocker,
40 base::WeakPtr<DownloadDestinationObserver> observer)
41 : file_(save_info->file_path,
42 url,
43 referrer_url,
44 save_info->offset,
45 calculate_hash,
46 save_info->hash_state,
47 save_info->file_stream.Pass(),
48 bound_net_log),
49 default_download_directory_(default_download_directory),
50 stream_reader_(stream.Pass()),
51 bytes_seen_(0),
52 bound_net_log_(bound_net_log),
53 observer_(observer),
54 weak_factory_(this),
55 power_save_blocker_(power_save_blocker.Pass()) {
58 DownloadFileImpl::~DownloadFileImpl() {
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
60 --number_active_objects_;
63 void DownloadFileImpl::Initialize(const InitializeCallback& callback) {
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
66 update_timer_.reset(new base::RepeatingTimer<DownloadFileImpl>());
67 DownloadInterruptReason result =
68 file_.Initialize(default_download_directory_);
69 if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
70 BrowserThread::PostTask(
71 BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
72 return;
75 stream_reader_->RegisterCallback(
76 base::Bind(&DownloadFileImpl::StreamActive, weak_factory_.GetWeakPtr()));
78 download_start_ = base::TimeTicks::Now();
80 // Primarily to make reset to zero in restart visible to owner.
81 SendUpdate();
83 // Initial pull from the straw.
84 StreamActive();
86 BrowserThread::PostTask(
87 BrowserThread::UI, FROM_HERE, base::Bind(
88 callback, DOWNLOAD_INTERRUPT_REASON_NONE));
90 ++number_active_objects_;
93 DownloadInterruptReason DownloadFileImpl::AppendDataToFile(
94 const char* data, size_t data_len) {
95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
97 if (!update_timer_->IsRunning()) {
98 update_timer_->Start(FROM_HERE,
99 base::TimeDelta::FromMilliseconds(kUpdatePeriodMs),
100 this, &DownloadFileImpl::SendUpdate);
102 rate_estimator_.Increment(data_len);
103 return file_.AppendDataToFile(data, data_len);
106 void DownloadFileImpl::RenameAndUniquify(
107 const base::FilePath& full_path,
108 const RenameCompletionCallback& callback) {
109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
111 base::FilePath new_path(full_path);
113 int uniquifier = file_util::GetUniquePathNumber(
114 new_path, base::FilePath::StringType());
115 if (uniquifier > 0) {
116 new_path = new_path.InsertBeforeExtensionASCII(
117 base::StringPrintf(" (%d)", uniquifier));
120 DownloadInterruptReason reason = file_.Rename(new_path);
121 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
122 // Make sure our information is updated, since we're about to
123 // error out.
124 SendUpdate();
126 // Null out callback so that we don't do any more stream processing.
127 stream_reader_->RegisterCallback(base::Closure());
129 new_path.clear();
132 BrowserThread::PostTask(
133 BrowserThread::UI, FROM_HERE,
134 base::Bind(callback, reason, new_path));
137 void DownloadFileImpl::RenameAndAnnotate(
138 const base::FilePath& full_path,
139 const RenameCompletionCallback& callback) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
142 base::FilePath new_path(full_path);
144 DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE;
145 // Short circuit null rename.
146 if (full_path != file_.full_path())
147 reason = file_.Rename(new_path);
149 if (reason == DOWNLOAD_INTERRUPT_REASON_NONE) {
150 // Doing the annotation after the rename rather than before leaves
151 // a very small window during which the file has the final name but
152 // hasn't been marked with the Mark Of The Web. However, it allows
153 // anti-virus scanners on Windows to actually see the data
154 // (http://crbug.com/127999) under the correct name (which is information
155 // it uses).
156 reason = file_.AnnotateWithSourceInformation();
159 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
160 // Make sure our information is updated, since we're about to
161 // error out.
162 SendUpdate();
164 // Null out callback so that we don't do any more stream processing.
165 stream_reader_->RegisterCallback(base::Closure());
167 new_path.clear();
170 BrowserThread::PostTask(
171 BrowserThread::UI, FROM_HERE,
172 base::Bind(callback, reason, new_path));
175 void DownloadFileImpl::Detach() {
176 file_.Detach();
179 void DownloadFileImpl::Cancel() {
180 file_.Cancel();
183 base::FilePath DownloadFileImpl::FullPath() const {
184 return file_.full_path();
187 bool DownloadFileImpl::InProgress() const {
188 return file_.in_progress();
191 int64 DownloadFileImpl::CurrentSpeed() const {
192 return rate_estimator_.GetCountPerSecond();
195 bool DownloadFileImpl::GetHash(std::string* hash) {
196 return file_.GetHash(hash);
199 std::string DownloadFileImpl::GetHashState() {
200 return file_.GetHashState();
203 void DownloadFileImpl::SetClientGuid(const std::string& guid) {
204 file_.SetClientGuid(guid);
207 void DownloadFileImpl::StreamActive() {
208 base::TimeTicks start(base::TimeTicks::Now());
209 base::TimeTicks now;
210 scoped_refptr<net::IOBuffer> incoming_data;
211 size_t incoming_data_size = 0;
212 size_t total_incoming_data_size = 0;
213 size_t num_buffers = 0;
214 ByteStreamReader::StreamState state(ByteStreamReader::STREAM_EMPTY);
215 DownloadInterruptReason reason = DOWNLOAD_INTERRUPT_REASON_NONE;
216 base::TimeDelta delta(
217 base::TimeDelta::FromMilliseconds(kMaxTimeBlockingFileThreadMs));
219 // Take care of any file local activity required.
220 do {
221 state = stream_reader_->Read(&incoming_data, &incoming_data_size);
223 switch (state) {
224 case ByteStreamReader::STREAM_EMPTY:
225 break;
226 case ByteStreamReader::STREAM_HAS_DATA:
228 ++num_buffers;
229 base::TimeTicks write_start(base::TimeTicks::Now());
230 reason = AppendDataToFile(
231 incoming_data.get()->data(), incoming_data_size);
232 disk_writes_time_ += (base::TimeTicks::Now() - write_start);
233 bytes_seen_ += incoming_data_size;
234 total_incoming_data_size += incoming_data_size;
236 break;
237 case ByteStreamReader::STREAM_COMPLETE:
239 reason = static_cast<DownloadInterruptReason>(
240 stream_reader_->GetStatus());
241 SendUpdate();
242 base::TimeTicks close_start(base::TimeTicks::Now());
243 file_.Finish();
244 base::TimeTicks now(base::TimeTicks::Now());
245 disk_writes_time_ += (now - close_start);
246 RecordFileBandwidth(
247 bytes_seen_, disk_writes_time_, now - download_start_);
248 update_timer_.reset();
250 break;
251 default:
252 NOTREACHED();
253 break;
255 now = base::TimeTicks::Now();
256 } while (state == ByteStreamReader::STREAM_HAS_DATA &&
257 reason == DOWNLOAD_INTERRUPT_REASON_NONE &&
258 now - start <= delta);
260 // If we're stopping to yield the thread, post a task so we come back.
261 if (state == ByteStreamReader::STREAM_HAS_DATA &&
262 now - start > delta) {
263 BrowserThread::PostTask(
264 BrowserThread::FILE, FROM_HERE,
265 base::Bind(&DownloadFileImpl::StreamActive,
266 weak_factory_.GetWeakPtr()));
269 if (total_incoming_data_size)
270 RecordFileThreadReceiveBuffers(num_buffers);
272 RecordContiguousWriteTime(now - start);
274 // Take care of communication with our observer.
275 if (reason != DOWNLOAD_INTERRUPT_REASON_NONE) {
276 // Error case for both upstream source and file write.
277 // Shut down processing and signal an error to our observer.
278 // Our observer will clean us up.
279 stream_reader_->RegisterCallback(base::Closure());
280 weak_factory_.InvalidateWeakPtrs();
281 SendUpdate(); // Make info up to date before error.
282 BrowserThread::PostTask(
283 BrowserThread::UI, FROM_HERE,
284 base::Bind(&DownloadDestinationObserver::DestinationError,
285 observer_, reason));
286 } else if (state == ByteStreamReader::STREAM_COMPLETE) {
287 // Signal successful completion and shut down processing.
288 stream_reader_->RegisterCallback(base::Closure());
289 weak_factory_.InvalidateWeakPtrs();
290 std::string hash;
291 if (!GetHash(&hash) || file_.IsEmptyHash(hash))
292 hash.clear();
293 SendUpdate();
294 BrowserThread::PostTask(
295 BrowserThread::UI, FROM_HERE,
296 base::Bind(
297 &DownloadDestinationObserver::DestinationCompleted,
298 observer_, hash));
300 if (bound_net_log_.IsLoggingAllEvents()) {
301 bound_net_log_.AddEvent(
302 net::NetLog::TYPE_DOWNLOAD_STREAM_DRAINED,
303 base::Bind(&FileStreamDrainedNetLogCallback, total_incoming_data_size,
304 num_buffers));
308 void DownloadFileImpl::SendUpdate() {
309 BrowserThread::PostTask(
310 BrowserThread::UI, FROM_HERE,
311 base::Bind(&DownloadDestinationObserver::DestinationUpdate,
312 observer_, file_.bytes_so_far(), CurrentSpeed(),
313 GetHashState()));
316 // static
317 int DownloadFile::GetNumberOfDownloadFiles() {
318 return number_active_objects_;
321 } // namespace content