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, 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::PlatformFileInfo 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 102 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( 120 base::TaskRunner* task_runner, 121 const base::FilePath& path, 122 uint64 range_offset, 123 uint64 range_length, 124 const base::Time& expected_modification_time) 125 : task_runner_(task_runner), 126 path_(path), 127 range_offset_(range_offset), 128 range_length_(range_length), 129 expected_modification_time_(expected_modification_time), 130 file_stream_(NULL, FileStreamDeleter(task_runner_.get())), 131 content_length_(0), 132 bytes_remaining_(0), 133 weak_ptr_factory_(this) { 134 DCHECK(task_runner_.get()); 135 } 136 137 UploadFileElementReader::~UploadFileElementReader() { 138 } 139 140 const UploadFileElementReader* UploadFileElementReader::AsFileReader() const { 141 return this; 142 } 143 144 int UploadFileElementReader::Init(const CompletionCallback& callback) { 145 DCHECK(!callback.is_null()); 146 Reset(); 147 148 ScopedFileStreamPtr* file_stream = 149 new ScopedFileStreamPtr(NULL, FileStreamDeleter(task_runner_.get())); 150 uint64* content_length = new uint64; 151 const bool posted = base::PostTaskAndReplyWithResult( 152 task_runner_.get(), 153 FROM_HERE, 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(), 163 base::Owned(file_stream), 164 base::Owned(content_length), 165 callback)); 166 DCHECK(posted); 167 return ERR_IO_PENDING; 168 } 169 170 uint64 UploadFileElementReader::GetContentLength() const { 171 if (overriding_content_length) 172 return overriding_content_length; 173 return content_length_; 174 } 175 176 uint64 UploadFileElementReader::BytesRemaining() const { 177 return bytes_remaining_; 178 } 179 180 int UploadFileElementReader::Read(IOBuffer* buf, 181 int buf_length, 182 const CompletionCallback& callback) { 183 DCHECK(!callback.is_null()); 184 185 if (BytesRemaining() == 0) 186 return 0; 187 188 // Save the value of file_stream_.get() before base::Passed() invalidates it. 189 FileStream* file_stream_ptr = file_stream_.get(); 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, 201 weak_ptr_factory_.GetWeakPtr(), 202 base::Passed(&file_stream_), 203 callback)); 204 DCHECK(posted); 205 return ERR_IO_PENDING; 206 } 207 208 void UploadFileElementReader::Reset() { 209 weak_ptr_factory_.InvalidateWeakPtrs(); 210 bytes_remaining_ = 0; 211 content_length_ = 0; 212 file_stream_.reset(); 213 } 214 215 void UploadFileElementReader::OnInitCompleted( 216 ScopedFileStreamPtr* file_stream, 217 uint64* content_length, 218 const CompletionCallback& callback, 219 int result) { 220 file_stream_.swap(*file_stream); 221 content_length_ = *content_length; 222 bytes_remaining_ = GetContentLength(); 223 if (!callback.is_null()) 224 callback.Run(result); 225 } 226 227 void UploadFileElementReader::OnReadCompleted( 228 ScopedFileStreamPtr file_stream, 229 const CompletionCallback& callback, 230 int result) { 231 file_stream_.swap(file_stream); 232 if (result > 0) { 233 DCHECK_GE(bytes_remaining_, static_cast<uint64>(result)); 234 bytes_remaining_ -= result; 235 } 236 if (!callback.is_null()) 237 callback.Run(result); 238 } 239 240 UploadFileElementReader::ScopedOverridingContentLengthForTests:: 241 ScopedOverridingContentLengthForTests(uint64 value) { 242 overriding_content_length = value; 243 } 244 245 UploadFileElementReader::ScopedOverridingContentLengthForTests:: 246 ~ScopedOverridingContentLengthForTests() { 247 overriding_content_length = 0; 248 } 249 250 UploadFileElementReaderSync::UploadFileElementReaderSync( 251 const base::FilePath& path, 252 uint64 range_offset, 253 uint64 range_length, 254 const base::Time& expected_modification_time) 255 : path_(path), 256 range_offset_(range_offset), 257 range_length_(range_length), 258 expected_modification_time_(expected_modification_time), 259 content_length_(0), 260 bytes_remaining_(0) { 261 } 262 263 UploadFileElementReaderSync::~UploadFileElementReaderSync() { 264 } 265 266 int UploadFileElementReaderSync::Init(const CompletionCallback& callback) { 267 bytes_remaining_ = 0; 268 content_length_ = 0; 269 file_stream_.reset(); 270 271 const int result = InitInternal(path_, range_offset_, range_length_, 272 expected_modification_time_, 273 &file_stream_, &content_length_); 274 bytes_remaining_ = GetContentLength(); 275 return result; 276 } 277 278 uint64 UploadFileElementReaderSync::GetContentLength() const { 279 return content_length_; 280 } 281 282 uint64 UploadFileElementReaderSync::BytesRemaining() const { 283 return bytes_remaining_; 284 } 285 286 int UploadFileElementReaderSync::Read(IOBuffer* buf, 287 int buf_length, 288 const CompletionCallback& callback) { 289 const int result = ReadInternal(buf, buf_length, BytesRemaining(), 290 file_stream_.get()); 291 if (result > 0) { 292 DCHECK_GE(bytes_remaining_, static_cast<uint64>(result)); 293 bytes_remaining_ -= result; 294 } 295 return result; 296 } 297 298 } // namespace net 299