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

Side by Side Diff: net/base/upload_file_element_reader.cc

Issue 139253002: net: Use FileStream asynchronously from UploadFileElementReader (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: remove const Created 6 years, 11 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 | « net/base/upload_file_element_reader.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/base/upload_file_element_reader.h" 5 #include "net/base/upload_file_element_reader.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/file_util.h" 8 #include "base/file_util.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/task_runner_util.h" 10 #include "base/task_runner_util.h"
11 #include "net/base/file_stream.h" 11 #include "net/base/file_stream.h"
12 #include "net/base/io_buffer.h" 12 #include "net/base/io_buffer.h"
13 #include "net/base/net_errors.h" 13 #include "net/base/net_errors.h"
14 14
15 namespace net { 15 namespace net {
16 16
17 namespace { 17 namespace {
18 18
19 // In tests, this value is used to override the return value of 19 // In tests, this value is used to override the return value of
20 // UploadFileElementReader::GetContentLength() when set to non-zero. 20 // UploadFileElementReader::GetContentLength() when set to non-zero.
21 uint64 overriding_content_length = 0; 21 uint64 overriding_content_length = 0;
22 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, the upload should fail.
36 DLOG(WARNING) << "Failed to open \"" << path.value()
37 << "\" for reading: " << rv;
38 return rv;
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 return rv;
45 }
46 }
47
48 int64 length = 0;
49 if (!base::GetFileSize(path, &length)) {
50 DLOG(WARNING) << "Failed to get file size of \"" << path.value() << "\"";
51 return ERR_FILE_NOT_FOUND;
52 }
53
54 if (range_offset < static_cast<uint64>(length)) {
55 // Compensate for the offset.
56 length = std::min(length - range_offset, range_length);
57 }
58
59 // If the underlying file has been changed and the expected file modification
60 // time is set, treat it as error. Note that the expected modification time
61 // from WebKit is based on time_t precision. So we have to convert both to
62 // time_t to compare. This check is used for sliced files.
63 if (!expected_modification_time.is_null()) {
64 base::File::Info info;
65 if (!base::GetFileInfo(path, &info)) {
66 DLOG(WARNING) << "Failed to get file info of \"" << path.value() << "\"";
67 return ERR_FILE_NOT_FOUND;
68 }
69
70 if (expected_modification_time.ToTimeT() != info.last_modified.ToTimeT()) {
71 return ERR_UPLOAD_FILE_CHANGED;
72 }
73 }
74
75 *out_content_length = length;
76 out_file_stream->reset(file_stream.release());
77
78 return OK;
79 }
80
81 // This function is used to implement Read().
82 int ReadInternal(scoped_refptr<IOBuffer> buf,
83 int buf_length,
84 uint64 bytes_remaining,
85 FileStream* file_stream) {
86 DCHECK_LT(0, buf_length);
87
88 const uint64 num_bytes_to_read =
89 std::min(bytes_remaining, static_cast<uint64>(buf_length));
90
91 int result = 0;
92 if (num_bytes_to_read > 0) {
93 DCHECK(file_stream); // file_stream is non-null if content_length_ > 0.
94 result = file_stream->ReadSync(buf->data(), num_bytes_to_read);
95 if (result == 0) // Reached end-of-file earlier than expected.
96 result = ERR_UPLOAD_FILE_CHANGED;
97 }
98 return result;
99 }
100
101 } // namespace 23 } // namespace
102 24
103 UploadFileElementReader::FileStreamDeleter::FileStreamDeleter(
104 base::TaskRunner* task_runner) : task_runner_(task_runner) {
105 DCHECK(task_runner_.get());
106 }
107
108 UploadFileElementReader::FileStreamDeleter::~FileStreamDeleter() {}
109
110 void UploadFileElementReader::FileStreamDeleter::operator() (
111 FileStream* file_stream) const {
112 if (file_stream) {
113 task_runner_->PostTask(FROM_HERE,
114 base::Bind(&base::DeletePointer<FileStream>,
115 file_stream));
116 }
117 }
118
119 UploadFileElementReader::UploadFileElementReader( 25 UploadFileElementReader::UploadFileElementReader(
120 base::TaskRunner* task_runner, 26 base::TaskRunner* task_runner,
121 const base::FilePath& path, 27 const base::FilePath& path,
122 uint64 range_offset, 28 uint64 range_offset,
123 uint64 range_length, 29 uint64 range_length,
124 const base::Time& expected_modification_time) 30 const base::Time& expected_modification_time)
125 : task_runner_(task_runner), 31 : task_runner_(task_runner),
126 path_(path), 32 path_(path),
127 range_offset_(range_offset), 33 range_offset_(range_offset),
128 range_length_(range_length), 34 range_length_(range_length),
129 expected_modification_time_(expected_modification_time), 35 expected_modification_time_(expected_modification_time),
130 file_stream_(NULL, FileStreamDeleter(task_runner_.get())),
131 content_length_(0), 36 content_length_(0),
132 bytes_remaining_(0), 37 bytes_remaining_(0),
133 weak_ptr_factory_(this) { 38 weak_ptr_factory_(this) {
134 DCHECK(task_runner_.get()); 39 DCHECK(task_runner_.get());
135 } 40 }
136 41
137 UploadFileElementReader::~UploadFileElementReader() { 42 UploadFileElementReader::~UploadFileElementReader() {
138 } 43 }
139 44
140 const UploadFileElementReader* UploadFileElementReader::AsFileReader() const { 45 const UploadFileElementReader* UploadFileElementReader::AsFileReader() const {
141 return this; 46 return this;
142 } 47 }
143 48
144 int UploadFileElementReader::Init(const CompletionCallback& callback) { 49 int UploadFileElementReader::Init(const CompletionCallback& callback) {
145 DCHECK(!callback.is_null()); 50 DCHECK(!callback.is_null());
146 Reset(); 51 Reset();
147 52
148 ScopedFileStreamPtr* file_stream = 53 file_stream_.reset(new FileStream(NULL, task_runner_.get()));
149 new ScopedFileStreamPtr(NULL, FileStreamDeleter(task_runner_.get())); 54 int result = file_stream_->Open(
150 uint64* content_length = new uint64; 55 path_,
151 const bool posted = base::PostTaskAndReplyWithResult( 56 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ |
152 task_runner_.get(), 57 base::PLATFORM_FILE_ASYNC,
153 FROM_HERE, 58 base::Bind(&UploadFileElementReader::OnOpenCompleted,
154 base::Bind(&InitInternal<FileStreamDeleter>,
155 path_,
156 range_offset_,
157 range_length_,
158 expected_modification_time_,
159 file_stream,
160 content_length),
161 base::Bind(&UploadFileElementReader::OnInitCompleted,
162 weak_ptr_factory_.GetWeakPtr(), 59 weak_ptr_factory_.GetWeakPtr(),
163 base::Owned(file_stream),
164 base::Owned(content_length),
165 callback)); 60 callback));
166 DCHECK(posted); 61 DCHECK_GT(0, result);
167 return ERR_IO_PENDING; 62 return result;
168 } 63 }
169 64
170 uint64 UploadFileElementReader::GetContentLength() const { 65 uint64 UploadFileElementReader::GetContentLength() const {
171 if (overriding_content_length) 66 if (overriding_content_length)
172 return overriding_content_length; 67 return overriding_content_length;
173 return content_length_; 68 return content_length_;
174 } 69 }
175 70
176 uint64 UploadFileElementReader::BytesRemaining() const { 71 uint64 UploadFileElementReader::BytesRemaining() const {
177 return bytes_remaining_; 72 return bytes_remaining_;
178 } 73 }
179 74
180 int UploadFileElementReader::Read(IOBuffer* buf, 75 int UploadFileElementReader::Read(IOBuffer* buf,
181 int buf_length, 76 int buf_length,
182 const CompletionCallback& callback) { 77 const CompletionCallback& callback) {
183 DCHECK(!callback.is_null()); 78 DCHECK(!callback.is_null());
184 79
185 if (BytesRemaining() == 0) 80 uint64 num_bytes_to_read =
81 std::min(BytesRemaining(), static_cast<uint64>(buf_length));
82 if (num_bytes_to_read == 0)
186 return 0; 83 return 0;
187 84
188 // Save the value of file_stream_.get() before base::Passed() invalidates it. 85 int result = file_stream_->Read(
189 FileStream* file_stream_ptr = file_stream_.get(); 86 buf, num_bytes_to_read,
190 // Pass the ownership of file_stream_ to the worker pool to safely perform
191 // operation even when |this| is destructed before the read completes.
192 const bool posted = base::PostTaskAndReplyWithResult(
193 task_runner_.get(),
194 FROM_HERE,
195 base::Bind(&ReadInternal,
196 scoped_refptr<IOBuffer>(buf),
197 buf_length,
198 BytesRemaining(),
199 file_stream_ptr),
200 base::Bind(&UploadFileElementReader::OnReadCompleted, 87 base::Bind(&UploadFileElementReader::OnReadCompleted,
201 weak_ptr_factory_.GetWeakPtr(), 88 weak_ptr_factory_.GetWeakPtr(),
202 base::Passed(&file_stream_),
203 callback)); 89 callback));
204 DCHECK(posted); 90 DCHECK_GT(0, result);
205 return ERR_IO_PENDING; 91 return result;
206 } 92 }
207 93
208 void UploadFileElementReader::Reset() { 94 void UploadFileElementReader::Reset() {
209 weak_ptr_factory_.InvalidateWeakPtrs(); 95 weak_ptr_factory_.InvalidateWeakPtrs();
210 bytes_remaining_ = 0; 96 bytes_remaining_ = 0;
211 content_length_ = 0; 97 content_length_ = 0;
212 file_stream_.reset(); 98 file_stream_.reset();
213 } 99 }
214 100
215 void UploadFileElementReader::OnInitCompleted( 101 void UploadFileElementReader::OnOpenCompleted(
216 ScopedFileStreamPtr* file_stream,
217 uint64* content_length,
218 const CompletionCallback& callback, 102 const CompletionCallback& callback,
219 int result) { 103 int result) {
220 file_stream_.swap(*file_stream); 104 DCHECK(!callback.is_null());
221 content_length_ = *content_length; 105
106 if (result < 0) {
107 DLOG(WARNING) << "Failed to open \"" << path_.value()
108 << "\" for reading: " << result;
109 callback.Run(result);
110 return;
111 }
112
113 if (range_offset_) {
114 int result = file_stream_->Seek(
115 FROM_BEGIN, range_offset_,
116 base::Bind(&UploadFileElementReader::OnSeekCompleted,
117 weak_ptr_factory_.GetWeakPtr(),
118 callback));
119 DCHECK_GT(0, result);
120 if (result != ERR_IO_PENDING)
121 callback.Run(result);
122 } else {
123 OnSeekCompleted(callback, OK);
124 }
125 }
126
127 void UploadFileElementReader::OnSeekCompleted(
128 const CompletionCallback& callback,
129 int64 result) {
130 DCHECK(!callback.is_null());
131
132 if (result < 0) {
133 DLOG(WARNING) << "Failed to seek \"" << path_.value()
134 << "\" to offset: " << range_offset_ << " (" << result << ")";
135 callback.Run(result);
136 return;
137 }
138
139 base::File::Info* file_info = new base::File::Info;
140 bool posted = base::PostTaskAndReplyWithResult(
141 task_runner_,
142 FROM_HERE,
143 base::Bind(&base::GetFileInfo,
144 path_,
145 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;
222 bytes_remaining_ = GetContentLength(); 182 bytes_remaining_ = GetContentLength();
223 if (!callback.is_null()) 183 callback.Run(OK);
224 callback.Run(result);
225 } 184 }
226 185
227 void UploadFileElementReader::OnReadCompleted( 186 void UploadFileElementReader::OnReadCompleted(
228 ScopedFileStreamPtr file_stream,
229 const CompletionCallback& callback, 187 const CompletionCallback& callback,
230 int result) { 188 int result) {
231 file_stream_.swap(file_stream); 189 DCHECK(!callback.is_null());
190
191 if (result == 0) // Reached end-of-file earlier than expected.
192 result = ERR_UPLOAD_FILE_CHANGED;
193
232 if (result > 0) { 194 if (result > 0) {
233 DCHECK_GE(bytes_remaining_, static_cast<uint64>(result)); 195 DCHECK_GE(bytes_remaining_, static_cast<uint64>(result));
234 bytes_remaining_ -= result; 196 bytes_remaining_ -= result;
235 } 197 }
236 if (!callback.is_null()) 198 callback.Run(result);
237 callback.Run(result);
238 } 199 }
239 200
240 UploadFileElementReader::ScopedOverridingContentLengthForTests:: 201 UploadFileElementReader::ScopedOverridingContentLengthForTests::
241 ScopedOverridingContentLengthForTests(uint64 value) { 202 ScopedOverridingContentLengthForTests(uint64 value) {
242 overriding_content_length = value; 203 overriding_content_length = value;
243 } 204 }
244 205
245 UploadFileElementReader::ScopedOverridingContentLengthForTests:: 206 UploadFileElementReader::ScopedOverridingContentLengthForTests::
246 ~ScopedOverridingContentLengthForTests() { 207 ~ScopedOverridingContentLengthForTests() {
247 overriding_content_length = 0; 208 overriding_content_length = 0;
248 } 209 }
249 210
250 } // namespace net 211 } // namespace net
OLDNEW
« no previous file with comments | « net/base/upload_file_element_reader.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698