http_cache_writers.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. // Copyright (c) 2017 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/http/http_cache_writers.h"
  5. #include <algorithm>
  6. #include <utility>
  7. #include "base/auto_reset.h"
  8. #include "base/bind.h"
  9. #include "base/callback_helpers.h"
  10. #include "base/debug/crash_logging.h"
  11. #include "base/debug/dump_without_crashing.h"
  12. #include "base/logging.h"
  13. #include "base/strings/stringprintf.h"
  14. #include "base/threading/thread_task_runner_handle.h"
  15. #include "crypto/secure_hash.h"
  16. #include "crypto/sha2.h"
  17. #include "net/base/net_errors.h"
  18. #include "net/disk_cache/disk_cache.h"
  19. #include "net/http/http_cache_transaction.h"
  20. #include "net/http/http_response_info.h"
  21. #include "net/http/http_status_code.h"
  22. #include "net/http/partial_data.h"
  23. namespace net {
  24. namespace {
  25. base::debug::CrashKeyString* GetCacheKeyCrashKey() {
  26. static auto* crash_key = base::debug::AllocateCrashKeyString(
  27. "http_cache_key", base::debug::CrashKeySize::Size256);
  28. return crash_key;
  29. }
  30. base::debug::CrashKeyString* GetTransactionFlagsCrashKey() {
  31. static auto* crash_key = base::debug::AllocateCrashKeyString(
  32. "http_cache_transaction", base::debug::CrashKeySize::Size256);
  33. return crash_key;
  34. }
  35. bool IsValidResponseForWriter(bool is_partial,
  36. const HttpResponseInfo* response_info) {
  37. if (!response_info->headers.get())
  38. return false;
  39. // Return false if the response code sent by the server is garbled.
  40. // Both 200 and 304 are valid since concurrent writing is supported.
  41. if (!is_partial &&
  42. (response_info->headers->response_code() != net::HTTP_OK &&
  43. response_info->headers->response_code() != net::HTTP_NOT_MODIFIED)) {
  44. return false;
  45. }
  46. return true;
  47. }
  48. } // namespace
  49. HttpCache::Writers::TransactionInfo::TransactionInfo(PartialData* partial_data,
  50. const bool is_truncated,
  51. HttpResponseInfo info)
  52. : partial(partial_data), truncated(is_truncated), response_info(info) {}
  53. HttpCache::Writers::TransactionInfo::~TransactionInfo() = default;
  54. HttpCache::Writers::TransactionInfo::TransactionInfo(const TransactionInfo&) =
  55. default;
  56. HttpCache::Writers::Writers(HttpCache* cache, HttpCache::ActiveEntry* entry)
  57. : cache_(cache), entry_(entry) {
  58. DCHECK(cache_);
  59. DCHECK(entry_);
  60. }
  61. HttpCache::Writers::~Writers() = default;
  62. int HttpCache::Writers::Read(scoped_refptr<IOBuffer> buf,
  63. int buf_len,
  64. CompletionOnceCallback callback,
  65. Transaction* transaction) {
  66. DCHECK(buf);
  67. // TODO(https://crbug.com/1335423): Change to DCHECK_GT() or remove after bug
  68. // is fixed.
  69. CHECK_GT(buf_len, 0);
  70. DCHECK(!callback.is_null());
  71. DCHECK(transaction);
  72. // If another transaction invoked a Read which is currently ongoing, then
  73. // this transaction waits for the read to complete and gets its buffer filled
  74. // with the data returned from that read.
  75. if (next_state_ != State::NONE) {
  76. WaitingForRead read_info(buf, buf_len, std::move(callback));
  77. waiting_for_read_.insert(std::make_pair(transaction, std::move(read_info)));
  78. return ERR_IO_PENDING;
  79. }
  80. DCHECK_EQ(next_state_, State::NONE);
  81. DCHECK(callback_.is_null());
  82. DCHECK_EQ(nullptr, active_transaction_);
  83. DCHECK(HasTransaction(transaction));
  84. active_transaction_ = transaction;
  85. read_buf_ = std::move(buf);
  86. io_buf_len_ = buf_len;
  87. next_state_ = State::NETWORK_READ;
  88. int rv = DoLoop(OK);
  89. if (rv == ERR_IO_PENDING)
  90. callback_ = std::move(callback);
  91. return rv;
  92. }
  93. bool HttpCache::Writers::StopCaching(bool keep_entry) {
  94. // If this is the only transaction in Writers, then stopping will be
  95. // successful. If not, then we will not stop caching since there are
  96. // other consumers waiting to read from the cache.
  97. if (all_writers_.size() != 1)
  98. return false;
  99. network_read_only_ = true;
  100. if (!keep_entry) {
  101. should_keep_entry_ = false;
  102. cache_->WritersDoomEntryRestartTransactions(entry_);
  103. }
  104. return true;
  105. }
  106. void HttpCache::Writers::AddTransaction(
  107. Transaction* transaction,
  108. ParallelWritingPattern initial_writing_pattern,
  109. RequestPriority priority,
  110. const TransactionInfo& info) {
  111. DCHECK(transaction);
  112. ParallelWritingPattern writers_pattern;
  113. DCHECK(CanAddWriters(&writers_pattern));
  114. DCHECK_EQ(0u, all_writers_.count(transaction));
  115. // Set truncation related information.
  116. response_info_truncation_ = info.response_info;
  117. should_keep_entry_ =
  118. IsValidResponseForWriter(info.partial != nullptr, &(info.response_info));
  119. if (all_writers_.empty()) {
  120. DCHECK_EQ(PARALLEL_WRITING_NONE, parallel_writing_pattern_);
  121. parallel_writing_pattern_ = initial_writing_pattern;
  122. if (parallel_writing_pattern_ != PARALLEL_WRITING_JOIN)
  123. is_exclusive_ = true;
  124. } else {
  125. DCHECK_EQ(PARALLEL_WRITING_JOIN, parallel_writing_pattern_);
  126. }
  127. if (info.partial && !info.truncated) {
  128. DCHECK(!partial_do_not_truncate_);
  129. partial_do_not_truncate_ = true;
  130. }
  131. std::pair<Transaction*, TransactionInfo> writer(transaction, info);
  132. all_writers_.insert(writer);
  133. priority_ = std::max(priority, priority_);
  134. if (network_transaction_) {
  135. network_transaction_->SetPriority(priority_);
  136. }
  137. }
  138. void HttpCache::Writers::SetNetworkTransaction(
  139. Transaction* transaction,
  140. std::unique_ptr<HttpTransaction> network_transaction,
  141. std::unique_ptr<crypto::SecureHash> checksum) {
  142. DCHECK_EQ(1u, all_writers_.count(transaction));
  143. DCHECK(network_transaction);
  144. DCHECK(!network_transaction_);
  145. network_transaction_ = std::move(network_transaction);
  146. network_transaction_->SetPriority(priority_);
  147. DCHECK(!checksum_);
  148. checksum_ = std::move(checksum);
  149. }
  150. void HttpCache::Writers::ResetNetworkTransaction() {
  151. DCHECK(is_exclusive_);
  152. DCHECK_EQ(1u, all_writers_.size());
  153. DCHECK(all_writers_.begin()->second.partial);
  154. network_transaction_.reset();
  155. }
  156. void HttpCache::Writers::RemoveTransaction(Transaction* transaction,
  157. bool success) {
  158. EraseTransaction(transaction, OK);
  159. if (!all_writers_.empty())
  160. return;
  161. if (!success && ShouldTruncate())
  162. TruncateEntry();
  163. cache_->WritersDoneWritingToEntry(entry_, success, should_keep_entry_,
  164. TransactionSet());
  165. }
  166. void HttpCache::Writers::EraseTransaction(Transaction* transaction,
  167. int result) {
  168. // The transaction should be part of all_writers.
  169. auto it = all_writers_.find(transaction);
  170. DCHECK(it != all_writers_.end());
  171. EraseTransaction(it, result);
  172. }
  173. HttpCache::Writers::TransactionMap::iterator
  174. HttpCache::Writers::EraseTransaction(TransactionMap::iterator it, int result) {
  175. Transaction* transaction = it->first;
  176. transaction->WriterAboutToBeRemovedFromEntry(result);
  177. auto return_it = all_writers_.erase(it);
  178. if (all_writers_.empty() && next_state_ == State::NONE) {
  179. // This needs to be called to handle the edge case where even before Read is
  180. // invoked all transactions are removed. In that case the
  181. // network_transaction_ will still have a valid request info and so it
  182. // should be destroyed before its consumer is destroyed (request info
  183. // is a raw pointer owned by its consumer).
  184. network_transaction_.reset();
  185. } else {
  186. UpdatePriority();
  187. }
  188. if (active_transaction_ == transaction) {
  189. active_transaction_ = nullptr;
  190. } else {
  191. // If waiting for read, remove it from the map.
  192. waiting_for_read_.erase(transaction);
  193. }
  194. return return_it;
  195. }
  196. void HttpCache::Writers::UpdatePriority() {
  197. // Get the current highest priority.
  198. RequestPriority current_highest = MINIMUM_PRIORITY;
  199. for (auto& writer : all_writers_) {
  200. Transaction* transaction = writer.first;
  201. current_highest = std::max(transaction->priority(), current_highest);
  202. }
  203. if (priority_ != current_highest) {
  204. if (network_transaction_)
  205. network_transaction_->SetPriority(current_highest);
  206. priority_ = current_highest;
  207. }
  208. }
  209. void HttpCache::Writers::CloseConnectionOnDestruction() {
  210. if (network_transaction_)
  211. network_transaction_->CloseConnectionOnDestruction();
  212. }
  213. bool HttpCache::Writers::ContainsOnlyIdleWriters() const {
  214. return waiting_for_read_.empty() && !active_transaction_;
  215. }
  216. bool HttpCache::Writers::CanAddWriters(ParallelWritingPattern* reason) {
  217. *reason = parallel_writing_pattern_;
  218. if (all_writers_.empty())
  219. return true;
  220. return !is_exclusive_ && !network_read_only_;
  221. }
  222. void HttpCache::Writers::ProcessFailure(int error) {
  223. // Notify waiting_for_read_ of the failure. Tasks will be posted for all the
  224. // transactions.
  225. CompleteWaitingForReadTransactions(error);
  226. // Idle readers should fail when Read is invoked on them.
  227. RemoveIdleWriters(error);
  228. }
  229. void HttpCache::Writers::TruncateEntry() {
  230. DCHECK(ShouldTruncate());
  231. auto data = base::MakeRefCounted<PickledIOBuffer>();
  232. response_info_truncation_.Persist(data->pickle(),
  233. true /* skip_transient_headers*/,
  234. true /* response_truncated */);
  235. data->Done();
  236. io_buf_len_ = data->pickle()->size();
  237. entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(), io_buf_len_,
  238. base::DoNothing(), true);
  239. }
  240. bool HttpCache::Writers::ShouldTruncate() {
  241. // Don't set the flag for sparse entries or for entries that cannot be
  242. // resumed.
  243. if (!should_keep_entry_ || partial_do_not_truncate_)
  244. return false;
  245. // Check the response headers for strong validators.
  246. // Note that if this is a 206, content-length was already fixed after calling
  247. // PartialData::ResponseHeadersOK().
  248. if (response_info_truncation_.headers->GetContentLength() <= 0 ||
  249. response_info_truncation_.headers->HasHeaderValue("Accept-Ranges",
  250. "none") ||
  251. !response_info_truncation_.headers->HasStrongValidators()) {
  252. should_keep_entry_ = false;
  253. return false;
  254. }
  255. // Double check that there is something worth keeping.
  256. int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
  257. if (!current_size) {
  258. should_keep_entry_ = false;
  259. return false;
  260. }
  261. if (response_info_truncation_.headers->HasHeader("Content-Encoding")) {
  262. should_keep_entry_ = false;
  263. return false;
  264. }
  265. int64_t content_length =
  266. response_info_truncation_.headers->GetContentLength();
  267. if (content_length >= 0 && content_length <= current_size)
  268. return false;
  269. return true;
  270. }
  271. LoadState HttpCache::Writers::GetLoadState() const {
  272. if (network_transaction_)
  273. return network_transaction_->GetLoadState();
  274. return LOAD_STATE_IDLE;
  275. }
  276. HttpCache::Writers::WaitingForRead::WaitingForRead(
  277. scoped_refptr<IOBuffer> buf,
  278. int len,
  279. CompletionOnceCallback consumer_callback)
  280. : read_buf(std::move(buf)),
  281. read_buf_len(len),
  282. callback(std::move(consumer_callback)) {
  283. DCHECK(read_buf);
  284. DCHECK_GT(len, 0);
  285. DCHECK(!callback.is_null());
  286. }
  287. HttpCache::Writers::WaitingForRead::~WaitingForRead() = default;
  288. HttpCache::Writers::WaitingForRead::WaitingForRead(WaitingForRead&&) = default;
  289. int HttpCache::Writers::DoLoop(int result) {
  290. DCHECK_NE(State::UNSET, next_state_);
  291. DCHECK_NE(State::NONE, next_state_);
  292. int rv = result;
  293. do {
  294. State state = next_state_;
  295. next_state_ = State::UNSET;
  296. switch (state) {
  297. case State::NETWORK_READ:
  298. DCHECK_EQ(OK, rv);
  299. rv = DoNetworkRead();
  300. break;
  301. case State::NETWORK_READ_COMPLETE:
  302. rv = DoNetworkReadComplete(rv);
  303. break;
  304. case State::CACHE_WRITE_DATA:
  305. rv = DoCacheWriteData(rv);
  306. break;
  307. case State::CACHE_WRITE_DATA_COMPLETE:
  308. rv = DoCacheWriteDataComplete(rv);
  309. break;
  310. case State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE:
  311. // `rv` is bytes here.
  312. DCHECK_EQ(0, rv);
  313. rv = DoMarkSingleKeyedCacheEntryUnusable();
  314. break;
  315. case State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE:
  316. rv = DoMarkSingleKeyedCacheEntryUnusableComplete(rv);
  317. break;
  318. case State::UNSET:
  319. NOTREACHED() << "bad state";
  320. rv = ERR_FAILED;
  321. break;
  322. case State::NONE:
  323. // Do Nothing.
  324. break;
  325. }
  326. } while (next_state_ != State::NONE && rv != ERR_IO_PENDING);
  327. if (next_state_ != State::NONE) {
  328. if (rv != ERR_IO_PENDING && !callback_.is_null()) {
  329. std::move(callback_).Run(rv);
  330. }
  331. return rv;
  332. }
  333. // Save the callback as |this| may be destroyed when |cache_callback_| is run.
  334. // Note that |callback_| is intentionally reset even if it is not run.
  335. CompletionOnceCallback callback = std::move(callback_);
  336. read_buf_ = nullptr;
  337. DCHECK(!all_writers_.empty() || cache_callback_);
  338. if (cache_callback_)
  339. std::move(cache_callback_).Run();
  340. // |this| may have been destroyed in the |cache_callback_|.
  341. if (rv != ERR_IO_PENDING && !callback.is_null())
  342. std::move(callback).Run(rv);
  343. return rv;
  344. }
  345. int HttpCache::Writers::DoNetworkRead() {
  346. DCHECK(network_transaction_);
  347. next_state_ = State::NETWORK_READ_COMPLETE;
  348. // TODO(https://crbug.com/778641): This is a partial mitigation and an attempt
  349. // to gather more info)
  350. if (!network_transaction_) {
  351. static bool reported = false;
  352. if (!reported) {
  353. reported = true;
  354. base::debug::ScopedCrashKeyString key_info(
  355. GetCacheKeyCrashKey(), active_transaction_
  356. ? active_transaction_->key()
  357. : "(no transaction)");
  358. base::debug::ScopedCrashKeyString flags_info(
  359. GetTransactionFlagsCrashKey(),
  360. active_transaction_
  361. ? base::StringPrintf(
  362. "mth=%s/m=%d/p=%d/t=%d/ex=%d/tc=%d/par=%d/pri=%d/nw=%zu",
  363. active_transaction_->method().c_str(),
  364. static_cast<int>(active_transaction_->mode()),
  365. static_cast<int>(active_transaction_->partial() != nullptr),
  366. static_cast<int>(active_transaction_->is_truncated()),
  367. static_cast<int>(IsExclusive()), GetTransactionsCount(),
  368. static_cast<int>(parallel_writing_pattern_),
  369. static_cast<int>(priority_), all_writers_.size())
  370. : "(no transaction)");
  371. base::debug::DumpWithoutCrashing();
  372. }
  373. return ERR_FAILED;
  374. }
  375. CompletionOnceCallback io_callback = base::BindOnce(
  376. &HttpCache::Writers::OnIOComplete, weak_factory_.GetWeakPtr());
  377. return network_transaction_->Read(read_buf_.get(), io_buf_len_,
  378. std::move(io_callback));
  379. }
  380. int HttpCache::Writers::DoNetworkReadComplete(int result) {
  381. if (result < 0) {
  382. next_state_ = State::NONE;
  383. OnNetworkReadFailure(result);
  384. return result;
  385. }
  386. next_state_ = State::CACHE_WRITE_DATA;
  387. return result;
  388. }
  389. void HttpCache::Writers::OnNetworkReadFailure(int result) {
  390. ProcessFailure(result);
  391. if (active_transaction_)
  392. EraseTransaction(active_transaction_, result);
  393. active_transaction_ = nullptr;
  394. if (ShouldTruncate())
  395. TruncateEntry();
  396. SetCacheCallback(false, TransactionSet());
  397. }
  398. int HttpCache::Writers::DoCacheWriteData(int num_bytes) {
  399. next_state_ = State::CACHE_WRITE_DATA_COMPLETE;
  400. write_len_ = num_bytes;
  401. if (!num_bytes || network_read_only_)
  402. return num_bytes;
  403. int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
  404. CompletionOnceCallback io_callback = base::BindOnce(
  405. &HttpCache::Writers::OnIOComplete, weak_factory_.GetWeakPtr());
  406. int rv = 0;
  407. PartialData* partial = nullptr;
  408. // The active transaction must be alive if this is a partial request, as
  409. // partial requests are exclusive and hence will always be the active
  410. // transaction.
  411. // TODO(shivanisha): When partial requests support parallel writing, this
  412. // assumption will not be true.
  413. if (active_transaction_)
  414. partial = all_writers_.find(active_transaction_)->second.partial;
  415. if (!partial) {
  416. rv = entry_->disk_entry->WriteData(kResponseContentIndex, current_size,
  417. read_buf_.get(), num_bytes,
  418. std::move(io_callback), true);
  419. } else {
  420. rv = partial->CacheWrite(entry_->GetEntry(), read_buf_.get(), num_bytes,
  421. std::move(io_callback));
  422. }
  423. return rv;
  424. }
  425. int HttpCache::Writers::DoCacheWriteDataComplete(int result) {
  426. DCHECK(!all_writers_.empty());
  427. next_state_ = State::NONE;
  428. if (checksum_) {
  429. if (write_len_ > 0) {
  430. checksum_->Update(read_buf_->data(), write_len_);
  431. } else {
  432. // The write to the cache may have failed if result < 0, but even in that
  433. // case we want to check whether the data we've read from the network is
  434. // valid or not.
  435. CHECK(active_transaction_);
  436. if (!active_transaction_->ResponseChecksumMatches(std::move(checksum_))) {
  437. next_state_ = State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE;
  438. }
  439. }
  440. }
  441. if (result != write_len_) {
  442. // Note that it is possible for cache write to fail if the size of the file
  443. // exceeds the per-file limit.
  444. OnCacheWriteFailure();
  445. // |active_transaction_| can continue reading from the network.
  446. result = write_len_;
  447. } else {
  448. OnDataReceived(result);
  449. }
  450. return result;
  451. }
  452. int HttpCache::Writers::DoMarkSingleKeyedCacheEntryUnusable() {
  453. // `response_info_truncation_` is not actually truncated.
  454. // TODO(ricea): Maybe change the name of the member?
  455. response_info_truncation_.single_keyed_cache_entry_unusable = true;
  456. next_state_ = State::MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE;
  457. // Update cache metadata. This is a subset of what
  458. // HttpCache::Transaction::WriteResponseInfoToEntry does.
  459. auto data = base::MakeRefCounted<PickledIOBuffer>();
  460. response_info_truncation_.Persist(data->pickle(),
  461. /*skip_transient_headers=*/true,
  462. /*response_truncated=*/false);
  463. data->Done();
  464. io_buf_len_ = data->pickle()->size();
  465. CompletionOnceCallback io_callback = base::BindOnce(
  466. &HttpCache::Writers::OnIOComplete, weak_factory_.GetWeakPtr());
  467. return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(),
  468. io_buf_len_, std::move(io_callback),
  469. true);
  470. }
  471. int HttpCache::Writers::DoMarkSingleKeyedCacheEntryUnusableComplete(
  472. int result) {
  473. next_state_ = State::NONE;
  474. if (result < 0) {
  475. OnCacheWriteFailure();
  476. }
  477. // DoLoop() wants the size of the data write, not the size of the metadata
  478. // write.
  479. return write_len_;
  480. }
  481. void HttpCache::Writers::OnDataReceived(int result) {
  482. DCHECK(!all_writers_.empty());
  483. auto it = all_writers_.find(active_transaction_);
  484. bool is_partial =
  485. active_transaction_ != nullptr && it->second.partial != nullptr;
  486. // Partial transaction will process the result, return from here.
  487. // This is done because partial requests handling require an awareness of both
  488. // headers and body state machines as they might have to go to the headers
  489. // phase for the next range, so it cannot be completely handled here.
  490. if (is_partial) {
  491. active_transaction_ = nullptr;
  492. return;
  493. }
  494. if (result == 0) {
  495. // Check if the response is actually completed or if not, attempt to mark
  496. // the entry as truncated in OnNetworkReadFailure.
  497. int current_size = entry_->disk_entry->GetDataSize(kResponseContentIndex);
  498. DCHECK(network_transaction_);
  499. const HttpResponseInfo* response_info =
  500. network_transaction_->GetResponseInfo();
  501. int64_t content_length = response_info->headers->GetContentLength();
  502. if (content_length >= 0 && content_length > current_size) {
  503. OnNetworkReadFailure(result);
  504. return;
  505. }
  506. if (active_transaction_)
  507. EraseTransaction(active_transaction_, result);
  508. active_transaction_ = nullptr;
  509. CompleteWaitingForReadTransactions(write_len_);
  510. // Invoke entry processing.
  511. DCHECK(ContainsOnlyIdleWriters());
  512. TransactionSet make_readers;
  513. for (auto& writer : all_writers_)
  514. make_readers.insert(writer.first);
  515. all_writers_.clear();
  516. SetCacheCallback(true, make_readers);
  517. return;
  518. }
  519. // Notify waiting_for_read_. Tasks will be posted for all the
  520. // transactions.
  521. CompleteWaitingForReadTransactions(write_len_);
  522. active_transaction_ = nullptr;
  523. }
  524. void HttpCache::Writers::OnCacheWriteFailure() {
  525. DLOG(ERROR) << "failed to write response data to cache";
  526. ProcessFailure(ERR_CACHE_WRITE_FAILURE);
  527. // Now writers will only be reading from the network.
  528. network_read_only_ = true;
  529. active_transaction_ = nullptr;
  530. should_keep_entry_ = false;
  531. if (all_writers_.empty()) {
  532. SetCacheCallback(false, TransactionSet());
  533. } else {
  534. cache_->WritersDoomEntryRestartTransactions(entry_);
  535. }
  536. }
  537. void HttpCache::Writers::CompleteWaitingForReadTransactions(int result) {
  538. for (auto it = waiting_for_read_.begin(); it != waiting_for_read_.end();) {
  539. Transaction* transaction = it->first;
  540. int callback_result = result;
  541. if (result >= 0) { // success
  542. // Save the data in the waiting transaction's read buffer.
  543. it->second.write_len = std::min(it->second.read_buf_len, result);
  544. memcpy(it->second.read_buf->data(), read_buf_->data(),
  545. it->second.write_len);
  546. callback_result = it->second.write_len;
  547. }
  548. // Post task to notify transaction.
  549. base::ThreadTaskRunnerHandle::Get()->PostTask(
  550. FROM_HERE,
  551. base::BindOnce(std::move(it->second.callback), callback_result));
  552. it = waiting_for_read_.erase(it);
  553. // If its response completion or failure, this transaction needs to be
  554. // removed from writers.
  555. if (result <= 0)
  556. EraseTransaction(transaction, result);
  557. }
  558. }
  559. void HttpCache::Writers::RemoveIdleWriters(int result) {
  560. // Since this is only for idle transactions, waiting_for_read_
  561. // should be empty.
  562. DCHECK(waiting_for_read_.empty());
  563. for (auto it = all_writers_.begin(); it != all_writers_.end();) {
  564. Transaction* transaction = it->first;
  565. if (transaction == active_transaction_) {
  566. it++;
  567. continue;
  568. }
  569. it = EraseTransaction(it, result);
  570. }
  571. }
  572. void HttpCache::Writers::SetCacheCallback(bool success,
  573. const TransactionSet& make_readers) {
  574. DCHECK(!cache_callback_);
  575. cache_callback_ = base::BindOnce(&HttpCache::WritersDoneWritingToEntry,
  576. cache_->GetWeakPtr(), entry_, success,
  577. should_keep_entry_, make_readers);
  578. }
  579. void HttpCache::Writers::OnIOComplete(int result) {
  580. DoLoop(result);
  581. }
  582. } // namespace net