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 "net/base/upload_file_element_reader.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"
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;
23 // This function is used to implement Init().
24 template<typename FileStreamDeleter
>
25 int InitInternal(const base::FilePath
& path
,
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
);
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
;
39 } else if (range_offset
) {
40 rv
= file_stream
->SeekSync(FROM_BEGIN
, range_offset
);
42 DLOG(WARNING
) << "Failed to seek \"" << path
.value()
43 << "\" to offset: " << range_offset
<< " (" << rv
<< ")";
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
);
55 *out_content_length
= length
;
56 out_file_stream
->reset(file_stream
.release());
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
;
73 // This function is used to implement Read().
74 int ReadInternal(scoped_refptr
<IOBuffer
> buf
,
76 uint64 bytes_remaining
,
77 FileStream
* file_stream
) {
78 DCHECK_LT(0, buf_length
);
80 const uint64 num_bytes_to_read
=
81 std::min(bytes_remaining
, static_cast<uint64
>(buf_length
));
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
;
95 UploadFileElementReader::FileStreamDeleter::FileStreamDeleter(
96 base::TaskRunner
* task_runner
) : task_runner_(task_runner
) {
97 DCHECK(task_runner_
.get());
100 UploadFileElementReader::FileStreamDeleter::~FileStreamDeleter() {}
102 void UploadFileElementReader::FileStreamDeleter::operator() (
103 FileStream
* file_stream
) const {
105 task_runner_
->PostTask(FROM_HERE
,
106 base::Bind(&base::DeletePointer
<FileStream
>,
111 UploadFileElementReader::UploadFileElementReader(
112 base::TaskRunner
* task_runner
,
113 const base::FilePath
& path
,
116 const base::Time
& expected_modification_time
)
117 : task_runner_(task_runner
),
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())),
125 weak_ptr_factory_(this) {
126 DCHECK(task_runner_
.get());
129 UploadFileElementReader::~UploadFileElementReader() {
132 const UploadFileElementReader
* UploadFileElementReader::AsFileReader() const {
136 int UploadFileElementReader::Init(const CompletionCallback
& callback
) {
137 DCHECK(!callback
.is_null());
140 ScopedFileStreamPtr
* file_stream
=
141 new ScopedFileStreamPtr(NULL
, FileStreamDeleter(task_runner_
.get()));
142 uint64
* content_length
= new uint64
;
143 const bool posted
= base::PostTaskAndReplyWithResult(
146 base::Bind(&InitInternal
<FileStreamDeleter
>,
150 expected_modification_time_
,
153 base::Bind(&UploadFileElementReader::OnInitCompleted
,
154 weak_ptr_factory_
.GetWeakPtr(),
155 base::Owned(file_stream
),
156 base::Owned(content_length
),
159 return ERR_IO_PENDING
;
162 uint64
UploadFileElementReader::GetContentLength() const {
163 if (overriding_content_length
)
164 return overriding_content_length
;
165 return content_length_
;
168 uint64
UploadFileElementReader::BytesRemaining() const {
169 return bytes_remaining_
;
172 int UploadFileElementReader::Read(IOBuffer
* buf
,
174 const CompletionCallback
& callback
) {
175 DCHECK(!callback
.is_null());
177 if (BytesRemaining() == 0)
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(
187 base::Bind(&ReadInternal
,
188 scoped_refptr
<IOBuffer
>(buf
),
192 base::Bind(&UploadFileElementReader::OnReadCompleted
,
193 weak_ptr_factory_
.GetWeakPtr(),
194 base::Passed(&file_stream_
),
197 return ERR_IO_PENDING
;
200 void UploadFileElementReader::Reset() {
201 weak_ptr_factory_
.InvalidateWeakPtrs();
202 bytes_remaining_
= 0;
204 file_stream_
.reset();
207 void UploadFileElementReader::OnInitCompleted(
208 ScopedFileStreamPtr
* file_stream
,
209 uint64
* content_length
,
210 const CompletionCallback
& callback
,
212 file_stream_
.swap(*file_stream
);
213 content_length_
= *content_length
;
214 bytes_remaining_
= GetContentLength();
215 if (!callback
.is_null())
216 callback
.Run(result
);
219 void UploadFileElementReader::OnReadCompleted(
220 ScopedFileStreamPtr file_stream
,
221 const CompletionCallback
& callback
,
223 file_stream_
.swap(file_stream
);
225 DCHECK_GE(bytes_remaining_
, static_cast<uint64
>(result
));
226 bytes_remaining_
-= result
;
228 if (!callback
.is_null())
229 callback
.Run(result
);
232 UploadFileElementReader::ScopedOverridingContentLengthForTests::
233 ScopedOverridingContentLengthForTests(uint64 value
) {
234 overriding_content_length
= value
;
237 UploadFileElementReader::ScopedOverridingContentLengthForTests::
238 ~ScopedOverridingContentLengthForTests() {
239 overriding_content_length
= 0;
242 UploadFileElementReaderSync::UploadFileElementReaderSync(
243 const base::FilePath
& path
,
246 const base::Time
& expected_modification_time
)
248 range_offset_(range_offset
),
249 range_length_(range_length
),
250 expected_modification_time_(expected_modification_time
),
252 bytes_remaining_(0) {
255 UploadFileElementReaderSync::~UploadFileElementReaderSync() {
258 int UploadFileElementReaderSync::Init(const CompletionCallback
& callback
) {
259 bytes_remaining_
= 0;
261 file_stream_
.reset();
263 const int result
= InitInternal(path_
, range_offset_
, range_length_
,
264 expected_modification_time_
,
265 &file_stream_
, &content_length_
);
266 bytes_remaining_
= GetContentLength();
270 uint64
UploadFileElementReaderSync::GetContentLength() const {
271 return content_length_
;
274 uint64
UploadFileElementReaderSync::BytesRemaining() const {
275 return bytes_remaining_
;
278 int UploadFileElementReaderSync::Read(IOBuffer
* buf
,
280 const CompletionCallback
& callback
) {
281 const int result
= ReadInternal(buf
, buf_length
, BytesRemaining(),
284 DCHECK_GE(bytes_remaining_
, static_cast<uint64
>(result
));
285 bytes_remaining_
-= result
;