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 |