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/threading/thread_restrictions.h" | 10 #include "base/threading/thread_restrictions.h" |
11 #include "base/threading/worker_pool.h" | 11 #include "base/threading/worker_pool.h" |
12 #include "net/base/file_stream.h" | 12 #include "net/base/file_stream.h" |
13 #include "net/base/io_buffer.h" | |
13 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
14 | 15 |
15 namespace net { | 16 namespace net { |
16 | 17 |
17 namespace { | 18 namespace { |
18 | 19 |
19 // In tests, this value is used to override the return value of | 20 // In tests, this value is used to override the return value of |
20 // UploadFileElementReader::GetContentLength() when set to non-zero. | 21 // UploadFileElementReader::GetContentLength() when set to non-zero. |
21 uint64 overriding_content_length = 0; | 22 uint64 overriding_content_length = 0; |
22 | 23 |
23 // This method is used to implement Init(). | 24 // This function is used to implement Init(). |
24 void InitInternal(const FilePath& path, | 25 void InitInternal(const FilePath& path, |
25 uint64 range_offset, | 26 uint64 range_offset, |
26 uint64 range_length, | 27 uint64 range_length, |
27 const base::Time& expected_modification_time, | 28 const base::Time& expected_modification_time, |
28 scoped_ptr<FileStream>* out_file_stream, | 29 scoped_ptr<FileStream>* out_file_stream, |
29 uint64* out_content_length, | 30 uint64* out_content_length, |
30 int* out_result) { | 31 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); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 *out_result = ERR_UPLOAD_FILE_CHANGED; |
68 return; | 69 return; |
69 } | 70 } |
70 } | 71 } |
71 | 72 |
72 *out_result = OK; | 73 *out_result = OK; |
73 } | 74 } |
74 | 75 |
76 // This function is used to implement Read(). | |
77 void ReadInternal(scoped_refptr<IOBuffer> buf, | |
78 int buf_length, | |
79 uint64 bytes_remaining, | |
80 FileStream* file_stream, | |
81 int* result) { | |
82 DCHECK_LT(0, buf_length); | |
83 | |
84 const uint64 num_bytes_to_read = | |
85 std::min(bytes_remaining, static_cast<uint64>(buf_length)); | |
86 | |
87 if (num_bytes_to_read > 0) { | |
88 int num_bytes_consumed = 0; | |
89 // file_stream is NULL if the target file is missing or not readable. | |
90 if (file_stream) { | |
91 num_bytes_consumed = file_stream->ReadSync(buf->data(), | |
92 num_bytes_to_read); | |
93 } | |
94 if (num_bytes_consumed <= 0) { | |
95 // If there's less data to read than we initially observed, then | |
96 // pad with zero. Otherwise the server will hang waiting for the | |
97 // rest of the data. | |
98 memset(buf->data(), 0, num_bytes_to_read); | |
99 } | |
100 } | |
101 *result = num_bytes_to_read; | |
102 } | |
103 | |
75 } // namespace | 104 } // namespace |
76 | 105 |
77 UploadFileElementReader::UploadFileElementReader( | 106 UploadFileElementReader::UploadFileElementReader( |
78 const FilePath& path, | 107 const FilePath& path, |
79 uint64 range_offset, | 108 uint64 range_offset, |
80 uint64 range_length, | 109 uint64 range_length, |
81 const base::Time& expected_modification_time) | 110 const base::Time& expected_modification_time) |
82 : path_(path), | 111 : path_(path), |
83 range_offset_(range_offset), | 112 range_offset_(range_offset), |
84 range_length_(range_length), | 113 range_length_(range_length), |
85 expected_modification_time_(expected_modification_time), | 114 expected_modification_time_(expected_modification_time), |
86 content_length_(0), | 115 content_length_(0), |
87 bytes_remaining_(0), | 116 bytes_remaining_(0), |
88 weak_ptr_factory_(this) { | 117 weak_ptr_factory_(this) { |
89 } | 118 } |
90 | 119 |
91 UploadFileElementReader::~UploadFileElementReader() { | 120 UploadFileElementReader::~UploadFileElementReader() { |
92 if (file_stream_.get()) { | 121 if (file_stream_.get()) { |
93 base::WorkerPool::PostTask(FROM_HERE, | 122 base::WorkerPool::PostTask(FROM_HERE, |
94 base::Bind(&base::DeletePointer<FileStream>, | 123 base::Bind(&base::DeletePointer<FileStream>, |
95 file_stream_.release()), | 124 file_stream_.release()), |
96 true /* task_is_slow */); | 125 true /* task_is_slow */); |
97 } | 126 } |
98 } | 127 } |
99 | 128 |
100 int UploadFileElementReader::Init(const CompletionCallback& callback) { | 129 int UploadFileElementReader::Init(const CompletionCallback& callback) { |
mmenke
2012/10/16 19:13:41
For future consideration: If we automatically cal
hashimoto
2012/10/17 08:04:31
I agree with you that ReadInternal() and InitInter
| |
101 scoped_ptr<FileStream>* file_stream = new scoped_ptr<FileStream>; | 130 scoped_ptr<FileStream>* file_stream = new scoped_ptr<FileStream>; |
102 uint64* content_length = new uint64; | 131 uint64* content_length = new uint64; |
103 int* result = new int; | 132 int* result = new int; |
104 const bool posted = base::WorkerPool::PostTaskAndReply( | 133 const bool posted = base::WorkerPool::PostTaskAndReply( |
105 FROM_HERE, | 134 FROM_HERE, |
106 base::Bind(&InitInternal, | 135 base::Bind(&InitInternal, |
107 path_, | 136 path_, |
108 range_offset_, | 137 range_offset_, |
109 range_length_, | 138 range_length_, |
110 expected_modification_time_, | 139 expected_modification_time_, |
(...skipping 27 matching lines...) Expand all Loading... | |
138 uint64 UploadFileElementReader::GetContentLength() const { | 167 uint64 UploadFileElementReader::GetContentLength() const { |
139 if (overriding_content_length) | 168 if (overriding_content_length) |
140 return overriding_content_length; | 169 return overriding_content_length; |
141 return content_length_; | 170 return content_length_; |
142 } | 171 } |
143 | 172 |
144 uint64 UploadFileElementReader::BytesRemaining() const { | 173 uint64 UploadFileElementReader::BytesRemaining() const { |
145 return bytes_remaining_; | 174 return bytes_remaining_; |
146 } | 175 } |
147 | 176 |
148 int UploadFileElementReader::ReadSync(char* buf, int buf_length) { | 177 int UploadFileElementReader::Read(IOBuffer* buf, |
178 int buf_length, | |
179 const CompletionCallback& callback) { | |
180 DCHECK(!callback.is_null()); | |
181 | |
182 if (BytesRemaining() == 0) | |
183 return 0; | |
184 | |
185 // Save the value of file_stream_.get() before base::Passed() invalidates it. | |
186 FileStream* file_stream_ptr = file_stream_.get(); | |
187 int* result = new int; | |
188 // Pass the ownership of file_stream_ to the worker pool to safely perform | |
189 // operation even when |this| is destructed before the read completes. | |
190 const bool posted = base::WorkerPool::PostTaskAndReply( | |
mmenke
2012/10/16 19:13:41
optional: There's a PostTaskAndReplyWithResult th
hashimoto
2012/10/17 08:04:31
Good to know, thanks.
Done.
| |
191 FROM_HERE, | |
192 base::Bind(&ReadInternal, | |
193 scoped_refptr<IOBuffer>(buf), | |
194 buf_length, | |
195 BytesRemaining(), | |
196 file_stream_ptr, | |
197 result), | |
198 base::Bind(&UploadFileElementReader::OnReadCompleted, | |
199 weak_ptr_factory_.GetWeakPtr(), | |
200 base::Passed(&file_stream_), | |
201 base::Owned(result), | |
202 callback), | |
203 true /* task_is_slow */); | |
204 DCHECK(posted); | |
205 return ERR_IO_PENDING; | |
206 } | |
207 | |
208 int UploadFileElementReader::ReadSync(IOBuffer* buf, int buf_length) { | |
149 // Temporarily allow until fix: http://crbug.com/72001. | 209 // Temporarily allow until fix: http://crbug.com/72001. |
150 base::ThreadRestrictions::ScopedAllowIO allow_io; | 210 base::ThreadRestrictions::ScopedAllowIO allow_io; |
151 DCHECK_LT(0, buf_length); | 211 int result = 0; |
152 | 212 ReadInternal(buf, buf_length, BytesRemaining(), file_stream_.get(), &result); |
153 const uint64 num_bytes_to_read = | 213 OnReadCompleted(file_stream_.Pass(), &result, CompletionCallback()); |
154 static_cast<int>(std::min(BytesRemaining(), | 214 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 } | 215 } |
175 | 216 |
176 void UploadFileElementReader::OnInitCompleted( | 217 void UploadFileElementReader::OnInitCompleted( |
177 scoped_ptr<FileStream>* file_stream, | 218 scoped_ptr<FileStream>* file_stream, |
178 uint64* content_length, | 219 uint64* content_length, |
179 int* result, | 220 int* result, |
180 const CompletionCallback& callback) { | 221 const CompletionCallback& callback) { |
181 file_stream_.swap(*file_stream); | 222 file_stream_.swap(*file_stream); |
182 content_length_ = *content_length; | 223 content_length_ = *content_length; |
183 bytes_remaining_ = GetContentLength(); | 224 bytes_remaining_ = GetContentLength(); |
184 if (!callback.is_null()) | 225 if (!callback.is_null()) |
185 callback.Run(*result); | 226 callback.Run(*result); |
186 } | 227 } |
187 | 228 |
229 void UploadFileElementReader::OnReadCompleted( | |
230 scoped_ptr<FileStream> file_stream, | |
231 int* result, | |
232 const CompletionCallback& callback) { | |
233 file_stream_.swap(file_stream); | |
234 DCHECK_GE(static_cast<int>(bytes_remaining_), *result); | |
235 bytes_remaining_ -= *result; | |
236 if (!callback.is_null()) | |
237 callback.Run(*result); | |
238 } | |
239 | |
188 UploadFileElementReader::ScopedOverridingContentLengthForTests:: | 240 UploadFileElementReader::ScopedOverridingContentLengthForTests:: |
189 ScopedOverridingContentLengthForTests(uint64 value) { | 241 ScopedOverridingContentLengthForTests(uint64 value) { |
190 overriding_content_length = value; | 242 overriding_content_length = value; |
191 } | 243 } |
192 | 244 |
193 UploadFileElementReader::ScopedOverridingContentLengthForTests:: | 245 UploadFileElementReader::ScopedOverridingContentLengthForTests:: |
194 ~ScopedOverridingContentLengthForTests() { | 246 ~ScopedOverridingContentLengthForTests() { |
195 overriding_content_length = 0; | 247 overriding_content_length = 0; |
196 } | 248 } |
197 | 249 |
198 } // namespace net | 250 } // namespace net |
OLD | NEW |