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 "webkit/fileapi/file_writer_delegate.h" | 5 #include "webkit/fileapi/file_writer_delegate.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/file_util_proxy.h" | 9 #include "base/file_util_proxy.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
(...skipping 14 matching lines...) Expand all Loading... |
25 namespace { | 25 namespace { |
26 | 26 |
27 typedef base::Callback<void(base::PlatformFileError /* error code */, | 27 typedef base::Callback<void(base::PlatformFileError /* error code */, |
28 const base::PlatformFileInfo& /* file_info */)> | 28 const base::PlatformFileInfo& /* file_info */)> |
29 InitializeTaskCallback; | 29 InitializeTaskCallback; |
30 | 30 |
31 class InitializeTask : public base::RefCountedThreadSafe<InitializeTask> { | 31 class InitializeTask : public base::RefCountedThreadSafe<InitializeTask> { |
32 public: | 32 public: |
33 InitializeTask( | 33 InitializeTask( |
34 base::PlatformFile file, | 34 base::PlatformFile file, |
35 const FileSystemPath& path, | |
36 FileSystemOperationContext* context, | |
37 const InitializeTaskCallback& callback) | 35 const InitializeTaskCallback& callback) |
38 : original_loop_(base::MessageLoopProxy::current()), | 36 : original_loop_(base::MessageLoopProxy::current()), |
39 error_code_(base::PLATFORM_FILE_OK), | 37 error_code_(base::PLATFORM_FILE_OK), |
40 file_(file), | 38 file_(file), |
41 path_(path), | |
42 context_(*context), | |
43 callback_(callback) { | 39 callback_(callback) { |
44 DCHECK_EQ(false, callback.is_null()); | 40 DCHECK_EQ(false, callback.is_null()); |
45 } | 41 } |
46 | 42 |
47 bool Start(base::SequencedTaskRunner* task_runner, | 43 bool Start(base::SequencedTaskRunner* task_runner, |
48 const tracked_objects::Location& from_here) { | 44 const tracked_objects::Location& from_here) { |
49 return task_runner->PostTask( | 45 return task_runner->PostTask( |
50 from_here, | 46 from_here, |
51 base::Bind(&InitializeTask::ProcessOnTargetThread, this)); | 47 base::Bind(&InitializeTask::ProcessOnTargetThread, this)); |
52 } | 48 } |
53 | 49 |
54 private: | 50 private: |
55 friend class base::RefCountedThreadSafe<InitializeTask>; | 51 friend class base::RefCountedThreadSafe<InitializeTask>; |
56 ~InitializeTask() {} | 52 ~InitializeTask() {} |
57 | 53 |
58 void RunCallback() { | 54 void RunCallback() { |
59 callback_.Run(error_code_, file_info_); | 55 callback_.Run(error_code_, file_info_); |
60 } | 56 } |
61 | 57 |
62 void ProcessOnTargetThread() { | 58 void ProcessOnTargetThread() { |
63 DCHECK(context_.file_system_context()); | |
64 FileSystemQuotaUtil* quota_util = context_.file_system_context()-> | |
65 GetQuotaUtil(path_.type()); | |
66 if (quota_util) { | |
67 DCHECK(quota_util->proxy()); | |
68 quota_util->proxy()->StartUpdateOrigin(path_.origin(), path_.type()); | |
69 } | |
70 if (!base::GetPlatformFileInfo(file_, &file_info_)) | 59 if (!base::GetPlatformFileInfo(file_, &file_info_)) |
71 error_code_ = base::PLATFORM_FILE_ERROR_FAILED; | 60 error_code_ = base::PLATFORM_FILE_ERROR_FAILED; |
72 original_loop_->PostTask( | 61 original_loop_->PostTask( |
73 FROM_HERE, | 62 FROM_HERE, |
74 base::Bind(&InitializeTask::RunCallback, this)); | 63 base::Bind(&InitializeTask::RunCallback, this)); |
75 } | 64 } |
76 | 65 |
77 scoped_refptr<base::MessageLoopProxy> original_loop_; | 66 scoped_refptr<base::MessageLoopProxy> original_loop_; |
78 base::PlatformFileError error_code_; | 67 base::PlatformFileError error_code_; |
79 | 68 |
80 base::PlatformFile file_; | 69 base::PlatformFile file_; |
81 FileSystemPath path_; | |
82 FileSystemOperationContext context_; | |
83 InitializeTaskCallback callback_; | 70 InitializeTaskCallback callback_; |
84 | 71 |
85 base::PlatformFileInfo file_info_; | 72 base::PlatformFileInfo file_info_; |
86 }; | 73 }; |
87 | 74 |
88 } // namespace (anonymous) | 75 } // namespace (anonymous) |
89 | 76 |
90 FileWriterDelegate::FileWriterDelegate( | 77 FileWriterDelegate::FileWriterDelegate( |
91 FileSystemOperation* file_system_operation, | 78 FileSystemOperation* file_system_operation, |
92 const FileSystemPath& path, | 79 const FileSystemPath& path, |
93 int64 offset) | 80 int64 offset) |
94 : file_system_operation_(file_system_operation), | 81 : file_system_operation_(file_system_operation), |
95 file_(base::kInvalidPlatformFileValue), | 82 file_(base::kInvalidPlatformFileValue), |
96 path_(path), | 83 path_(path), |
97 offset_(offset), | 84 offset_(offset), |
| 85 has_pending_write_(false), |
98 bytes_written_backlog_(0), | 86 bytes_written_backlog_(0), |
99 bytes_written_(0), | 87 bytes_written_(0), |
100 bytes_read_(0), | 88 bytes_read_(0), |
101 total_bytes_written_(0), | 89 total_bytes_written_(0), |
102 allowed_bytes_to_write_(0), | 90 allowed_bytes_to_write_(0), |
103 io_buffer_(new net::IOBufferWithSize(kReadBufSize)), | 91 io_buffer_(new net::IOBufferWithSize(kReadBufSize)), |
104 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | 92 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { |
105 } | 93 } |
106 | 94 |
107 FileWriterDelegate::~FileWriterDelegate() { | 95 FileWriterDelegate::~FileWriterDelegate() { |
108 } | 96 } |
109 | 97 |
110 void FileWriterDelegate::OnGetFileInfoAndCallStartUpdate( | 98 void FileWriterDelegate::OnGetFileInfoAndStartRequest( |
| 99 scoped_ptr<net::URLRequest> request, |
111 base::PlatformFileError error, | 100 base::PlatformFileError error, |
112 const base::PlatformFileInfo& file_info) { | 101 const base::PlatformFileInfo& file_info) { |
113 if (error) { | 102 if (error != base::PLATFORM_FILE_OK) { |
114 OnError(error); | 103 OnError(error); |
115 return; | 104 return; |
116 } | 105 } |
117 int64 allowed_bytes_growth = | 106 int64 allowed_bytes_growth = |
118 file_system_operation_context()->allowed_bytes_growth(); | 107 file_system_operation_context()->allowed_bytes_growth(); |
119 if (allowed_bytes_growth < 0) | 108 if (allowed_bytes_growth < 0) |
120 allowed_bytes_growth = 0; | 109 allowed_bytes_growth = 0; |
121 int64 overlap = file_info.size - offset_; | 110 int64 overlap = file_info.size - offset_; |
122 allowed_bytes_to_write_ = allowed_bytes_growth; | 111 allowed_bytes_to_write_ = allowed_bytes_growth; |
123 if (kint64max - overlap > allowed_bytes_growth) | 112 if (kint64max - overlap > allowed_bytes_growth) |
124 allowed_bytes_to_write_ += overlap; | 113 allowed_bytes_to_write_ += overlap; |
125 size_ = file_info.size; | 114 size_ = file_info.size; |
126 file_stream_.reset(new net::FileStream( | 115 file_stream_.reset(new net::FileStream( |
127 file_, | 116 file_, |
128 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE | | 117 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE | |
129 base::PLATFORM_FILE_ASYNC, | 118 base::PLATFORM_FILE_ASYNC, |
130 NULL)); | 119 NULL)); |
| 120 DCHECK(!request_.get()); |
| 121 request_ = request.Pass(); |
131 request_->Start(); | 122 request_->Start(); |
132 } | 123 } |
133 | 124 |
134 void FileWriterDelegate::Start(base::PlatformFile file, | 125 void FileWriterDelegate::Start(base::PlatformFile file, |
135 net::URLRequest* request) { | 126 scoped_ptr<net::URLRequest> request) { |
136 file_ = file; | 127 file_ = file; |
137 request_ = request; | |
138 | 128 |
139 scoped_refptr<InitializeTask> relay = new InitializeTask( | 129 scoped_refptr<InitializeTask> relay = new InitializeTask( |
140 file_, path_, | 130 file_, |
141 file_system_operation_context(), | 131 base::Bind(&FileWriterDelegate::OnGetFileInfoAndStartRequest, |
142 base::Bind(&FileWriterDelegate::OnGetFileInfoAndCallStartUpdate, | 132 weak_factory_.GetWeakPtr(), base::Passed(&request))); |
143 weak_factory_.GetWeakPtr())); | |
144 relay->Start(file_system_operation_context()->file_task_runner(), FROM_HERE); | 133 relay->Start(file_system_operation_context()->file_task_runner(), FROM_HERE); |
145 } | 134 } |
146 | 135 |
| 136 bool FileWriterDelegate::Cancel() { |
| 137 if (request_.get()) { |
| 138 // This halts any callbacks on this delegate. |
| 139 request_->set_delegate(NULL); |
| 140 request_->Cancel(); |
| 141 } |
| 142 |
| 143 // Return true to finish immediately if we're not writing. |
| 144 // Otherwise we'll do the final cleanup in the write callback. |
| 145 return !has_pending_write_; |
| 146 } |
| 147 |
147 void FileWriterDelegate::OnReceivedRedirect(net::URLRequest* request, | 148 void FileWriterDelegate::OnReceivedRedirect(net::URLRequest* request, |
148 const GURL& new_url, | 149 const GURL& new_url, |
149 bool* defer_redirect) { | 150 bool* defer_redirect) { |
150 NOTREACHED(); | 151 NOTREACHED(); |
151 OnError(base::PLATFORM_FILE_ERROR_SECURITY); | 152 OnError(base::PLATFORM_FILE_ERROR_SECURITY); |
152 } | 153 } |
153 | 154 |
154 void FileWriterDelegate::OnAuthRequired(net::URLRequest* request, | 155 void FileWriterDelegate::OnAuthRequired(net::URLRequest* request, |
155 net::AuthChallengeInfo* auth_info) { | 156 net::AuthChallengeInfo* auth_info) { |
156 NOTREACHED(); | 157 NOTREACHED(); |
157 OnError(base::PLATFORM_FILE_ERROR_SECURITY); | 158 OnError(base::PLATFORM_FILE_ERROR_SECURITY); |
158 } | 159 } |
159 | 160 |
160 void FileWriterDelegate::OnCertificateRequested( | 161 void FileWriterDelegate::OnCertificateRequested( |
161 net::URLRequest* request, | 162 net::URLRequest* request, |
162 net::SSLCertRequestInfo* cert_request_info) { | 163 net::SSLCertRequestInfo* cert_request_info) { |
163 NOTREACHED(); | 164 NOTREACHED(); |
164 OnError(base::PLATFORM_FILE_ERROR_SECURITY); | 165 OnError(base::PLATFORM_FILE_ERROR_SECURITY); |
165 } | 166 } |
166 | 167 |
167 void FileWriterDelegate::OnSSLCertificateError(net::URLRequest* request, | 168 void FileWriterDelegate::OnSSLCertificateError(net::URLRequest* request, |
168 const net::SSLInfo& ssl_info, | 169 const net::SSLInfo& ssl_info, |
169 bool fatal) { | 170 bool fatal) { |
170 NOTREACHED(); | 171 NOTREACHED(); |
171 OnError(base::PLATFORM_FILE_ERROR_SECURITY); | 172 OnError(base::PLATFORM_FILE_ERROR_SECURITY); |
172 } | 173 } |
173 | 174 |
174 void FileWriterDelegate::OnResponseStarted(net::URLRequest* request) { | 175 void FileWriterDelegate::OnResponseStarted(net::URLRequest* request) { |
175 DCHECK_EQ(request_, request); | 176 DCHECK_EQ(request_.get(), request); |
176 // file_stream_->Seek() blocks the IO thread. | 177 // file_stream_->Seek() blocks the IO thread. |
177 // See http://crbug.com/75548. | 178 // See http://crbug.com/75548. |
178 base::ThreadRestrictions::ScopedAllowIO allow_io; | 179 base::ThreadRestrictions::ScopedAllowIO allow_io; |
179 if (!request->status().is_success() || request->GetResponseCode() != 200) { | 180 if (!request->status().is_success() || request->GetResponseCode() != 200) { |
180 OnError(base::PLATFORM_FILE_ERROR_FAILED); | 181 OnError(base::PLATFORM_FILE_ERROR_FAILED); |
181 return; | 182 return; |
182 } | 183 } |
183 int64 error = file_stream_->SeekSync(net::FROM_BEGIN, offset_); | 184 int64 error = file_stream_->SeekSync(net::FROM_BEGIN, offset_); |
184 if (error != offset_) { | 185 if (error != offset_) { |
185 OnError(base::PLATFORM_FILE_ERROR_FAILED); | 186 OnError(base::PLATFORM_FILE_ERROR_FAILED); |
186 return; | 187 return; |
187 } | 188 } |
188 Read(); | 189 Read(); |
189 } | 190 } |
190 | 191 |
191 void FileWriterDelegate::OnReadCompleted(net::URLRequest* request, | 192 void FileWriterDelegate::OnReadCompleted(net::URLRequest* request, |
192 int bytes_read) { | 193 int bytes_read) { |
193 DCHECK_EQ(request_, request); | 194 DCHECK_EQ(request_.get(), request); |
194 if (!request->status().is_success()) { | 195 if (!request->status().is_success()) { |
195 OnError(base::PLATFORM_FILE_ERROR_FAILED); | 196 OnError(base::PLATFORM_FILE_ERROR_FAILED); |
196 return; | 197 return; |
197 } | 198 } |
198 OnDataReceived(bytes_read); | 199 OnDataReceived(bytes_read); |
199 } | 200 } |
200 | 201 |
201 void FileWriterDelegate::Read() { | 202 void FileWriterDelegate::Read() { |
202 bytes_written_ = 0; | 203 bytes_written_ = 0; |
203 bytes_read_ = 0; | 204 bytes_read_ = 0; |
(...skipping 30 matching lines...) Expand all Loading... |
234 allowed_bytes_to_write_ < 0); | 235 allowed_bytes_to_write_ < 0); |
235 if (total_bytes_written_ >= allowed_bytes_to_write_) { | 236 if (total_bytes_written_ >= allowed_bytes_to_write_) { |
236 OnError(base::PLATFORM_FILE_ERROR_NO_SPACE); | 237 OnError(base::PLATFORM_FILE_ERROR_NO_SPACE); |
237 return; | 238 return; |
238 } | 239 } |
239 | 240 |
240 int64 bytes_to_write = bytes_read_ - bytes_written_; | 241 int64 bytes_to_write = bytes_read_ - bytes_written_; |
241 if (bytes_to_write > allowed_bytes_to_write_ - total_bytes_written_) | 242 if (bytes_to_write > allowed_bytes_to_write_ - total_bytes_written_) |
242 bytes_to_write = allowed_bytes_to_write_ - total_bytes_written_; | 243 bytes_to_write = allowed_bytes_to_write_ - total_bytes_written_; |
243 | 244 |
| 245 has_pending_write_ = true; |
244 int write_response = | 246 int write_response = |
245 file_stream_->Write(cursor_, | 247 file_stream_->Write(cursor_, |
246 static_cast<int>(bytes_to_write), | 248 static_cast<int>(bytes_to_write), |
247 base::Bind(&FileWriterDelegate::OnDataWritten, | 249 base::Bind(&FileWriterDelegate::OnDataWritten, |
248 weak_factory_.GetWeakPtr())); | 250 weak_factory_.GetWeakPtr())); |
249 if (write_response > 0) | 251 if (write_response > 0) |
250 MessageLoop::current()->PostTask( | 252 MessageLoop::current()->PostTask( |
251 FROM_HERE, | 253 FROM_HERE, |
252 base::Bind(&FileWriterDelegate::OnDataWritten, | 254 base::Bind(&FileWriterDelegate::OnDataWritten, |
253 weak_factory_.GetWeakPtr(), write_response)); | 255 weak_factory_.GetWeakPtr(), write_response)); |
254 else if (net::ERR_IO_PENDING != write_response) | 256 else if (net::ERR_IO_PENDING != write_response) |
255 OnError(base::PLATFORM_FILE_ERROR_FAILED); | 257 OnError(base::PLATFORM_FILE_ERROR_FAILED); |
256 } | 258 } |
257 | 259 |
258 void FileWriterDelegate::OnDataWritten(int write_response) { | 260 void FileWriterDelegate::OnDataWritten(int write_response) { |
| 261 has_pending_write_ = false; |
259 if (write_response > 0) { | 262 if (write_response > 0) { |
| 263 if (request_->status().status() == net::URLRequestStatus::CANCELED) { |
| 264 OnProgress(write_response, true); |
| 265 return; |
| 266 } |
260 OnProgress(write_response, false); | 267 OnProgress(write_response, false); |
261 cursor_->DidConsume(write_response); | 268 cursor_->DidConsume(write_response); |
262 bytes_written_ += write_response; | 269 bytes_written_ += write_response; |
263 total_bytes_written_ += write_response; | 270 total_bytes_written_ += write_response; |
264 if (bytes_written_ == bytes_read_) | 271 if (bytes_written_ == bytes_read_) |
265 Read(); | 272 Read(); |
266 else | 273 else |
267 Write(); | 274 Write(); |
268 } else { | 275 } else { |
269 OnError(base::PLATFORM_FILE_ERROR_FAILED); | 276 OnError(base::PLATFORM_FILE_ERROR_FAILED); |
270 } | 277 } |
271 } | 278 } |
272 | 279 |
273 void FileWriterDelegate::OnError(base::PlatformFileError error) { | 280 void FileWriterDelegate::OnError(base::PlatformFileError error) { |
274 request_->set_delegate(NULL); | 281 if (request_.get()) { |
275 request_->Cancel(); | 282 request_->set_delegate(NULL); |
276 | 283 request_->Cancel(); |
277 if (quota_util()) | 284 } |
278 quota_util()->proxy()->EndUpdateOrigin(path_.origin(), path_.type()); | |
279 | 285 |
280 file_system_operation_->DidWrite(error, 0, true); | 286 file_system_operation_->DidWrite(error, 0, true); |
281 } | 287 } |
282 | 288 |
283 void FileWriterDelegate::OnProgress(int bytes_written, bool done) { | 289 void FileWriterDelegate::OnProgress(int bytes_written, bool done) { |
284 DCHECK(bytes_written + bytes_written_backlog_ >= bytes_written_backlog_); | 290 DCHECK(bytes_written + bytes_written_backlog_ >= bytes_written_backlog_); |
285 if (quota_util() && | 291 if (quota_util() && |
286 bytes_written > 0 && | 292 bytes_written > 0 && |
287 total_bytes_written_ + bytes_written + offset_ > size_) { | 293 total_bytes_written_ + bytes_written + offset_ > size_) { |
288 int overlapped = 0; | 294 int overlapped = 0; |
(...skipping 30 matching lines...) Expand all Loading... |
319 | 325 |
320 FileSystemQuotaUtil* FileWriterDelegate::quota_util() const { | 326 FileSystemQuotaUtil* FileWriterDelegate::quota_util() const { |
321 DCHECK(file_system_operation_); | 327 DCHECK(file_system_operation_); |
322 DCHECK(file_system_operation_->file_system_context()); | 328 DCHECK(file_system_operation_->file_system_context()); |
323 DCHECK(file_system_operation_->file_system_operation_context()); | 329 DCHECK(file_system_operation_->file_system_operation_context()); |
324 return file_system_operation_->file_system_context()->GetQuotaUtil( | 330 return file_system_operation_->file_system_context()->GetQuotaUtil( |
325 path_.type()); | 331 path_.type()); |
326 } | 332 } |
327 | 333 |
328 } // namespace fileapi | 334 } // namespace fileapi |
OLD | NEW |