| 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 |