Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: webkit/fileapi/file_writer_delegate.cc

Issue 15859007: Move browser-specific FileAPI code from webkit/fileapi to webkit/browser/fileapi (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: dump_file_system build fix Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/fileapi/file_writer_delegate.h ('k') | webkit/fileapi/file_writer_delegate_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "webkit/fileapi/file_writer_delegate.h"
6
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"
17
18 namespace fileapi {
19
20 static const int kReadBufSize = 32768;
21
22 namespace {
23
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;
37 }
38 }
39
40 } // namespace
41
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 weak_factory_(this) {
53 }
54
55 FileWriterDelegate::~FileWriterDelegate() {
56 }
57
58 void FileWriterDelegate::Start(scoped_ptr<net::URLRequest> request) {
59 request_ = request.Pass();
60 request_->Start();
61 }
62
63 bool FileWriterDelegate::Cancel() {
64 if (request_) {
65 // This halts any callbacks on this delegate.
66 request_->set_delegate(NULL);
67 request_->Cancel();
68 }
69
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);
76 }
77
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);
83 }
84
85 void FileWriterDelegate::OnAuthRequired(net::URLRequest* request,
86 net::AuthChallengeInfo* auth_info) {
87 NOTREACHED();
88 OnError(base::PLATFORM_FILE_ERROR_SECURITY);
89 }
90
91 void FileWriterDelegate::OnCertificateRequested(
92 net::URLRequest* request,
93 net::SSLCertRequestInfo* cert_request_info) {
94 NOTREACHED();
95 OnError(base::PLATFORM_FILE_ERROR_SECURITY);
96 }
97
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);
103 }
104
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;
110 }
111 Read();
112 }
113
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;
120 }
121 OnDataReceived(bytes_read);
122 }
123
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 base::MessageLoop::current()->PostTask(
129 FROM_HERE,
130 base::Bind(&FileWriterDelegate::OnDataReceived,
131 weak_factory_.GetWeakPtr(),
132 bytes_read_));
133 } else if (!request_->status().is_io_pending()) {
134 OnError(base::PLATFORM_FILE_ERROR_FAILED);
135 }
136 }
137
138 void FileWriterDelegate::OnDataReceived(int bytes_read) {
139 bytes_read_ = bytes_read;
140 if (!bytes_read_) { // We're done.
141 OnProgress(0, true);
142 } else {
143 // This could easily be optimized to rotate between a pool of buffers, so
144 // that we could read and write at the same time. It's not yet clear that
145 // it's necessary.
146 cursor_ = new net::DrainableIOBuffer(io_buffer_, bytes_read_);
147 Write();
148 }
149 }
150
151 void FileWriterDelegate::Write() {
152 writing_started_ = true;
153 int64 bytes_to_write = bytes_read_ - bytes_written_;
154 int write_response =
155 file_stream_writer_->Write(cursor_,
156 static_cast<int>(bytes_to_write),
157 base::Bind(&FileWriterDelegate::OnDataWritten,
158 weak_factory_.GetWeakPtr()));
159 if (write_response > 0)
160 base::MessageLoop::current()->PostTask(
161 FROM_HERE,
162 base::Bind(&FileWriterDelegate::OnDataWritten,
163 weak_factory_.GetWeakPtr(),
164 write_response));
165 else if (net::ERR_IO_PENDING != write_response)
166 OnError(NetErrorToPlatformFileError(write_response));
167 }
168
169 void FileWriterDelegate::OnDataWritten(int write_response) {
170 if (write_response > 0) {
171 OnProgress(write_response, false);
172 cursor_->DidConsume(write_response);
173 bytes_written_ += write_response;
174 if (bytes_written_ == bytes_read_)
175 Read();
176 else
177 Write();
178 } else {
179 OnError(NetErrorToPlatformFileError(write_response));
180 }
181 }
182
183 FileWriterDelegate::WriteProgressStatus
184 FileWriterDelegate::GetCompletionStatusOnError() const {
185 return writing_started_ ? ERROR_WRITE_STARTED : ERROR_WRITE_NOT_STARTED;
186 }
187
188 void FileWriterDelegate::OnError(base::PlatformFileError error) {
189 if (request_) {
190 request_->set_delegate(NULL);
191 request_->Cancel();
192 }
193
194 if (writing_started_)
195 FlushForCompletion(error, 0, ERROR_WRITE_STARTED);
196 else
197 write_callback_.Run(error, 0, ERROR_WRITE_NOT_STARTED);
198 }
199
200 void FileWriterDelegate::OnProgress(int bytes_written, bool done) {
201 DCHECK(bytes_written + bytes_written_backlog_ >= bytes_written_backlog_);
202 static const int kMinProgressDelayMS = 200;
203 base::Time currentTime = base::Time::Now();
204 if (done || last_progress_event_time_.is_null() ||
205 (currentTime - last_progress_event_time_).InMilliseconds() >
206 kMinProgressDelayMS) {
207 bytes_written += bytes_written_backlog_;
208 last_progress_event_time_ = currentTime;
209 bytes_written_backlog_ = 0;
210
211 if (done) {
212 FlushForCompletion(base::PLATFORM_FILE_OK, bytes_written,
213 SUCCESS_COMPLETED);
214 } else {
215 write_callback_.Run(base::PLATFORM_FILE_OK, bytes_written,
216 SUCCESS_IO_PENDING);
217 }
218 return;
219 }
220 bytes_written_backlog_ += bytes_written;
221 }
222
223 void FileWriterDelegate::OnWriteCancelled(int status) {
224 write_callback_.Run(base::PLATFORM_FILE_ERROR_ABORT, 0,
225 GetCompletionStatusOnError());
226 }
227
228 void FileWriterDelegate::FlushForCompletion(
229 base::PlatformFileError error,
230 int bytes_written,
231 WriteProgressStatus progress_status) {
232 int flush_error = file_stream_writer_->Flush(
233 base::Bind(&FileWriterDelegate::OnFlushed,
234 weak_factory_.GetWeakPtr(),
235 error, bytes_written, progress_status));
236 if (flush_error != net::ERR_IO_PENDING)
237 OnFlushed(error, bytes_written, progress_status, flush_error);
238 }
239
240 void FileWriterDelegate::OnFlushed(base::PlatformFileError error,
241 int bytes_written,
242 WriteProgressStatus progress_status,
243 int flush_error) {
244 if (error == base::PLATFORM_FILE_OK && flush_error != net::OK) {
245 // If the Flush introduced an error, overwrite the status.
246 // Otherwise, keep the original error status.
247 error = NetErrorToPlatformFileError(flush_error);
248 progress_status = GetCompletionStatusOnError();
249 }
250 write_callback_.Run(error, bytes_written, progress_status);
251 }
252
253 } // namespace fileapi
OLDNEW
« no previous file with comments | « webkit/fileapi/file_writer_delegate.h ('k') | webkit/fileapi/file_writer_delegate_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698