Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / webkit / fileapi / file_writer_delegate.cc
blob5fd20a9ec2e93646bc15e1f7ee276d1c4befb27e
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 "webkit/fileapi/file_writer_delegate.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/files/file_util_proxy.h"
10 #include "base/message_loop.h"
11 #include "base/message_loop_proxy.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "net/base/net_errors.h"
15 #include "webkit/fileapi/file_stream_writer.h"
16 #include "webkit/fileapi/file_system_context.h"
18 namespace fileapi {
20 static const int kReadBufSize = 32768;
22 namespace {
24 base::PlatformFileError NetErrorToPlatformFileError(int error) {
25 // TODO(kinuko): Move this static method to more convenient place.
26 switch (error) {
27 case net::OK:
28 return base::PLATFORM_FILE_OK;
29 case net::ERR_FILE_NO_SPACE:
30 return base::PLATFORM_FILE_ERROR_NO_SPACE;
31 case net::ERR_FILE_NOT_FOUND:
32 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
33 case net::ERR_ACCESS_DENIED:
34 return base::PLATFORM_FILE_ERROR_ACCESS_DENIED;
35 default:
36 return base::PLATFORM_FILE_ERROR_FAILED;
40 } // namespace
42 FileWriterDelegate::FileWriterDelegate(
43 const DelegateWriteCallback& write_callback,
44 scoped_ptr<FileStreamWriter> file_stream_writer)
45 : write_callback_(write_callback),
46 file_stream_writer_(file_stream_writer.Pass()),
47 writing_started_(false),
48 bytes_written_backlog_(0),
49 bytes_written_(0),
50 bytes_read_(0),
51 io_buffer_(new net::IOBufferWithSize(kReadBufSize)),
52 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
55 FileWriterDelegate::~FileWriterDelegate() {
58 void FileWriterDelegate::Start(scoped_ptr<net::URLRequest> request) {
59 request_ = request.Pass();
60 request_->Start();
63 bool FileWriterDelegate::Cancel() {
64 if (request_.get()) {
65 // This halts any callbacks on this delegate.
66 request_->set_delegate(NULL);
67 request_->Cancel();
70 const int status = file_stream_writer_->Cancel(
71 base::Bind(&FileWriterDelegate::OnWriteCancelled,
72 weak_factory_.GetWeakPtr()));
73 // Return true to finish immediately if we have no pending writes.
74 // Otherwise we'll do the final cleanup in the Cancel callback.
75 return (status != net::ERR_IO_PENDING);
78 void FileWriterDelegate::OnReceivedRedirect(net::URLRequest* request,
79 const GURL& new_url,
80 bool* defer_redirect) {
81 NOTREACHED();
82 OnError(base::PLATFORM_FILE_ERROR_SECURITY);
85 void FileWriterDelegate::OnAuthRequired(net::URLRequest* request,
86 net::AuthChallengeInfo* auth_info) {
87 NOTREACHED();
88 OnError(base::PLATFORM_FILE_ERROR_SECURITY);
91 void FileWriterDelegate::OnCertificateRequested(
92 net::URLRequest* request,
93 net::SSLCertRequestInfo* cert_request_info) {
94 NOTREACHED();
95 OnError(base::PLATFORM_FILE_ERROR_SECURITY);
98 void FileWriterDelegate::OnSSLCertificateError(net::URLRequest* request,
99 const net::SSLInfo& ssl_info,
100 bool fatal) {
101 NOTREACHED();
102 OnError(base::PLATFORM_FILE_ERROR_SECURITY);
105 void FileWriterDelegate::OnResponseStarted(net::URLRequest* request) {
106 DCHECK_EQ(request_.get(), request);
107 if (!request->status().is_success() || request->GetResponseCode() != 200) {
108 OnError(base::PLATFORM_FILE_ERROR_FAILED);
109 return;
111 Read();
114 void FileWriterDelegate::OnReadCompleted(net::URLRequest* request,
115 int bytes_read) {
116 DCHECK_EQ(request_.get(), request);
117 if (!request->status().is_success()) {
118 OnError(base::PLATFORM_FILE_ERROR_FAILED);
119 return;
121 OnDataReceived(bytes_read);
124 void FileWriterDelegate::Read() {
125 bytes_written_ = 0;
126 bytes_read_ = 0;
127 if (request_->Read(io_buffer_.get(), io_buffer_->size(), &bytes_read_)) {
128 MessageLoop::current()->PostTask(
129 FROM_HERE,
130 base::Bind(&FileWriterDelegate::OnDataReceived,
131 weak_factory_.GetWeakPtr(), bytes_read_));
132 } else if (!request_->status().is_io_pending()) {
133 OnError(base::PLATFORM_FILE_ERROR_FAILED);
137 void FileWriterDelegate::OnDataReceived(int bytes_read) {
138 bytes_read_ = bytes_read;
139 if (!bytes_read_) { // We're done.
140 OnProgress(0, true);
141 } else {
142 // This could easily be optimized to rotate between a pool of buffers, so
143 // that we could read and write at the same time. It's not yet clear that
144 // it's necessary.
145 cursor_ = new net::DrainableIOBuffer(io_buffer_, bytes_read_);
146 Write();
150 void FileWriterDelegate::Write() {
151 writing_started_ = true;
152 int64 bytes_to_write = bytes_read_ - bytes_written_;
153 int write_response =
154 file_stream_writer_->Write(cursor_,
155 static_cast<int>(bytes_to_write),
156 base::Bind(&FileWriterDelegate::OnDataWritten,
157 weak_factory_.GetWeakPtr()));
158 if (write_response > 0)
159 MessageLoop::current()->PostTask(
160 FROM_HERE,
161 base::Bind(&FileWriterDelegate::OnDataWritten,
162 weak_factory_.GetWeakPtr(), write_response));
163 else if (net::ERR_IO_PENDING != write_response)
164 OnError(NetErrorToPlatformFileError(write_response));
167 void FileWriterDelegate::OnDataWritten(int write_response) {
168 if (write_response > 0) {
169 OnProgress(write_response, false);
170 cursor_->DidConsume(write_response);
171 bytes_written_ += write_response;
172 if (bytes_written_ == bytes_read_)
173 Read();
174 else
175 Write();
176 } else {
177 OnError(NetErrorToPlatformFileError(write_response));
181 FileWriterDelegate::WriteProgressStatus
182 FileWriterDelegate::GetCompletionStatusOnError() const {
183 return writing_started_ ? ERROR_WRITE_STARTED : ERROR_WRITE_NOT_STARTED;
186 void FileWriterDelegate::OnError(base::PlatformFileError error) {
187 if (request_.get()) {
188 request_->set_delegate(NULL);
189 request_->Cancel();
192 if (writing_started_)
193 FlushForCompletion(error, 0, ERROR_WRITE_STARTED);
194 else
195 write_callback_.Run(error, 0, ERROR_WRITE_NOT_STARTED);
198 void FileWriterDelegate::OnProgress(int bytes_written, bool done) {
199 DCHECK(bytes_written + bytes_written_backlog_ >= bytes_written_backlog_);
200 static const int kMinProgressDelayMS = 200;
201 base::Time currentTime = base::Time::Now();
202 if (done || last_progress_event_time_.is_null() ||
203 (currentTime - last_progress_event_time_).InMilliseconds() >
204 kMinProgressDelayMS) {
205 bytes_written += bytes_written_backlog_;
206 last_progress_event_time_ = currentTime;
207 bytes_written_backlog_ = 0;
209 if (done) {
210 FlushForCompletion(base::PLATFORM_FILE_OK, bytes_written,
211 SUCCESS_COMPLETED);
212 } else {
213 write_callback_.Run(base::PLATFORM_FILE_OK, bytes_written,
214 SUCCESS_IO_PENDING);
216 return;
218 bytes_written_backlog_ += bytes_written;
221 void FileWriterDelegate::OnWriteCancelled(int status) {
222 write_callback_.Run(base::PLATFORM_FILE_ERROR_ABORT, 0,
223 GetCompletionStatusOnError());
226 void FileWriterDelegate::FlushForCompletion(
227 base::PlatformFileError error,
228 int bytes_written,
229 WriteProgressStatus progress_status) {
230 int flush_error = file_stream_writer_->Flush(
231 base::Bind(&FileWriterDelegate::OnFlushed,
232 weak_factory_.GetWeakPtr(),
233 error, bytes_written, progress_status));
234 if (flush_error != net::ERR_IO_PENDING)
235 OnFlushed(error, bytes_written, progress_status, flush_error);
238 void FileWriterDelegate::OnFlushed(base::PlatformFileError error,
239 int bytes_written,
240 WriteProgressStatus progress_status,
241 int flush_error) {
242 if (error == base::PLATFORM_FILE_OK && flush_error != net::OK) {
243 // If the Flush introduced an error, overwrite the status.
244 // Otherwise, keep the original error status.
245 error = NetErrorToPlatformFileError(flush_error);
246 progress_status = GetCompletionStatusOnError();
248 write_callback_.Run(error, bytes_written, progress_status);
251 } // namespace fileapi