Upstream version 10.39.225.0
[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/files/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 }  // namespace
24
25 UploadFileElementReader::UploadFileElementReader(
26     base::TaskRunner* task_runner,
27     const base::FilePath& path,
28     uint64 range_offset,
29     uint64 range_length,
30     const base::Time& expected_modification_time)
31     : task_runner_(task_runner),
32       path_(path),
33       range_offset_(range_offset),
34       range_length_(range_length),
35       expected_modification_time_(expected_modification_time),
36       content_length_(0),
37       bytes_remaining_(0),
38       weak_ptr_factory_(this) {
39   DCHECK(task_runner_.get());
40 }
41
42 UploadFileElementReader::~UploadFileElementReader() {
43 }
44
45 const UploadFileElementReader* UploadFileElementReader::AsFileReader() const {
46   return this;
47 }
48
49 int UploadFileElementReader::Init(const CompletionCallback& callback) {
50   DCHECK(!callback.is_null());
51   Reset();
52
53   file_stream_.reset(new FileStream(task_runner_.get()));
54   int result = file_stream_->Open(
55       path_,
56       base::File::FLAG_OPEN | base::File::FLAG_READ |
57       base::File::FLAG_ASYNC,
58       base::Bind(&UploadFileElementReader::OnOpenCompleted,
59                  weak_ptr_factory_.GetWeakPtr(),
60                  callback));
61   DCHECK_GT(0, result);
62   return result;
63 }
64
65 uint64 UploadFileElementReader::GetContentLength() const {
66   if (overriding_content_length)
67     return overriding_content_length;
68   return content_length_;
69 }
70
71 uint64 UploadFileElementReader::BytesRemaining() const {
72   return bytes_remaining_;
73 }
74
75 int UploadFileElementReader::Read(IOBuffer* buf,
76                                   int buf_length,
77                                   const CompletionCallback& callback) {
78   DCHECK(!callback.is_null());
79
80   uint64 num_bytes_to_read =
81       std::min(BytesRemaining(), static_cast<uint64>(buf_length));
82   if (num_bytes_to_read == 0)
83     return 0;
84
85   int result = file_stream_->Read(
86       buf, num_bytes_to_read,
87       base::Bind(base::IgnoreResult(&UploadFileElementReader::OnReadCompleted),
88                  weak_ptr_factory_.GetWeakPtr(),
89                  callback));
90   // Even in async mode, FileStream::Read() may return the result synchronously.
91   if (result != ERR_IO_PENDING)
92     return OnReadCompleted(CompletionCallback(), result);
93   return ERR_IO_PENDING;
94 }
95
96 void UploadFileElementReader::Reset() {
97   weak_ptr_factory_.InvalidateWeakPtrs();
98   bytes_remaining_ = 0;
99   content_length_ = 0;
100   file_stream_.reset();
101 }
102
103 void UploadFileElementReader::OnOpenCompleted(
104     const CompletionCallback& callback,
105     int result) {
106   DCHECK(!callback.is_null());
107
108   if (result < 0) {
109     DLOG(WARNING) << "Failed to open \"" << path_.value()
110                   << "\" for reading: " << result;
111     callback.Run(result);
112     return;
113   }
114
115   if (range_offset_) {
116     int result = file_stream_->Seek(
117         base::File::FROM_BEGIN, range_offset_,
118         base::Bind(&UploadFileElementReader::OnSeekCompleted,
119                    weak_ptr_factory_.GetWeakPtr(),
120                    callback));
121     DCHECK_GT(0, result);
122     if (result != ERR_IO_PENDING)
123       callback.Run(result);
124   } else {
125     OnSeekCompleted(callback, OK);
126   }
127 }
128
129 void UploadFileElementReader::OnSeekCompleted(
130     const CompletionCallback& callback,
131     int64 result) {
132   DCHECK(!callback.is_null());
133
134   if (result < 0) {
135     DLOG(WARNING) << "Failed to seek \"" << path_.value()
136                   << "\" to offset: " << range_offset_ << " (" << result << ")";
137     callback.Run(result);
138     return;
139   }
140
141   base::File::Info* file_info = new base::File::Info;
142   bool posted = base::PostTaskAndReplyWithResult(
143       task_runner_.get(),
144       FROM_HERE,
145       base::Bind(&base::GetFileInfo, path_, file_info),
146       base::Bind(&UploadFileElementReader::OnGetFileInfoCompleted,
147                  weak_ptr_factory_.GetWeakPtr(),
148                  callback,
149                  base::Owned(file_info)));
150   DCHECK(posted);
151 }
152
153 void UploadFileElementReader::OnGetFileInfoCompleted(
154     const CompletionCallback& callback,
155     base::File::Info* file_info,
156     bool result) {
157   DCHECK(!callback.is_null());
158   if (!result) {
159     DLOG(WARNING) << "Failed to get file info of \"" << path_.value() << "\"";
160     callback.Run(ERR_FILE_NOT_FOUND);
161     return;
162   }
163
164   int64 length = file_info->size;
165   if (range_offset_ < static_cast<uint64>(length)) {
166     // Compensate for the offset.
167     length = std::min(length - range_offset_, range_length_);
168   }
169
170   // If the underlying file has been changed and the expected file modification
171   // time is set, treat it as error. Note that the expected modification time
172   // from WebKit is based on time_t precision. So we have to convert both to
173   // time_t to compare. This check is used for sliced files.
174   if (!expected_modification_time_.is_null() &&
175       expected_modification_time_.ToTimeT() !=
176       file_info->last_modified.ToTimeT()) {
177     callback.Run(ERR_UPLOAD_FILE_CHANGED);
178     return;
179   }
180
181   content_length_ = length;
182   bytes_remaining_ = GetContentLength();
183   callback.Run(OK);
184 }
185
186 int UploadFileElementReader::OnReadCompleted(
187     const CompletionCallback& callback,
188     int result) {
189   if (result == 0)  // Reached end-of-file earlier than expected.
190     result = ERR_UPLOAD_FILE_CHANGED;
191
192   if (result > 0) {
193     DCHECK_GE(bytes_remaining_, static_cast<uint64>(result));
194     bytes_remaining_ -= result;
195   }
196
197   if (!callback.is_null())
198     callback.Run(result);
199   return result;
200 }
201
202 UploadFileElementReader::ScopedOverridingContentLengthForTests::
203 ScopedOverridingContentLengthForTests(uint64 value) {
204   overriding_content_length = value;
205 }
206
207 UploadFileElementReader::ScopedOverridingContentLengthForTests::
208 ~ScopedOverridingContentLengthForTests() {
209   overriding_content_length = 0;
210 }
211
212 }  // namespace net