upload_file_element_reader.cc 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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
  3. // found in the LICENSE file.
  4. #include "net/base/upload_file_element_reader.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/files/file_util.h"
  8. #include "base/location.h"
  9. #include "base/task/task_runner.h"
  10. #include "base/task/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. namespace net {
  15. namespace {
  16. // In tests, this value is used to override the return value of
  17. // UploadFileElementReader::GetContentLength() when set to non-zero.
  18. uint64_t overriding_content_length = 0;
  19. } // namespace
  20. UploadFileElementReader::UploadFileElementReader(
  21. base::TaskRunner* task_runner,
  22. base::File file,
  23. const base::FilePath& path,
  24. uint64_t range_offset,
  25. uint64_t range_length,
  26. const base::Time& expected_modification_time)
  27. : task_runner_(task_runner),
  28. path_(path),
  29. range_offset_(range_offset),
  30. range_length_(range_length),
  31. expected_modification_time_(expected_modification_time) {
  32. DCHECK(file.IsValid());
  33. DCHECK(task_runner_.get());
  34. file_stream_ = std::make_unique<FileStream>(std::move(file), task_runner);
  35. }
  36. UploadFileElementReader::UploadFileElementReader(
  37. base::TaskRunner* task_runner,
  38. const base::FilePath& path,
  39. uint64_t range_offset,
  40. uint64_t range_length,
  41. const base::Time& expected_modification_time)
  42. : task_runner_(task_runner),
  43. path_(path),
  44. range_offset_(range_offset),
  45. range_length_(range_length),
  46. expected_modification_time_(expected_modification_time) {
  47. DCHECK(task_runner_.get());
  48. }
  49. UploadFileElementReader::~UploadFileElementReader() = default;
  50. const UploadFileElementReader* UploadFileElementReader::AsFileReader() const {
  51. return this;
  52. }
  53. int UploadFileElementReader::Init(CompletionOnceCallback callback) {
  54. DCHECK(!callback.is_null());
  55. bytes_remaining_ = 0;
  56. content_length_ = 0;
  57. pending_callback_.Reset();
  58. // If the file is being opened, just update the callback, and continue
  59. // waiting.
  60. if (next_state_ == State::OPEN_COMPLETE) {
  61. DCHECK(file_stream_);
  62. pending_callback_ = std::move(callback);
  63. return ERR_IO_PENDING;
  64. }
  65. // If there's already a pending operation, wait for it to complete before
  66. // restarting the request.
  67. if (next_state_ != State::IDLE) {
  68. init_called_while_operation_pending_ = true;
  69. pending_callback_ = std::move(callback);
  70. return ERR_IO_PENDING;
  71. }
  72. DCHECK(!init_called_while_operation_pending_);
  73. if (file_stream_) {
  74. // If the file is already open, just re-use it.
  75. // TODO(mmenke): Consider reusing file info, too.
  76. next_state_ = State::SEEK;
  77. } else {
  78. next_state_ = State::OPEN;
  79. }
  80. int result = DoLoop(OK);
  81. if (result == ERR_IO_PENDING)
  82. pending_callback_ = std::move(callback);
  83. return result;
  84. }
  85. uint64_t UploadFileElementReader::GetContentLength() const {
  86. if (overriding_content_length)
  87. return overriding_content_length;
  88. return content_length_;
  89. }
  90. uint64_t UploadFileElementReader::BytesRemaining() const {
  91. return bytes_remaining_;
  92. }
  93. int UploadFileElementReader::Read(IOBuffer* buf,
  94. int buf_length,
  95. CompletionOnceCallback callback) {
  96. DCHECK(!callback.is_null());
  97. DCHECK_EQ(next_state_, State::IDLE);
  98. DCHECK(file_stream_);
  99. int num_bytes_to_read = static_cast<int>(
  100. std::min(BytesRemaining(), static_cast<uint64_t>(buf_length)));
  101. if (num_bytes_to_read == 0)
  102. return 0;
  103. next_state_ = State::READ_COMPLETE;
  104. int result = file_stream_->Read(
  105. buf, num_bytes_to_read,
  106. base::BindOnce(base::IgnoreResult(&UploadFileElementReader::OnIOComplete),
  107. weak_ptr_factory_.GetWeakPtr()));
  108. if (result != ERR_IO_PENDING)
  109. result = DoLoop(result);
  110. if (result == ERR_IO_PENDING)
  111. pending_callback_ = std::move(callback);
  112. return result;
  113. }
  114. int UploadFileElementReader::DoLoop(int result) {
  115. DCHECK_NE(result, ERR_IO_PENDING);
  116. if (init_called_while_operation_pending_) {
  117. // File should already have been opened successfully.
  118. DCHECK_NE(next_state_, State::OPEN_COMPLETE);
  119. next_state_ = State::SEEK;
  120. init_called_while_operation_pending_ = false;
  121. result = net::OK;
  122. }
  123. while (next_state_ != State::IDLE && result != ERR_IO_PENDING) {
  124. State state = next_state_;
  125. next_state_ = State::IDLE;
  126. switch (state) {
  127. case State::IDLE:
  128. NOTREACHED();
  129. break;
  130. case State::OPEN:
  131. // Ignore previous result here. It's typically OK, but if Init()
  132. // interrupted the previous operation, it may be an error.
  133. result = DoOpen();
  134. break;
  135. case State::OPEN_COMPLETE:
  136. result = DoOpenComplete(result);
  137. break;
  138. case State::SEEK:
  139. DCHECK_EQ(OK, result);
  140. result = DoSeek();
  141. break;
  142. case State::GET_FILE_INFO:
  143. result = DoGetFileInfo(result);
  144. break;
  145. case State::GET_FILE_INFO_COMPLETE:
  146. result = DoGetFileInfoComplete(result);
  147. break;
  148. case State::READ_COMPLETE:
  149. result = DoReadComplete(result);
  150. break;
  151. }
  152. }
  153. return result;
  154. }
  155. int UploadFileElementReader::DoOpen() {
  156. DCHECK(!file_stream_);
  157. next_state_ = State::OPEN_COMPLETE;
  158. file_stream_ = std::make_unique<FileStream>(task_runner_.get());
  159. int result = file_stream_->Open(
  160. path_,
  161. base::File::FLAG_OPEN | base::File::FLAG_READ | base::File::FLAG_ASYNC,
  162. base::BindOnce(&UploadFileElementReader::OnIOComplete,
  163. weak_ptr_factory_.GetWeakPtr()));
  164. DCHECK_GT(0, result);
  165. return result;
  166. }
  167. int UploadFileElementReader::DoOpenComplete(int result) {
  168. if (result < 0) {
  169. DLOG(WARNING) << "Failed to open \"" << path_.value()
  170. << "\" for reading: " << result;
  171. file_stream_.reset();
  172. return result;
  173. }
  174. if (range_offset_) {
  175. next_state_ = State::SEEK;
  176. } else {
  177. next_state_ = State::GET_FILE_INFO;
  178. }
  179. return net::OK;
  180. }
  181. int UploadFileElementReader::DoSeek() {
  182. next_state_ = State::GET_FILE_INFO;
  183. return file_stream_->Seek(
  184. range_offset_,
  185. base::BindOnce(
  186. [](base::WeakPtr<UploadFileElementReader> weak_this, int64_t result) {
  187. if (!weak_this)
  188. return;
  189. weak_this->OnIOComplete(result >= 0 ? OK
  190. : static_cast<int>(result));
  191. },
  192. weak_ptr_factory_.GetWeakPtr()));
  193. }
  194. int UploadFileElementReader::DoGetFileInfo(int result) {
  195. if (result < 0) {
  196. DLOG(WARNING) << "Failed to seek \"" << path_.value()
  197. << "\" to offset: " << range_offset_ << " (" << result << ")";
  198. return result;
  199. }
  200. next_state_ = State::GET_FILE_INFO_COMPLETE;
  201. auto file_info = std::make_unique<base::File::Info>();
  202. auto* file_info_ptr = file_info.get();
  203. result = file_stream_->GetFileInfo(
  204. file_info_ptr,
  205. base::BindOnce(
  206. [](base::WeakPtr<UploadFileElementReader> weak_this,
  207. std::unique_ptr<base::File::Info> file_info, int result) {
  208. if (!weak_this)
  209. return;
  210. weak_this->file_info_ = *file_info;
  211. weak_this->OnIOComplete(result);
  212. },
  213. weak_ptr_factory_.GetWeakPtr(), std::move(file_info)));
  214. // GetFileInfo() can't succeed synchronously.
  215. DCHECK_NE(result, OK);
  216. return result;
  217. }
  218. int UploadFileElementReader::DoGetFileInfoComplete(int result) {
  219. if (result != OK) {
  220. DLOG(WARNING) << "Failed to get file info of \"" << path_.value() << "\"";
  221. return result;
  222. }
  223. int64_t length = file_info_.size;
  224. if (range_offset_ < static_cast<uint64_t>(length)) {
  225. // Compensate for the offset.
  226. length = std::min(length - range_offset_, range_length_);
  227. }
  228. // If the underlying file has been changed and the expected file modification
  229. // time is set, treat it as error. Note that |expected_modification_time_| may
  230. // have gone through multiple conversion steps involving loss of precision
  231. // (including conversion to time_t). Therefore the check below only verifies
  232. // that the timestamps are within one second of each other. This check is used
  233. // for sliced files.
  234. if (!expected_modification_time_.is_null() &&
  235. (expected_modification_time_ - file_info_.last_modified)
  236. .magnitude()
  237. .InSeconds() != 0) {
  238. return ERR_UPLOAD_FILE_CHANGED;
  239. }
  240. content_length_ = length;
  241. bytes_remaining_ = GetContentLength();
  242. return result;
  243. }
  244. int UploadFileElementReader::DoReadComplete(int result) {
  245. if (result == 0) // Reached end-of-file earlier than expected.
  246. return ERR_UPLOAD_FILE_CHANGED;
  247. if (result > 0) {
  248. DCHECK_GE(bytes_remaining_, static_cast<uint64_t>(result));
  249. bytes_remaining_ -= result;
  250. }
  251. return result;
  252. }
  253. void UploadFileElementReader::OnIOComplete(int result) {
  254. DCHECK(pending_callback_);
  255. result = DoLoop(result);
  256. if (result != ERR_IO_PENDING)
  257. std::move(pending_callback_).Run(result);
  258. }
  259. UploadFileElementReader::ScopedOverridingContentLengthForTests::
  260. ScopedOverridingContentLengthForTests(uint64_t value) {
  261. overriding_content_length = value;
  262. }
  263. UploadFileElementReader::ScopedOverridingContentLengthForTests::
  264. ~ScopedOverridingContentLengthForTests() {
  265. overriding_content_length = 0;
  266. }
  267. } // namespace net