1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/url_request/url_fetcher_response_writer.h"
6
7#include "base/files/file_util.h"
8#include "base/location.h"
9#include "base/sequenced_task_runner.h"
10#include "base/task_runner_util.h"
11#include "net/base/file_stream.h"
12#include "net/base/io_buffer.h"
13#include "net/base/net_errors.h"
14
15namespace net {
16
17URLFetcherStringWriter* URLFetcherResponseWriter::AsStringWriter() {
18  return NULL;
19}
20
21URLFetcherFileWriter* URLFetcherResponseWriter::AsFileWriter() {
22  return NULL;
23}
24
25URLFetcherStringWriter::URLFetcherStringWriter() {
26}
27
28URLFetcherStringWriter::~URLFetcherStringWriter() {
29}
30
31int URLFetcherStringWriter::Initialize(const CompletionCallback& callback) {
32  data_.clear();
33  return OK;
34}
35
36int URLFetcherStringWriter::Write(IOBuffer* buffer,
37                                  int num_bytes,
38                                  const CompletionCallback& callback) {
39  data_.append(buffer->data(), num_bytes);
40  return num_bytes;
41}
42
43int URLFetcherStringWriter::Finish(const CompletionCallback& callback) {
44  // Do nothing.
45  return OK;
46}
47
48URLFetcherStringWriter* URLFetcherStringWriter::AsStringWriter() {
49  return this;
50}
51
52URLFetcherFileWriter::URLFetcherFileWriter(
53    scoped_refptr<base::SequencedTaskRunner> file_task_runner,
54    const base::FilePath& file_path)
55    : file_task_runner_(file_task_runner),
56      file_path_(file_path),
57      owns_file_(false),
58      weak_factory_(this) {
59  DCHECK(file_task_runner_.get());
60}
61
62URLFetcherFileWriter::~URLFetcherFileWriter() {
63  CloseAndDeleteFile();
64}
65
66int URLFetcherFileWriter::Initialize(const CompletionCallback& callback) {
67  file_stream_.reset(new FileStream(file_task_runner_));
68
69  int result = ERR_IO_PENDING;
70  if (file_path_.empty()) {
71    base::FilePath* temp_file_path = new base::FilePath;
72    base::PostTaskAndReplyWithResult(
73        file_task_runner_.get(),
74        FROM_HERE,
75        base::Bind(&base::CreateTemporaryFile, temp_file_path),
76        base::Bind(&URLFetcherFileWriter::DidCreateTempFile,
77                   weak_factory_.GetWeakPtr(),
78                   callback,
79                   base::Owned(temp_file_path)));
80  } else {
81    result = file_stream_->Open(
82        file_path_,
83        base::File::FLAG_WRITE | base::File::FLAG_ASYNC |
84        base::File::FLAG_CREATE_ALWAYS,
85        base::Bind(&URLFetcherFileWriter::DidOpenFile,
86                   weak_factory_.GetWeakPtr(),
87                   callback));
88    DCHECK_NE(OK, result);
89  }
90  return result;
91}
92
93int URLFetcherFileWriter::Write(IOBuffer* buffer,
94                                int num_bytes,
95                                const CompletionCallback& callback) {
96  DCHECK(file_stream_);
97  DCHECK(owns_file_);
98
99  int result = file_stream_->Write(buffer, num_bytes,
100                                   base::Bind(&URLFetcherFileWriter::DidWrite,
101                                              weak_factory_.GetWeakPtr(),
102                                              callback));
103  if (result < 0 && result != ERR_IO_PENDING)
104    CloseAndDeleteFile();
105
106  return result;
107}
108
109int URLFetcherFileWriter::Finish(const CompletionCallback& callback) {
110  // If the file_stream_ still exists at this point, close it.
111  if (file_stream_) {
112    int result = file_stream_->Close(base::Bind(
113        &URLFetcherFileWriter::CloseComplete,
114        weak_factory_.GetWeakPtr(), callback));
115    if (result != ERR_IO_PENDING)
116      file_stream_.reset();
117    return result;
118  }
119  return OK;
120}
121
122URLFetcherFileWriter* URLFetcherFileWriter::AsFileWriter() {
123  return this;
124}
125
126void URLFetcherFileWriter::DisownFile() {
127  // Disowning is done by the delegate's OnURLFetchComplete method.
128  // The file should be closed by the time that method is called.
129  DCHECK(!file_stream_);
130
131  owns_file_ = false;
132}
133
134void URLFetcherFileWriter::DidWrite(const CompletionCallback& callback,
135                                    int result) {
136  if (result < 0)
137    CloseAndDeleteFile();
138
139  callback.Run(result);
140}
141
142void URLFetcherFileWriter::CloseAndDeleteFile() {
143  if (!owns_file_)
144    return;
145
146  file_stream_.reset();
147  DisownFile();
148  file_task_runner_->PostTask(FROM_HERE,
149                              base::Bind(base::IgnoreResult(&base::DeleteFile),
150                                         file_path_,
151                                         false /* recursive */));
152}
153
154void URLFetcherFileWriter::DidCreateTempFile(const CompletionCallback& callback,
155                                             base::FilePath* temp_file_path,
156                                             bool success) {
157  if (!success) {
158    callback.Run(ERR_FILE_NOT_FOUND);
159    return;
160  }
161  file_path_ = *temp_file_path;
162  owns_file_ = true;
163  const int result = file_stream_->Open(
164      file_path_,
165      base::File::FLAG_WRITE | base::File::FLAG_ASYNC |
166      base::File::FLAG_OPEN,
167      base::Bind(&URLFetcherFileWriter::DidOpenFile,
168                 weak_factory_.GetWeakPtr(),
169                 callback));
170  if (result != ERR_IO_PENDING)
171    DidOpenFile(callback, result);
172}
173
174void URLFetcherFileWriter::DidOpenFile(const CompletionCallback& callback,
175                                       int result) {
176  if (result == OK)
177    owns_file_ = true;
178  else
179    CloseAndDeleteFile();
180
181  callback.Run(result);
182}
183
184void URLFetcherFileWriter::CloseComplete(const CompletionCallback& callback,
185                                         int result) {
186  // Destroy |file_stream_| whether or not the close succeeded.
187  file_stream_.reset();
188  callback.Run(result);
189}
190
191}  // namespace net
192