// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/url_request/url_fetcher_response_writer.h" #include "base/callback_helpers.h" #include "base/files/file_util.h" #include "base/location.h" #include "base/sequenced_task_runner.h" #include "base/task_runner_util.h" #include "net/base/file_stream.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" namespace net { URLFetcherStringWriter* URLFetcherResponseWriter::AsStringWriter() { return NULL; } URLFetcherFileWriter* URLFetcherResponseWriter::AsFileWriter() { return NULL; } URLFetcherStringWriter::URLFetcherStringWriter() = default; URLFetcherStringWriter::~URLFetcherStringWriter() = default; int URLFetcherStringWriter::Initialize(const CompletionCallback& callback) { data_.clear(); return OK; } int URLFetcherStringWriter::Write(IOBuffer* buffer, int num_bytes, const CompletionCallback& callback) { data_.append(buffer->data(), num_bytes); return num_bytes; } int URLFetcherStringWriter::Finish(int net_error, const CompletionCallback& callback) { // Do nothing. return OK; } URLFetcherStringWriter* URLFetcherStringWriter::AsStringWriter() { return this; } URLFetcherFileWriter::URLFetcherFileWriter( scoped_refptr file_task_runner, const base::FilePath& file_path) : file_task_runner_(file_task_runner), file_path_(file_path), owns_file_(false), weak_factory_(this) { DCHECK(file_task_runner_.get()); } URLFetcherFileWriter::~URLFetcherFileWriter() { CloseAndDeleteFile(); } int URLFetcherFileWriter::Initialize(const CompletionCallback& callback) { DCHECK(!callback_); file_stream_.reset(new FileStream(file_task_runner_)); int result = ERR_IO_PENDING; owns_file_ = true; if (file_path_.empty()) { base::FilePath* temp_file_path = new base::FilePath; base::PostTaskAndReplyWithResult( file_task_runner_.get(), FROM_HERE, base::Bind(&base::CreateTemporaryFile, temp_file_path), base::Bind(&URLFetcherFileWriter::DidCreateTempFile, weak_factory_.GetWeakPtr(), base::Owned(temp_file_path))); } else { result = file_stream_->Open(file_path_, base::File::FLAG_WRITE | base::File::FLAG_ASYNC | base::File::FLAG_CREATE_ALWAYS, base::Bind(&URLFetcherFileWriter::OnIOCompleted, weak_factory_.GetWeakPtr())); DCHECK_NE(OK, result); } if (result == ERR_IO_PENDING) { callback_ = callback; return result; } if (result < 0) CloseAndDeleteFile(); return result; } int URLFetcherFileWriter::Write(IOBuffer* buffer, int num_bytes, const CompletionCallback& callback) { DCHECK(file_stream_); DCHECK(owns_file_); DCHECK(!callback_); int result = file_stream_->Write( buffer, num_bytes, base::Bind(&URLFetcherFileWriter::OnIOCompleted, weak_factory_.GetWeakPtr())); if (result == ERR_IO_PENDING) { callback_ = callback; return result; } if (result < 0) CloseAndDeleteFile(); return result; } int URLFetcherFileWriter::Finish(int net_error, const CompletionCallback& callback) { DCHECK_NE(ERR_IO_PENDING, net_error); // If an error occurred, simply delete the file after any pending operation // is done. Do not call file_stream_->Close() because there might be an // operation pending. See crbug.com/487732. if (net_error < 0) { // Cancel callback and invalid weak ptrs so as to cancel any posted task. callback_.Reset(); weak_factory_.InvalidateWeakPtrs(); CloseAndDeleteFile(); return OK; } DCHECK(!callback_); // If the file_stream_ still exists at this point, close it. if (file_stream_) { int result = file_stream_->Close(base::Bind( &URLFetcherFileWriter::CloseComplete, weak_factory_.GetWeakPtr())); if (result == ERR_IO_PENDING) { callback_ = callback; return result; } file_stream_.reset(); return result; } return OK; } URLFetcherFileWriter* URLFetcherFileWriter::AsFileWriter() { return this; } void URLFetcherFileWriter::DisownFile() { // Disowning is done by the delegate's OnURLFetchComplete method. // The file should be closed by the time that method is called. DCHECK(!file_stream_); owns_file_ = false; } void URLFetcherFileWriter::CloseAndDeleteFile() { if (!owns_file_) return; file_stream_.reset(); DisownFile(); file_task_runner_->PostTask(FROM_HERE, base::Bind(base::IgnoreResult(&base::DeleteFile), file_path_, false /* recursive */)); } void URLFetcherFileWriter::DidCreateTempFile(base::FilePath* temp_file_path, bool success) { if (!success) { OnIOCompleted(ERR_FILE_NOT_FOUND); return; } file_path_ = *temp_file_path; const int result = file_stream_->Open( file_path_, base::File::FLAG_WRITE | base::File::FLAG_ASYNC | base::File::FLAG_OPEN, base::Bind(&URLFetcherFileWriter::OnIOCompleted, weak_factory_.GetWeakPtr())); if (result != ERR_IO_PENDING) OnIOCompleted(result); } void URLFetcherFileWriter::OnIOCompleted(int result) { if (result < OK) CloseAndDeleteFile(); if (!callback_.is_null()) base::ResetAndReturn(&callback_).Run(result); } void URLFetcherFileWriter::CloseComplete(int result) { // Destroy |file_stream_| whether or not the close succeeded. file_stream_.reset(); if (!callback_.is_null()) base::ResetAndReturn(&callback_).Run(result); } } // namespace net