| // 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/files/file_util.h" | 
 | #include "base/location.h" | 
 | #include "base/profiler/scoped_tracker.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() { | 
 | } | 
 |  | 
 | URLFetcherStringWriter::~URLFetcherStringWriter() { | 
 | } | 
 |  | 
 | 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(const CompletionCallback& callback) { | 
 |   // Do nothing. | 
 |   return OK; | 
 | } | 
 |  | 
 | URLFetcherStringWriter* URLFetcherStringWriter::AsStringWriter() { | 
 |   return this; | 
 | } | 
 |  | 
 | URLFetcherFileWriter::URLFetcherFileWriter( | 
 |     scoped_refptr<base::SequencedTaskRunner> 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) { | 
 |   file_stream_.reset(new FileStream(file_task_runner_)); | 
 |  | 
 |   int result = ERR_IO_PENDING; | 
 |   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(), | 
 |                    callback, | 
 |                    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::DidOpenFile, | 
 |                    weak_factory_.GetWeakPtr(), | 
 |                    callback)); | 
 |     DCHECK_NE(OK, result); | 
 |   } | 
 |   return result; | 
 | } | 
 |  | 
 | int URLFetcherFileWriter::Write(IOBuffer* buffer, | 
 |                                 int num_bytes, | 
 |                                 const CompletionCallback& callback) { | 
 |   DCHECK(file_stream_); | 
 |   DCHECK(owns_file_); | 
 |  | 
 |   int result = file_stream_->Write(buffer, num_bytes, | 
 |                                    base::Bind(&URLFetcherFileWriter::DidWrite, | 
 |                                               weak_factory_.GetWeakPtr(), | 
 |                                               callback)); | 
 |   if (result < 0 && result != ERR_IO_PENDING) | 
 |     CloseAndDeleteFile(); | 
 |  | 
 |   return result; | 
 | } | 
 |  | 
 | int URLFetcherFileWriter::Finish(const CompletionCallback& 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(), callback)); | 
 |     if (result != ERR_IO_PENDING) | 
 |       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::DidWrite(const CompletionCallback& callback, | 
 |                                     int result) { | 
 |   if (result < 0) | 
 |     CloseAndDeleteFile(); | 
 |  | 
 |   callback.Run(result); | 
 | } | 
 |  | 
 | 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(const CompletionCallback& callback, | 
 |                                              base::FilePath* temp_file_path, | 
 |                                              bool success) { | 
 |   if (!success) { | 
 |     callback.Run(ERR_FILE_NOT_FOUND); | 
 |     return; | 
 |   } | 
 |   file_path_ = *temp_file_path; | 
 |   owns_file_ = true; | 
 |   const int result = file_stream_->Open( | 
 |       file_path_, | 
 |       base::File::FLAG_WRITE | base::File::FLAG_ASYNC | | 
 |       base::File::FLAG_OPEN, | 
 |       base::Bind(&URLFetcherFileWriter::DidOpenFile, | 
 |                  weak_factory_.GetWeakPtr(), | 
 |                  callback)); | 
 |   if (result != ERR_IO_PENDING) | 
 |     DidOpenFile(callback, result); | 
 | } | 
 |  | 
 | void URLFetcherFileWriter::DidOpenFile(const CompletionCallback& callback, | 
 |                                        int result) { | 
 |   // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. | 
 |   tracked_objects::ScopedTracker tracking_profile( | 
 |       FROM_HERE_WITH_EXPLICIT_FUNCTION( | 
 |           "423948 URLFetcherFileWriter::DidOpenFile")); | 
 |  | 
 |   if (result == OK) | 
 |     owns_file_ = true; | 
 |   else | 
 |     CloseAndDeleteFile(); | 
 |  | 
 |   callback.Run(result); | 
 | } | 
 |  | 
 | void URLFetcherFileWriter::CloseComplete(const CompletionCallback& callback, | 
 |                                          int result) { | 
 |   // Destroy |file_stream_| whether or not the close succeeded. | 
 |   file_stream_.reset(); | 
 |   callback.Run(result); | 
 | } | 
 |  | 
 | }  // namespace net |