- add sources.
[platform/framework/web/crosswalk.git] / src / net / base / upload_file_element_reader.cc
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 "net/base/upload_file_element_reader.h"
6
7 #include "base/bind.h"
8 #include "base/file_util.h"
9 #include "base/location.h"
10 #include "base/task_runner_util.h"
11 #include "net/base/file_stream.h"
12 #include "net/base/io_buffer.h"
13 #include "net/base/net_errors.h"
14
15 namespace net {
16
17 namespace {
18
19 // In tests, this value is used to override the return value of
20 // UploadFileElementReader::GetContentLength() when set to non-zero.
21 uint64 overriding_content_length = 0;
22
23 // This function is used to implement Init().
24 template<typename FileStreamDeleter>
25 int InitInternal(const base::FilePath& path,
26                  uint64 range_offset,
27                  uint64 range_length,
28                  const base::Time& expected_modification_time,
29                  scoped_ptr<FileStream, FileStreamDeleter>* out_file_stream,
30                  uint64* out_content_length) {
31   scoped_ptr<FileStream> file_stream(new FileStream(NULL));
32   int64 rv = file_stream->OpenSync(
33       path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ);
34   if (rv != OK) {
35     // If the file can't be opened, we'll just upload an empty file.
36     DLOG(WARNING) << "Failed to open \"" << path.value()
37                   << "\" for reading: " << rv;
38     file_stream.reset();
39   } else if (range_offset) {
40     rv = file_stream->SeekSync(FROM_BEGIN, range_offset);
41     if (rv < 0) {
42       DLOG(WARNING) << "Failed to seek \"" << path.value()
43                     << "\" to offset: " << range_offset << " (" << rv << ")";
44       file_stream.reset();
45     }
46   }
47
48   int64 length = 0;
49   if (file_stream.get() &&
50       file_util::GetFileSize(path, &length) &&
51       range_offset < static_cast<uint64>(length)) {
52     // Compensate for the offset.
53     length = std::min(length - range_offset, range_length);
54   }
55   *out_content_length = length;
56   out_file_stream->reset(file_stream.release());
57
58   // If the underlying file has been changed and the expected file modification
59   // time is set, treat it as error. Note that the expected modification time
60   // from WebKit is based on time_t precision. So we have to convert both to
61   // time_t to compare. This check is used for sliced files.
62   if (!expected_modification_time.is_null()) {
63     base::PlatformFileInfo info;
64     if (file_util::GetFileInfo(path, &info) &&
65         expected_modification_time.ToTimeT() != info.last_modified.ToTimeT()) {
66       return ERR_UPLOAD_FILE_CHANGED;
67     }
68   }
69
70   return OK;
71 }
72
73 // This function is used to implement Read().
74 int ReadInternal(scoped_refptr<IOBuffer> buf,
75                  int buf_length,
76                  uint64 bytes_remaining,
77                  FileStream* file_stream) {
78   DCHECK_LT(0, buf_length);
79
80   const uint64 num_bytes_to_read =
81       std::min(bytes_remaining, static_cast<uint64>(buf_length));
82
83   int result = 0;
84   if (num_bytes_to_read > 0) {
85     DCHECK(file_stream);  // file_stream is non-null if content_length_ > 0.
86     result = file_stream->ReadSync(buf->data(), num_bytes_to_read);
87     if (result == 0)  // Reached end-of-file earlier than expected.
88       result = ERR_UPLOAD_FILE_CHANGED;
89   }
90   return result;
91 }
92
93 }  // namespace
94
95 UploadFileElementReader::FileStreamDeleter::FileStreamDeleter(
96     base::TaskRunner* task_runner) : task_runner_(task_runner) {
97   DCHECK(task_runner_.get());
98 }
99
100 UploadFileElementReader::FileStreamDeleter::~FileStreamDeleter() {}
101
102 void UploadFileElementReader::FileStreamDeleter::operator() (
103     FileStream* file_stream) const {
104   if (file_stream) {
105     task_runner_->PostTask(FROM_HERE,
106                            base::Bind(&base::DeletePointer<FileStream>,
107                                       file_stream));
108   }
109 }
110
111 UploadFileElementReader::UploadFileElementReader(
112     base::TaskRunner* task_runner,
113     const base::FilePath& path,
114     uint64 range_offset,
115     uint64 range_length,
116     const base::Time& expected_modification_time)
117     : task_runner_(task_runner),
118       path_(path),
119       range_offset_(range_offset),
120       range_length_(range_length),
121       expected_modification_time_(expected_modification_time),
122       file_stream_(NULL, FileStreamDeleter(task_runner_.get())),
123       content_length_(0),
124       bytes_remaining_(0),
125       weak_ptr_factory_(this) {
126   DCHECK(task_runner_.get());
127 }
128
129 UploadFileElementReader::~UploadFileElementReader() {
130 }
131
132 const UploadFileElementReader* UploadFileElementReader::AsFileReader() const {
133   return this;
134 }
135
136 int UploadFileElementReader::Init(const CompletionCallback& callback) {
137   DCHECK(!callback.is_null());
138   Reset();
139
140   ScopedFileStreamPtr* file_stream =
141       new ScopedFileStreamPtr(NULL, FileStreamDeleter(task_runner_.get()));
142   uint64* content_length = new uint64;
143   const bool posted = base::PostTaskAndReplyWithResult(
144       task_runner_.get(),
145       FROM_HERE,
146       base::Bind(&InitInternal<FileStreamDeleter>,
147                  path_,
148                  range_offset_,
149                  range_length_,
150                  expected_modification_time_,
151                  file_stream,
152                  content_length),
153       base::Bind(&UploadFileElementReader::OnInitCompleted,
154                  weak_ptr_factory_.GetWeakPtr(),
155                  base::Owned(file_stream),
156                  base::Owned(content_length),
157                  callback));
158   DCHECK(posted);
159   return ERR_IO_PENDING;
160 }
161
162 uint64 UploadFileElementReader::GetContentLength() const {
163   if (overriding_content_length)
164     return overriding_content_length;
165   return content_length_;
166 }
167
168 uint64 UploadFileElementReader::BytesRemaining() const {
169   return bytes_remaining_;
170 }
171
172 int UploadFileElementReader::Read(IOBuffer* buf,
173                                   int buf_length,
174                                   const CompletionCallback& callback) {
175   DCHECK(!callback.is_null());
176
177   if (BytesRemaining() == 0)
178     return 0;
179
180   // Save the value of file_stream_.get() before base::Passed() invalidates it.
181   FileStream* file_stream_ptr = file_stream_.get();
182   // Pass the ownership of file_stream_ to the worker pool to safely perform
183   // operation even when |this| is destructed before the read completes.
184   const bool posted = base::PostTaskAndReplyWithResult(
185       task_runner_.get(),
186       FROM_HERE,
187       base::Bind(&ReadInternal,
188                  scoped_refptr<IOBuffer>(buf),
189                  buf_length,
190                  BytesRemaining(),
191                  file_stream_ptr),
192       base::Bind(&UploadFileElementReader::OnReadCompleted,
193                  weak_ptr_factory_.GetWeakPtr(),
194                  base::Passed(&file_stream_),
195                  callback));
196   DCHECK(posted);
197   return ERR_IO_PENDING;
198 }
199
200 void UploadFileElementReader::Reset() {
201   weak_ptr_factory_.InvalidateWeakPtrs();
202   bytes_remaining_ = 0;
203   content_length_ = 0;
204   file_stream_.reset();
205 }
206
207 void UploadFileElementReader::OnInitCompleted(
208     ScopedFileStreamPtr* file_stream,
209     uint64* content_length,
210     const CompletionCallback& callback,
211     int result) {
212   file_stream_.swap(*file_stream);
213   content_length_ = *content_length;
214   bytes_remaining_ = GetContentLength();
215   if (!callback.is_null())
216     callback.Run(result);
217 }
218
219 void UploadFileElementReader::OnReadCompleted(
220     ScopedFileStreamPtr file_stream,
221     const CompletionCallback& callback,
222     int result) {
223   file_stream_.swap(file_stream);
224   if (result > 0) {
225     DCHECK_GE(bytes_remaining_, static_cast<uint64>(result));
226     bytes_remaining_ -= result;
227   }
228   if (!callback.is_null())
229     callback.Run(result);
230 }
231
232 UploadFileElementReader::ScopedOverridingContentLengthForTests::
233 ScopedOverridingContentLengthForTests(uint64 value) {
234   overriding_content_length = value;
235 }
236
237 UploadFileElementReader::ScopedOverridingContentLengthForTests::
238 ~ScopedOverridingContentLengthForTests() {
239   overriding_content_length = 0;
240 }
241
242 UploadFileElementReaderSync::UploadFileElementReaderSync(
243     const base::FilePath& path,
244     uint64 range_offset,
245     uint64 range_length,
246     const base::Time& expected_modification_time)
247     : path_(path),
248       range_offset_(range_offset),
249       range_length_(range_length),
250       expected_modification_time_(expected_modification_time),
251       content_length_(0),
252       bytes_remaining_(0) {
253 }
254
255 UploadFileElementReaderSync::~UploadFileElementReaderSync() {
256 }
257
258 int UploadFileElementReaderSync::Init(const CompletionCallback& callback) {
259   bytes_remaining_ = 0;
260   content_length_ = 0;
261   file_stream_.reset();
262
263   const int result = InitInternal(path_, range_offset_, range_length_,
264                                   expected_modification_time_,
265                                   &file_stream_, &content_length_);
266   bytes_remaining_ = GetContentLength();
267   return result;
268 }
269
270 uint64 UploadFileElementReaderSync::GetContentLength() const {
271   return content_length_;
272 }
273
274 uint64 UploadFileElementReaderSync::BytesRemaining() const {
275   return bytes_remaining_;
276 }
277
278 int UploadFileElementReaderSync::Read(IOBuffer* buf,
279                                       int buf_length,
280                                       const CompletionCallback& callback) {
281   const int result = ReadInternal(buf, buf_length, BytesRemaining(),
282                                   file_stream_.get());
283   if (result > 0) {
284     DCHECK_GE(bytes_remaining_, static_cast<uint64>(result));
285     bytes_remaining_ -= result;
286   }
287   return result;
288 }
289
290 }  // namespace net