| OLD | NEW |
| 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/threading/thread_restrictions.h" | 11 #include "base/threading/thread_restrictions.h" |
| 11 #include "base/threading/worker_pool.h" | 12 #include "base/threading/worker_pool.h" |
| 12 #include "net/base/file_stream.h" | 13 #include "net/base/file_stream.h" |
| 14 #include "net/base/io_buffer.h" |
| 13 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
| 14 | 16 |
| 15 namespace net { | 17 namespace net { |
| 16 | 18 |
| 17 namespace { | 19 namespace { |
| 18 | 20 |
| 19 // In tests, this value is used to override the return value of | 21 // In tests, this value is used to override the return value of |
| 20 // UploadFileElementReader::GetContentLength() when set to non-zero. | 22 // UploadFileElementReader::GetContentLength() when set to non-zero. |
| 21 uint64 overriding_content_length = 0; | 23 uint64 overriding_content_length = 0; |
| 22 | 24 |
| 23 // This method is used to implement Init(). | 25 // This function is used to implement Init(). |
| 24 void InitInternal(const FilePath& path, | 26 int InitInternal(const FilePath& path, |
| 25 uint64 range_offset, | 27 uint64 range_offset, |
| 26 uint64 range_length, | 28 uint64 range_length, |
| 27 const base::Time& expected_modification_time, | 29 const base::Time& expected_modification_time, |
| 28 scoped_ptr<FileStream>* out_file_stream, | 30 scoped_ptr<FileStream>* out_file_stream, |
| 29 uint64* out_content_length, | 31 uint64* out_content_length) { |
| 30 int* out_result) { | |
| 31 scoped_ptr<FileStream> file_stream(new FileStream(NULL)); | 32 scoped_ptr<FileStream> file_stream(new FileStream(NULL)); |
| 32 int64 rv = file_stream->OpenSync( | 33 int64 rv = file_stream->OpenSync( |
| 33 path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ); | 34 path, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ); |
| 34 if (rv != OK) { | 35 if (rv != OK) { |
| 35 // If the file can't be opened, we'll just upload an empty file. | 36 // If the file can't be opened, we'll just upload an empty file. |
| 36 DLOG(WARNING) << "Failed to open \"" << path.value() | 37 DLOG(WARNING) << "Failed to open \"" << path.value() |
| 37 << "\" for reading: " << rv; | 38 << "\" for reading: " << rv; |
| 38 file_stream.reset(); | 39 file_stream.reset(); |
| 39 } else if (range_offset) { | 40 } else if (range_offset) { |
| 40 rv = file_stream->SeekSync(FROM_BEGIN, range_offset); | 41 rv = file_stream->SeekSync(FROM_BEGIN, range_offset); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 57 out_file_stream->swap(file_stream); | 58 out_file_stream->swap(file_stream); |
| 58 | 59 |
| 59 // If the underlying file has been changed and the expected file modification | 60 // 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 // 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 // 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 // time_t to compare. This check is used for sliced files. |
| 63 if (!expected_modification_time.is_null()) { | 64 if (!expected_modification_time.is_null()) { |
| 64 base::PlatformFileInfo info; | 65 base::PlatformFileInfo info; |
| 65 if (file_util::GetFileInfo(path, &info) && | 66 if (file_util::GetFileInfo(path, &info) && |
| 66 expected_modification_time.ToTimeT() != info.last_modified.ToTimeT()) { | 67 expected_modification_time.ToTimeT() != info.last_modified.ToTimeT()) { |
| 67 *out_result = ERR_UPLOAD_FILE_CHANGED; | 68 return ERR_UPLOAD_FILE_CHANGED; |
| 68 return; | |
| 69 } | 69 } |
| 70 } | 70 } |
| 71 | 71 |
| 72 *out_result = OK; | 72 return OK; |
| 73 } |
| 74 |
| 75 // This function is used to implement Read(). |
| 76 int ReadInternal(scoped_refptr<IOBuffer> buf, |
| 77 int buf_length, |
| 78 uint64 bytes_remaining, |
| 79 FileStream* file_stream) { |
| 80 DCHECK_LT(0, buf_length); |
| 81 |
| 82 const uint64 num_bytes_to_read = |
| 83 std::min(bytes_remaining, static_cast<uint64>(buf_length)); |
| 84 |
| 85 if (num_bytes_to_read > 0) { |
| 86 int num_bytes_consumed = 0; |
| 87 // file_stream is NULL if the target file is missing or not readable. |
| 88 if (file_stream) { |
| 89 num_bytes_consumed = file_stream->ReadSync(buf->data(), |
| 90 num_bytes_to_read); |
| 91 } |
| 92 if (num_bytes_consumed <= 0) { |
| 93 // If there's less data to read than we initially observed, then |
| 94 // pad with zero. Otherwise the server will hang waiting for the |
| 95 // rest of the data. |
| 96 memset(buf->data(), 0, num_bytes_to_read); |
| 97 } |
| 98 } |
| 99 return num_bytes_to_read; |
| 73 } | 100 } |
| 74 | 101 |
| 75 } // namespace | 102 } // namespace |
| 76 | 103 |
| 77 UploadFileElementReader::UploadFileElementReader( | 104 UploadFileElementReader::UploadFileElementReader( |
| 78 const FilePath& path, | 105 const FilePath& path, |
| 79 uint64 range_offset, | 106 uint64 range_offset, |
| 80 uint64 range_length, | 107 uint64 range_length, |
| 81 const base::Time& expected_modification_time) | 108 const base::Time& expected_modification_time) |
| 82 : path_(path), | 109 : path_(path), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 93 base::WorkerPool::PostTask(FROM_HERE, | 120 base::WorkerPool::PostTask(FROM_HERE, |
| 94 base::Bind(&base::DeletePointer<FileStream>, | 121 base::Bind(&base::DeletePointer<FileStream>, |
| 95 file_stream_.release()), | 122 file_stream_.release()), |
| 96 true /* task_is_slow */); | 123 true /* task_is_slow */); |
| 97 } | 124 } |
| 98 } | 125 } |
| 99 | 126 |
| 100 int UploadFileElementReader::Init(const CompletionCallback& callback) { | 127 int UploadFileElementReader::Init(const CompletionCallback& callback) { |
| 101 scoped_ptr<FileStream>* file_stream = new scoped_ptr<FileStream>; | 128 scoped_ptr<FileStream>* file_stream = new scoped_ptr<FileStream>; |
| 102 uint64* content_length = new uint64; | 129 uint64* content_length = new uint64; |
| 103 int* result = new int; | 130 const bool posted = base::PostTaskAndReplyWithResult( |
| 104 const bool posted = base::WorkerPool::PostTaskAndReply( | 131 base::WorkerPool::GetTaskRunner(true /* task_is_slow */), |
| 105 FROM_HERE, | 132 FROM_HERE, |
| 106 base::Bind(&InitInternal, | 133 base::Bind(&InitInternal, |
| 107 path_, | 134 path_, |
| 108 range_offset_, | 135 range_offset_, |
| 109 range_length_, | 136 range_length_, |
| 110 expected_modification_time_, | 137 expected_modification_time_, |
| 111 file_stream, | 138 file_stream, |
| 112 content_length, | 139 content_length), |
| 113 result), | |
| 114 base::Bind(&UploadFileElementReader::OnInitCompleted, | 140 base::Bind(&UploadFileElementReader::OnInitCompleted, |
| 115 weak_ptr_factory_.GetWeakPtr(), | 141 weak_ptr_factory_.GetWeakPtr(), |
| 116 base::Owned(file_stream), | 142 base::Owned(file_stream), |
| 117 base::Owned(content_length), | 143 base::Owned(content_length), |
| 118 base::Owned(result), | 144 callback)); |
| 119 callback), | |
| 120 true /* task_is_slow */); | |
| 121 DCHECK(posted); | 145 DCHECK(posted); |
| 122 return ERR_IO_PENDING; | 146 return ERR_IO_PENDING; |
| 123 } | 147 } |
| 124 | 148 |
| 125 int UploadFileElementReader::InitSync() { | 149 int UploadFileElementReader::InitSync() { |
| 126 // Temporarily allow until fix: http://crbug.com/72001. | 150 // Temporarily allow until fix: http://crbug.com/72001. |
| 127 base::ThreadRestrictions::ScopedAllowIO allow_io; | 151 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 128 | 152 |
| 129 scoped_ptr<FileStream> file_stream; | 153 scoped_ptr<FileStream> file_stream; |
| 130 uint64 content_length = 0; | 154 uint64 content_length = 0; |
| 131 int result = OK; | 155 const int result = InitInternal(path_, range_offset_, range_length_, |
| 132 InitInternal(path_, range_offset_, range_length_, expected_modification_time_, | 156 expected_modification_time_, |
| 133 &file_stream, &content_length, &result); | 157 &file_stream, &content_length); |
| 134 OnInitCompleted(&file_stream, &content_length, &result, CompletionCallback()); | 158 OnInitCompleted(&file_stream, &content_length, CompletionCallback(), result); |
| 135 return result; | 159 return result; |
| 136 } | 160 } |
| 137 | 161 |
| 138 uint64 UploadFileElementReader::GetContentLength() const { | 162 uint64 UploadFileElementReader::GetContentLength() const { |
| 139 if (overriding_content_length) | 163 if (overriding_content_length) |
| 140 return overriding_content_length; | 164 return overriding_content_length; |
| 141 return content_length_; | 165 return content_length_; |
| 142 } | 166 } |
| 143 | 167 |
| 144 uint64 UploadFileElementReader::BytesRemaining() const { | 168 uint64 UploadFileElementReader::BytesRemaining() const { |
| 145 return bytes_remaining_; | 169 return bytes_remaining_; |
| 146 } | 170 } |
| 147 | 171 |
| 148 int UploadFileElementReader::ReadSync(char* buf, int buf_length) { | 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 base::WorkerPool::GetTaskRunner(true /* task_is_slow */), |
| 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 int UploadFileElementReader::ReadSync(IOBuffer* buf, int buf_length) { |
| 149 // Temporarily allow until fix: http://crbug.com/72001. | 201 // Temporarily allow until fix: http://crbug.com/72001. |
| 150 base::ThreadRestrictions::ScopedAllowIO allow_io; | 202 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 151 DCHECK_LT(0, buf_length); | 203 const int result = ReadInternal(buf, buf_length, BytesRemaining(), |
| 152 | 204 file_stream_.get()); |
| 153 const uint64 num_bytes_to_read = | 205 OnReadCompleted(file_stream_.Pass(), CompletionCallback(), result); |
| 154 static_cast<int>(std::min(BytesRemaining(), | 206 return result; |
| 155 static_cast<uint64>(buf_length))); | |
| 156 if (num_bytes_to_read > 0) { | |
| 157 int num_bytes_consumed = 0; | |
| 158 // file_stream_ is NULL if the target file is | |
| 159 // missing or not readable. | |
| 160 if (file_stream_.get()) { | |
| 161 num_bytes_consumed = | |
| 162 file_stream_->ReadSync(buf, num_bytes_to_read); | |
| 163 } | |
| 164 if (num_bytes_consumed <= 0) { | |
| 165 // If there's less data to read than we initially observed, then | |
| 166 // pad with zero. Otherwise the server will hang waiting for the | |
| 167 // rest of the data. | |
| 168 memset(buf, 0, num_bytes_to_read); | |
| 169 } | |
| 170 } | |
| 171 DCHECK_GE(bytes_remaining_, num_bytes_to_read); | |
| 172 bytes_remaining_ -= num_bytes_to_read; | |
| 173 return num_bytes_to_read; | |
| 174 } | 207 } |
| 175 | 208 |
| 176 void UploadFileElementReader::OnInitCompleted( | 209 void UploadFileElementReader::OnInitCompleted( |
| 177 scoped_ptr<FileStream>* file_stream, | 210 scoped_ptr<FileStream>* file_stream, |
| 178 uint64* content_length, | 211 uint64* content_length, |
| 179 int* result, | 212 const CompletionCallback& callback, |
| 180 const CompletionCallback& callback) { | 213 int result) { |
| 181 file_stream_.swap(*file_stream); | 214 file_stream_.swap(*file_stream); |
| 182 content_length_ = *content_length; | 215 content_length_ = *content_length; |
| 183 bytes_remaining_ = GetContentLength(); | 216 bytes_remaining_ = GetContentLength(); |
| 184 if (!callback.is_null()) | 217 if (!callback.is_null()) |
| 185 callback.Run(*result); | 218 callback.Run(result); |
| 219 } |
| 220 |
| 221 void UploadFileElementReader::OnReadCompleted( |
| 222 scoped_ptr<FileStream> file_stream, |
| 223 const CompletionCallback& callback, |
| 224 int result) { |
| 225 file_stream_.swap(file_stream); |
| 226 DCHECK_GE(static_cast<int>(bytes_remaining_), result); |
| 227 bytes_remaining_ -= result; |
| 228 if (!callback.is_null()) |
| 229 callback.Run(result); |
| 186 } | 230 } |
| 187 | 231 |
| 188 UploadFileElementReader::ScopedOverridingContentLengthForTests:: | 232 UploadFileElementReader::ScopedOverridingContentLengthForTests:: |
| 189 ScopedOverridingContentLengthForTests(uint64 value) { | 233 ScopedOverridingContentLengthForTests(uint64 value) { |
| 190 overriding_content_length = value; | 234 overriding_content_length = value; |
| 191 } | 235 } |
| 192 | 236 |
| 193 UploadFileElementReader::ScopedOverridingContentLengthForTests:: | 237 UploadFileElementReader::ScopedOverridingContentLengthForTests:: |
| 194 ~ScopedOverridingContentLengthForTests() { | 238 ~ScopedOverridingContentLengthForTests() { |
| 195 overriding_content_length = 0; | 239 overriding_content_length = 0; |
| 196 } | 240 } |
| 197 | 241 |
| 198 } // namespace net | 242 } // namespace net |
| OLD | NEW |