• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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/http/http_cache_transaction.h"
6 
7 #include "base/feature_list.h"
8 #include "base/task/single_thread_task_runner.h"
9 #include "build/build_config.h"  // For IS_POSIX
10 
11 #if BUILDFLAG(IS_POSIX)
12 #include <unistd.h>
13 #endif
14 
15 #include <algorithm>
16 #include <memory>
17 #include <string>
18 #include <type_traits>
19 #include <utility>
20 
21 #include "base/auto_reset.h"
22 #include "base/compiler_specific.h"
23 #include "base/containers/fixed_flat_set.h"
24 #include "base/cxx17_backports.h"
25 #include "base/format_macros.h"
26 #include "base/functional/bind.h"
27 #include "base/functional/callback_helpers.h"
28 #include "base/location.h"
29 #include "base/memory/raw_ptr_exclusion.h"
30 #include "base/metrics/histogram_functions.h"
31 #include "base/metrics/histogram_macros.h"
32 #include "base/power_monitor/power_monitor.h"
33 #include "base/strings/string_number_conversions.h"  // For HexEncode.
34 #include "base/strings/string_piece.h"
35 #include "base/strings/string_util.h"  // For EqualsCaseInsensitiveASCII.
36 #include "base/task/single_thread_task_runner.h"
37 #include "base/time/clock.h"
38 #include "base/trace_event/base_tracing.h"
39 #include "base/trace_event/common/trace_event_common.h"
40 #include "base/values.h"
41 #include "crypto/secure_hash.h"
42 #include "crypto/sha2.h"
43 #include "net/base/auth.h"
44 #include "net/base/cache_metrics.h"
45 #include "net/base/features.h"
46 #include "net/base/load_flags.h"
47 #include "net/base/load_timing_info.h"
48 #include "net/base/trace_constants.h"
49 #include "net/base/tracing.h"
50 #include "net/base/transport_info.h"
51 #include "net/base/upload_data_stream.h"
52 #include "net/cert/cert_status_flags.h"
53 #include "net/cert/x509_certificate.h"
54 #include "net/disk_cache/disk_cache.h"
55 #include "net/http/http_cache_writers.h"
56 #include "net/http/http_log_util.h"
57 #include "net/http/http_network_session.h"
58 #include "net/http/http_request_info.h"
59 #include "net/http/http_response_headers.h"
60 #include "net/http/http_status_code.h"
61 #include "net/http/http_util.h"
62 #include "net/http/webfonts_histogram.h"
63 #include "net/log/net_log_event_type.h"
64 #include "net/ssl/ssl_cert_request_info.h"
65 #include "net/ssl/ssl_config_service.h"
66 
67 using base::Time;
68 using base::TimeTicks;
69 
70 namespace net {
71 
72 using CacheEntryStatus = HttpResponseInfo::CacheEntryStatus;
73 
74 namespace {
75 
76 constexpr base::TimeDelta kStaleRevalidateTimeout = base::Seconds(60);
77 
GetNextTraceId(HttpCache * cache)78 uint64_t GetNextTraceId(HttpCache* cache) {
79   static uint32_t sNextTraceId = 0;
80 
81   DCHECK(cache);
82   return (reinterpret_cast<uint64_t>(cache) << 32) | sNextTraceId++;
83 }
84 
85 // From http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-21#section-6
86 //      a "non-error response" is one with a 2xx (Successful) or 3xx
87 //      (Redirection) status code.
NonErrorResponse(int status_code)88 bool NonErrorResponse(int status_code) {
89   int status_code_range = status_code / 100;
90   return status_code_range == 2 || status_code_range == 3;
91 }
92 
IsOnBatteryPower()93 bool IsOnBatteryPower() {
94   if (base::PowerMonitor::IsInitialized())
95     return base::PowerMonitor::IsOnBatteryPower();
96   return false;
97 }
98 
99 enum ExternallyConditionalizedType {
100   EXTERNALLY_CONDITIONALIZED_CACHE_REQUIRES_VALIDATION,
101   EXTERNALLY_CONDITIONALIZED_CACHE_USABLE,
102   EXTERNALLY_CONDITIONALIZED_MISMATCHED_VALIDATORS,
103   EXTERNALLY_CONDITIONALIZED_MAX
104 };
105 
106 // These values are persisted to logs. Entries should not be renumbered and
107 // numeric values should never be reused.
108 enum class RestrictedPrefetchReused {
109   kNotReused = 0,
110   kReused = 1,
111   kMaxValue = kReused
112 };
113 
RecordPervasivePayloadIndex(const char * histogram_name,int index)114 void RecordPervasivePayloadIndex(const char* histogram_name, int index) {
115   if (index != -1) {
116     base::UmaHistogramCustomCounts(histogram_name, index, 1, 323, 323);
117   }
118 }
119 
ShouldByPassCacheForFirstPartySets(const absl::optional<int64_t> & clear_at_run_id,const absl::optional<int64_t> & written_at_run_id)120 bool ShouldByPassCacheForFirstPartySets(
121     const absl::optional<int64_t>& clear_at_run_id,
122     const absl::optional<int64_t>& written_at_run_id) {
123   return clear_at_run_id.has_value() &&
124          (!written_at_run_id.has_value() ||
125           written_at_run_id.value() < clear_at_run_id.value());
126 }
127 }  // namespace
128 
129 #define CACHE_STATUS_HISTOGRAMS(type)                                      \
130   UMA_HISTOGRAM_ENUMERATION("HttpCache.Pattern" type, cache_entry_status_, \
131                             CacheEntryStatus::ENTRY_MAX)
132 
133 #define IS_NO_STORE_HISTOGRAMS(type, is_no_store) \
134   base::UmaHistogramBoolean("HttpCache.IsNoStore" type, is_no_store)
135 
136 struct HeaderNameAndValue {
137   const char* name;
138   const char* value;
139 };
140 
141 // If the request includes one of these request headers, then avoid caching
142 // to avoid getting confused.
143 static const HeaderNameAndValue kPassThroughHeaders[] = {
144     {"if-unmodified-since", nullptr},  // causes unexpected 412s
145     {"if-match", nullptr},             // causes unexpected 412s
146     {"if-range", nullptr},
147     {nullptr, nullptr}};
148 
149 struct ValidationHeaderInfo {
150   const char* request_header_name;
151   const char* related_response_header_name;
152 };
153 
154 static const ValidationHeaderInfo kValidationHeaders[] = {
155   { "if-modified-since", "last-modified" },
156   { "if-none-match", "etag" },
157 };
158 
159 // If the request includes one of these request headers, then avoid reusing
160 // our cached copy if any.
161 static const HeaderNameAndValue kForceFetchHeaders[] = {
162     {"cache-control", "no-cache"},
163     {"pragma", "no-cache"},
164     {nullptr, nullptr}};
165 
166 // If the request includes one of these request headers, then force our
167 // cached copy (if any) to be revalidated before reusing it.
168 static const HeaderNameAndValue kForceValidateHeaders[] = {
169     {"cache-control", "max-age=0"},
170     {nullptr, nullptr}};
171 
HeaderMatches(const HttpRequestHeaders & headers,const HeaderNameAndValue * search)172 static bool HeaderMatches(const HttpRequestHeaders& headers,
173                           const HeaderNameAndValue* search) {
174   for (; search->name; ++search) {
175     std::string header_value;
176     if (!headers.GetHeader(search->name, &header_value))
177       continue;
178 
179     if (!search->value)
180       return true;
181 
182     HttpUtil::ValuesIterator v(header_value.begin(), header_value.end(), ',');
183     while (v.GetNext()) {
184       if (base::EqualsCaseInsensitiveASCII(v.value_piece(), search->value))
185         return true;
186     }
187   }
188   return false;
189 }
190 
191 //-----------------------------------------------------------------------------
192 
Transaction(RequestPriority priority,HttpCache * cache)193 HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache)
194     : trace_id_(GetNextTraceId(cache)),
195       priority_(priority),
196       cache_(cache->GetWeakPtr()) {
197   TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::Transaction",
198                          TRACE_ID_LOCAL(trace_id_), TRACE_EVENT_FLAG_FLOW_OUT,
199                          "priority", RequestPriorityToString(priority));
200   static_assert(HttpCache::Transaction::kNumValidationHeaders ==
201                     std::size(kValidationHeaders),
202                 "invalid number of validation headers");
203 
204   io_callback_ = base::BindRepeating(&Transaction::OnIOComplete,
205                                      weak_factory_.GetWeakPtr());
206 }
207 
~Transaction()208 HttpCache::Transaction::~Transaction() {
209   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::~Transaction",
210                          TRACE_ID_LOCAL(trace_id_), TRACE_EVENT_FLAG_FLOW_IN);
211   RecordHistograms();
212 
213   // We may have to issue another IO, but we should never invoke the callback_
214   // after this point.
215   callback_.Reset();
216 
217   if (cache_) {
218     if (entry_) {
219       DoneWithEntry(false /* entry_is_complete */);
220     } else if (cache_pending_) {
221       cache_->RemovePendingTransaction(this);
222     }
223   }
224 }
225 
mode() const226 HttpCache::Transaction::Mode HttpCache::Transaction::mode() const {
227   return mode_;
228 }
229 
GetWriterLoadState() const230 LoadState HttpCache::Transaction::GetWriterLoadState() const {
231   const HttpTransaction* transaction = network_transaction();
232   if (transaction)
233     return transaction->GetLoadState();
234   if (entry_ || !request_)
235     return LOAD_STATE_IDLE;
236   return LOAD_STATE_WAITING_FOR_CACHE;
237 }
238 
net_log() const239 const NetLogWithSource& HttpCache::Transaction::net_log() const {
240   return net_log_;
241 }
242 
Start(const HttpRequestInfo * request,CompletionOnceCallback callback,const NetLogWithSource & net_log)243 int HttpCache::Transaction::Start(const HttpRequestInfo* request,
244                                   CompletionOnceCallback callback,
245                                   const NetLogWithSource& net_log) {
246   DCHECK(request);
247   DCHECK(request->IsConsistent());
248   DCHECK(!callback.is_null());
249   TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::Start",
250                          TRACE_ID_LOCAL(trace_id_),
251                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
252                          "url", request->url.spec());
253 
254   // Ensure that we only have one asynchronous call at a time.
255   DCHECK(callback_.is_null());
256   DCHECK(!reading_);
257   DCHECK(!network_trans_.get());
258   DCHECK(!entry_);
259   DCHECK_EQ(next_state_, STATE_NONE);
260 
261   if (!cache_.get())
262     return ERR_UNEXPECTED;
263 
264   initial_request_ = request;
265   SetRequest(net_log);
266 
267   // We have to wait until the backend is initialized so we start the SM.
268   next_state_ = STATE_GET_BACKEND;
269   int rv = DoLoop(OK);
270 
271   // Setting this here allows us to check for the existence of a callback_ to
272   // determine if we are still inside Start.
273   if (rv == ERR_IO_PENDING)
274     callback_ = std::move(callback);
275 
276   return rv;
277 }
278 
RestartIgnoringLastError(CompletionOnceCallback callback)279 int HttpCache::Transaction::RestartIgnoringLastError(
280     CompletionOnceCallback callback) {
281   DCHECK(!callback.is_null());
282 
283   // Ensure that we only have one asynchronous call at a time.
284   DCHECK(callback_.is_null());
285 
286   if (!cache_.get())
287     return ERR_UNEXPECTED;
288 
289   int rv = RestartNetworkRequest();
290 
291   if (rv == ERR_IO_PENDING)
292     callback_ = std::move(callback);
293 
294   return rv;
295 }
296 
RestartWithCertificate(scoped_refptr<X509Certificate> client_cert,scoped_refptr<SSLPrivateKey> client_private_key,CompletionOnceCallback callback)297 int HttpCache::Transaction::RestartWithCertificate(
298     scoped_refptr<X509Certificate> client_cert,
299     scoped_refptr<SSLPrivateKey> client_private_key,
300     CompletionOnceCallback callback) {
301   DCHECK(!callback.is_null());
302 
303   // Ensure that we only have one asynchronous call at a time.
304   DCHECK(callback_.is_null());
305 
306   if (!cache_.get())
307     return ERR_UNEXPECTED;
308 
309   int rv = RestartNetworkRequestWithCertificate(std::move(client_cert),
310                                                 std::move(client_private_key));
311 
312   if (rv == ERR_IO_PENDING)
313     callback_ = std::move(callback);
314 
315   return rv;
316 }
317 
RestartWithAuth(const AuthCredentials & credentials,CompletionOnceCallback callback)318 int HttpCache::Transaction::RestartWithAuth(const AuthCredentials& credentials,
319                                             CompletionOnceCallback callback) {
320   DCHECK(auth_response_.headers.get());
321   DCHECK(!callback.is_null());
322 
323   // Ensure that we only have one asynchronous call at a time.
324   DCHECK(callback_.is_null());
325 
326   if (!cache_.get())
327     return ERR_UNEXPECTED;
328 
329   // Clear the intermediate response since we are going to start over.
330   SetAuthResponse(HttpResponseInfo());
331 
332   int rv = RestartNetworkRequestWithAuth(credentials);
333 
334   if (rv == ERR_IO_PENDING)
335     callback_ = std::move(callback);
336 
337   return rv;
338 }
339 
IsReadyToRestartForAuth()340 bool HttpCache::Transaction::IsReadyToRestartForAuth() {
341   if (!network_trans_.get())
342     return false;
343   return network_trans_->IsReadyToRestartForAuth();
344 }
345 
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)346 int HttpCache::Transaction::Read(IOBuffer* buf,
347                                  int buf_len,
348                                  CompletionOnceCallback callback) {
349   TRACE_EVENT_WITH_FLOW1(
350       "net", "HttpCacheTransaction::Read", TRACE_ID_LOCAL(trace_id_),
351       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "buf_len", buf_len);
352 
353   DCHECK_EQ(next_state_, STATE_NONE);
354   DCHECK(buf);
355   // TODO(https://crbug.com/1335423): Change to DCHECK_GT() or remove after bug
356   // is fixed.
357   CHECK_GT(buf_len, 0);
358   DCHECK(!callback.is_null());
359 
360   DCHECK(callback_.is_null());
361 
362   if (!cache_.get())
363     return ERR_UNEXPECTED;
364 
365   // If we have an intermediate auth response at this point, then it means the
366   // user wishes to read the network response (the error page).  If there is a
367   // previous response in the cache then we should leave it intact.
368   if (auth_response_.headers.get() && mode_ != NONE) {
369     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
370     DCHECK(mode_ & WRITE);
371     bool stopped = StopCachingImpl(mode_ == READ_WRITE);
372     DCHECK(stopped);
373   }
374 
375   reading_ = true;
376   read_buf_ = buf;
377   read_buf_len_ = buf_len;
378   int rv = TransitionToReadingState();
379   if (rv != OK || next_state_ == STATE_NONE)
380     return rv;
381 
382   rv = DoLoop(OK);
383 
384   if (rv == ERR_IO_PENDING) {
385     DCHECK(callback_.is_null());
386     callback_ = std::move(callback);
387   }
388   return rv;
389 }
390 
TransitionToReadingState()391 int HttpCache::Transaction::TransitionToReadingState() {
392   if (!entry_) {
393     if (network_trans_) {
394       // This can happen when the request should be handled exclusively by
395       // the network layer (skipping the cache entirely using
396       // LOAD_DISABLE_CACHE) or there was an error during the headers phase
397       // due to which the transaction cannot write to the cache or the consumer
398       // is reading the auth response from the network.
399       // TODO(http://crbug.com/740947) to get rid of this state in future.
400       next_state_ = STATE_NETWORK_READ;
401 
402       return OK;
403     }
404 
405     // If there is no network, and no cache entry, then there is nothing to read
406     // from.
407     next_state_ = STATE_NONE;
408 
409     // An error state should be set for the next read, else this transaction
410     // should have been terminated once it reached this state. To assert we
411     // could dcheck that shared_writing_error_ is set to a valid error value but
412     // in some specific conditions (http://crbug.com/806344) it's possible that
413     // the consumer does an extra Read in which case the assert will fail.
414     return shared_writing_error_;
415   }
416 
417   // If entry_ is present, the transaction is either a member of entry_->writers
418   // or readers.
419   if (!InWriters()) {
420     // Since transaction is not a writer and we are in Read(), it must be a
421     // reader.
422     DCHECK(entry_->TransactionInReaders(this));
423     DCHECK(mode_ == READ || (mode_ == READ_WRITE && partial_));
424     next_state_ = STATE_CACHE_READ_DATA;
425     return OK;
426   }
427 
428   DCHECK(mode_ & WRITE || mode_ == NONE);
429 
430   // If it's a writer and it is partial then it may need to read from the cache
431   // or from the network based on whether network transaction is present or not.
432   if (partial_) {
433     if (entry_->writers->network_transaction())
434       next_state_ = STATE_NETWORK_READ_CACHE_WRITE;
435     else
436       next_state_ = STATE_CACHE_READ_DATA;
437     return OK;
438   }
439 
440   // Full request.
441   // If it's a writer and a full request then it may read from the cache if its
442   // offset is behind the current offset else from the network.
443   int disk_entry_size = entry_->GetEntry()->GetDataSize(kResponseContentIndex);
444   if (read_offset_ == disk_entry_size || entry_->writers->network_read_only()) {
445     next_state_ = STATE_NETWORK_READ_CACHE_WRITE;
446   } else {
447     DCHECK_LT(read_offset_, disk_entry_size);
448     next_state_ = STATE_CACHE_READ_DATA;
449   }
450   return OK;
451 }
452 
StopCaching()453 void HttpCache::Transaction::StopCaching() {
454   // We really don't know where we are now. Hopefully there is no operation in
455   // progress, but nothing really prevents this method to be called after we
456   // returned ERR_IO_PENDING. We cannot attempt to truncate the entry at this
457   // point because we need the state machine for that (and even if we are really
458   // free, that would be an asynchronous operation). In other words, keep the
459   // entry how it is (it will be marked as truncated at destruction), and let
460   // the next piece of code that executes know that we are now reading directly
461   // from the net.
462   if (cache_.get() && (mode_ & WRITE) && !is_sparse_ && !range_requested_ &&
463       network_transaction()) {
464     StopCachingImpl(false);
465   }
466 }
467 
GetTotalReceivedBytes() const468 int64_t HttpCache::Transaction::GetTotalReceivedBytes() const {
469   int64_t total_received_bytes = network_transaction_info_.total_received_bytes;
470   const HttpTransaction* transaction = GetOwnedOrMovedNetworkTransaction();
471   if (transaction)
472     total_received_bytes += transaction->GetTotalReceivedBytes();
473   return total_received_bytes;
474 }
475 
GetTotalSentBytes() const476 int64_t HttpCache::Transaction::GetTotalSentBytes() const {
477   int64_t total_sent_bytes = network_transaction_info_.total_sent_bytes;
478   const HttpTransaction* transaction = GetOwnedOrMovedNetworkTransaction();
479   if (transaction)
480     total_sent_bytes += transaction->GetTotalSentBytes();
481   return total_sent_bytes;
482 }
483 
DoneReading()484 void HttpCache::Transaction::DoneReading() {
485   if (cache_.get() && entry_) {
486     DCHECK_NE(mode_, UPDATE);
487     DoneWithEntry(true);
488   }
489 }
490 
GetResponseInfo() const491 const HttpResponseInfo* HttpCache::Transaction::GetResponseInfo() const {
492   // Null headers means we encountered an error or haven't a response yet
493   if (auth_response_.headers.get()) {
494     DCHECK_EQ(cache_entry_status_, auth_response_.cache_entry_status)
495         << "These must be in sync via SetResponse and SetAuthResponse.";
496     return &auth_response_;
497   }
498   // TODO(https://crbug.com/1219402): This should check in `response_`
499   return &response_;
500 }
501 
GetLoadState() const502 LoadState HttpCache::Transaction::GetLoadState() const {
503   // If there's no pending callback, the ball is not in the
504   // HttpCache::Transaction's court, whatever else may be going on.
505   if (!callback_)
506     return LOAD_STATE_IDLE;
507 
508   LoadState state = GetWriterLoadState();
509   if (state != LOAD_STATE_WAITING_FOR_CACHE)
510     return state;
511 
512   if (cache_.get())
513     return cache_->GetLoadStateForPendingTransaction(this);
514 
515   return LOAD_STATE_IDLE;
516 }
517 
SetQuicServerInfo(QuicServerInfo * quic_server_info)518 void HttpCache::Transaction::SetQuicServerInfo(
519     QuicServerInfo* quic_server_info) {}
520 
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const521 bool HttpCache::Transaction::GetLoadTimingInfo(
522     LoadTimingInfo* load_timing_info) const {
523   const HttpTransaction* transaction = GetOwnedOrMovedNetworkTransaction();
524   if (transaction)
525     return transaction->GetLoadTimingInfo(load_timing_info);
526 
527   if (network_transaction_info_.old_network_trans_load_timing) {
528     *load_timing_info =
529         *network_transaction_info_.old_network_trans_load_timing;
530     return true;
531   }
532 
533   if (first_cache_access_since_.is_null())
534     return false;
535 
536   // If the cache entry was opened, return that time.
537   load_timing_info->send_start = first_cache_access_since_;
538   // This time doesn't make much sense when reading from the cache, so just use
539   // the same time as send_start.
540   load_timing_info->send_end = first_cache_access_since_;
541   // Provide the time immediately before parsing a cached entry.
542   load_timing_info->receive_headers_start = read_headers_since_;
543   return true;
544 }
545 
GetRemoteEndpoint(IPEndPoint * endpoint) const546 bool HttpCache::Transaction::GetRemoteEndpoint(IPEndPoint* endpoint) const {
547   const HttpTransaction* transaction = GetOwnedOrMovedNetworkTransaction();
548   if (transaction)
549     return transaction->GetRemoteEndpoint(endpoint);
550 
551   if (!network_transaction_info_.old_remote_endpoint.address().empty()) {
552     *endpoint = network_transaction_info_.old_remote_endpoint;
553     return true;
554   }
555 
556   return false;
557 }
558 
PopulateNetErrorDetails(NetErrorDetails * details) const559 void HttpCache::Transaction::PopulateNetErrorDetails(
560     NetErrorDetails* details) const {
561   const HttpTransaction* transaction = GetOwnedOrMovedNetworkTransaction();
562   if (transaction)
563     return transaction->PopulateNetErrorDetails(details);
564   return;
565 }
566 
SetPriority(RequestPriority priority)567 void HttpCache::Transaction::SetPriority(RequestPriority priority) {
568   priority_ = priority;
569 
570   if (network_trans_)
571     network_trans_->SetPriority(priority_);
572 
573   if (InWriters()) {
574     DCHECK(!network_trans_ || partial_);
575     entry_->writers->UpdatePriority();
576   }
577 }
578 
SetWebSocketHandshakeStreamCreateHelper(WebSocketHandshakeStreamBase::CreateHelper * create_helper)579 void HttpCache::Transaction::SetWebSocketHandshakeStreamCreateHelper(
580     WebSocketHandshakeStreamBase::CreateHelper* create_helper) {
581   websocket_handshake_stream_base_create_helper_ = create_helper;
582 
583   // TODO(shivanisha). Since this function must be invoked before Start() as
584   // per the API header, a network transaction should not exist at that point.
585   HttpTransaction* transaction = network_transaction();
586   if (transaction)
587     transaction->SetWebSocketHandshakeStreamCreateHelper(create_helper);
588 }
589 
SetBeforeNetworkStartCallback(BeforeNetworkStartCallback callback)590 void HttpCache::Transaction::SetBeforeNetworkStartCallback(
591     BeforeNetworkStartCallback callback) {
592   DCHECK(!network_trans_);
593   before_network_start_callback_ = std::move(callback);
594 }
595 
SetConnectedCallback(const ConnectedCallback & callback)596 void HttpCache::Transaction::SetConnectedCallback(
597     const ConnectedCallback& callback) {
598   DCHECK(!network_trans_);
599   connected_callback_ = callback;
600 }
601 
SetRequestHeadersCallback(RequestHeadersCallback callback)602 void HttpCache::Transaction::SetRequestHeadersCallback(
603     RequestHeadersCallback callback) {
604   DCHECK(!network_trans_);
605   request_headers_callback_ = std::move(callback);
606 }
607 
SetResponseHeadersCallback(ResponseHeadersCallback callback)608 void HttpCache::Transaction::SetResponseHeadersCallback(
609     ResponseHeadersCallback callback) {
610   DCHECK(!network_trans_);
611   response_headers_callback_ = std::move(callback);
612 }
613 
SetEarlyResponseHeadersCallback(ResponseHeadersCallback callback)614 void HttpCache::Transaction::SetEarlyResponseHeadersCallback(
615     ResponseHeadersCallback callback) {
616   DCHECK(!network_trans_);
617   early_response_headers_callback_ = std::move(callback);
618 }
619 
ResumeNetworkStart()620 int HttpCache::Transaction::ResumeNetworkStart() {
621   if (network_trans_)
622     return network_trans_->ResumeNetworkStart();
623   return ERR_UNEXPECTED;
624 }
625 
GetConnectionAttempts() const626 ConnectionAttempts HttpCache::Transaction::GetConnectionAttempts() const {
627   ConnectionAttempts attempts;
628   const HttpTransaction* transaction = GetOwnedOrMovedNetworkTransaction();
629   if (transaction)
630     attempts = transaction->GetConnectionAttempts();
631 
632   attempts.insert(attempts.begin(),
633                   network_transaction_info_.old_connection_attempts.begin(),
634                   network_transaction_info_.old_connection_attempts.end());
635   return attempts;
636 }
637 
CloseConnectionOnDestruction()638 void HttpCache::Transaction::CloseConnectionOnDestruction() {
639   if (network_trans_) {
640     network_trans_->CloseConnectionOnDestruction();
641   } else if (InWriters()) {
642     entry_->writers->CloseConnectionOnDestruction();
643   }
644 }
645 
SetValidatingCannotProceed()646 void HttpCache::Transaction::SetValidatingCannotProceed() {
647   DCHECK(!reading_);
648   // Ensure this transaction is waiting for a callback.
649   DCHECK_NE(STATE_UNSET, next_state_);
650 
651   next_state_ = STATE_HEADERS_PHASE_CANNOT_PROCEED;
652   entry_ = nullptr;
653 }
654 
WriterAboutToBeRemovedFromEntry(int result)655 void HttpCache::Transaction::WriterAboutToBeRemovedFromEntry(int result) {
656   TRACE_EVENT_WITH_FLOW1(
657       "net", "HttpCacheTransaction::WriterAboutToBeRemovedFromEntry",
658       TRACE_ID_LOCAL(trace_id_),
659       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
660   // Since the transaction can no longer access the network transaction, save
661   // all network related info now.
662   if (moved_network_transaction_to_writers_ &&
663       entry_->writers->network_transaction()) {
664     SaveNetworkTransactionInfo(*(entry_->writers->network_transaction()));
665   }
666 
667   entry_ = nullptr;
668   mode_ = NONE;
669 
670   // Transactions in the midst of a Read call through writers will get any error
671   // code through the IO callback but for idle transactions/transactions reading
672   // from the cache, the error for a future Read must be stored here.
673   if (result < 0)
674     shared_writing_error_ = result;
675 }
676 
WriteModeTransactionAboutToBecomeReader()677 void HttpCache::Transaction::WriteModeTransactionAboutToBecomeReader() {
678   TRACE_EVENT_WITH_FLOW0(
679       "net", "HttpCacheTransaction::WriteModeTransactionAboutToBecomeReader",
680       TRACE_ID_LOCAL(trace_id_),
681       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
682   mode_ = READ;
683   if (moved_network_transaction_to_writers_ &&
684       entry_->writers->network_transaction()) {
685     SaveNetworkTransactionInfo(*(entry_->writers->network_transaction()));
686   }
687 }
688 
ResponseChecksumMatches(std::unique_ptr<crypto::SecureHash> checksum) const689 bool HttpCache::Transaction::ResponseChecksumMatches(
690     std::unique_ptr<crypto::SecureHash> checksum) const {
691   DCHECK(checksum);
692   uint8_t result[crypto::kSHA256Length];
693   checksum->Finish(result, crypto::kSHA256Length);
694   const std::string hex_result = base::HexEncode(result);
695   if (hex_result != request_->checksum) {
696     DVLOG(2) << "Pervasive payload checksum mismatch for \"" << request_->url
697              << "\": got " << hex_result << ", expected " << request_->checksum;
698     RecordPervasivePayloadIndex(
699         "Network.CacheTransparency2.MismatchedChecksums",
700         request_->pervasive_payloads_index_for_logging);
701     return false;
702   }
703   RecordPervasivePayloadIndex(
704       "Network.CacheTransparency2.SingleKeyedCacheIsUsed",
705       request_->pervasive_payloads_index_for_logging);
706   return true;
707 }
708 
AddDiskCacheWriteTime(base::TimeDelta elapsed)709 void HttpCache::Transaction::AddDiskCacheWriteTime(base::TimeDelta elapsed) {
710   total_disk_cache_write_time_ += elapsed;
711 }
712 
713 //-----------------------------------------------------------------------------
714 
715 // A few common patterns: (Foo* means Foo -> FooComplete)
716 //
717 // 1. Not-cached entry:
718 //   Start():
719 //   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
720 //   SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse ->
721 //   CacheWriteResponse* -> TruncateCachedData* -> PartialHeadersReceived ->
722 //   FinishHeaders*
723 //
724 //   Read():
725 //   NetworkReadCacheWrite*/CacheReadData* (if other writers are also writing to
726 //   the cache)
727 //
728 // 2. Cached entry, no validation:
729 //   Start():
730 //   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
731 //   CacheReadResponse* -> CacheDispatchValidation ->
732 //   BeginPartialCacheValidation() -> BeginCacheValidation() ->
733 //   ConnectedCallback* -> SetupEntryForRead() -> FinishHeaders*
734 //
735 //   Read():
736 //   CacheReadData*
737 //
738 // 3. Cached entry, validation (304):
739 //   Start():
740 //   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
741 //   CacheReadResponse* -> CacheDispatchValidation ->
742 //   BeginPartialCacheValidation() -> BeginCacheValidation() -> SendRequest* ->
743 //   SuccessfulSendRequest -> UpdateCachedResponse -> CacheWriteUpdatedResponse*
744 //   -> UpdateCachedResponseComplete -> OverwriteCachedResponse ->
745 //   PartialHeadersReceived -> FinishHeaders*
746 //
747 //   Read():
748 //   CacheReadData*
749 //
750 // 4. Cached entry, validation and replace (200):
751 //   Start():
752 //   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
753 //   CacheReadResponse* -> CacheDispatchValidation ->
754 //   BeginPartialCacheValidation() -> BeginCacheValidation() -> SendRequest* ->
755 //   SuccessfulSendRequest -> OverwriteCachedResponse -> CacheWriteResponse* ->
756 //   DoTruncateCachedData* -> PartialHeadersReceived -> FinishHeaders*
757 //
758 //   Read():
759 //   NetworkReadCacheWrite*/CacheReadData* (if other writers are also writing to
760 //   the cache)
761 //
762 // 5. Sparse entry, partially cached, byte range request:
763 //   Start():
764 //   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
765 //   CacheReadResponse* -> CacheDispatchValidation ->
766 //   BeginPartialCacheValidation() -> CacheQueryData* ->
767 //   ValidateEntryHeadersAndContinue() -> StartPartialCacheValidation ->
768 //   CompletePartialCacheValidation -> BeginCacheValidation() -> SendRequest* ->
769 //   SuccessfulSendRequest -> UpdateCachedResponse -> CacheWriteUpdatedResponse*
770 //   -> UpdateCachedResponseComplete -> OverwriteCachedResponse ->
771 //   PartialHeadersReceived -> FinishHeaders*
772 //
773 //   Read() 1:
774 //   NetworkReadCacheWrite*
775 //
776 //   Read() 2:
777 //   NetworkReadCacheWrite* -> StartPartialCacheValidation ->
778 //   CompletePartialCacheValidation -> ConnectedCallback* -> CacheReadData*
779 //
780 //   Read() 3:
781 //   CacheReadData* -> StartPartialCacheValidation ->
782 //   CompletePartialCacheValidation -> BeginCacheValidation() -> SendRequest* ->
783 //   SuccessfulSendRequest -> UpdateCachedResponse* -> OverwriteCachedResponse
784 //   -> PartialHeadersReceived -> NetworkReadCacheWrite*
785 //
786 // 6. HEAD. Not-cached entry:
787 //   Pass through. Don't save a HEAD by itself.
788 //   Start():
789 //   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> SendRequest*
790 //
791 // 7. HEAD. Cached entry, no validation:
792 //   Start():
793 //   The same flow as for a GET request (example #2)
794 //
795 //   Read():
796 //   CacheReadData (returns 0)
797 //
798 // 8. HEAD. Cached entry, validation (304):
799 //   The request updates the stored headers.
800 //   Start(): Same as for a GET request (example #3)
801 //
802 //   Read():
803 //   CacheReadData (returns 0)
804 //
805 // 9. HEAD. Cached entry, validation and replace (200):
806 //   Pass through. The request dooms the old entry, as a HEAD won't be stored by
807 //   itself.
808 //   Start():
809 //   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
810 //   CacheReadResponse* -> CacheDispatchValidation ->
811 //   BeginPartialCacheValidation() -> BeginCacheValidation() -> SendRequest* ->
812 //   SuccessfulSendRequest -> OverwriteCachedResponse -> FinishHeaders*
813 //
814 // 10. HEAD. Sparse entry, partially cached:
815 //   Serve the request from the cache, as long as it doesn't require
816 //   revalidation. Ignore missing ranges when deciding to revalidate. If the
817 //   entry requires revalidation, ignore the whole request and go to full pass
818 //   through (the result of the HEAD request will NOT update the entry).
819 //
820 //   Start(): Basically the same as example 7, as we never create a partial_
821 //   object for this request.
822 //
823 // 11. Prefetch, not-cached entry:
824 //   The same as example 1. The "unused_since_prefetch" bit is stored as true in
825 //   UpdateCachedResponse.
826 //
827 // 12. Prefetch, cached entry:
828 //   Like examples 2-4, only CacheWriteUpdatedPrefetchResponse* is inserted
829 //   between CacheReadResponse* and CacheDispatchValidation if the
830 //   unused_since_prefetch bit is unset.
831 //
832 // 13. Cached entry less than 5 minutes old, unused_since_prefetch is true:
833 //   Skip validation, similar to example 2.
834 //   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
835 //   CacheReadResponse* -> CacheToggleUnusedSincePrefetch* ->
836 //   CacheDispatchValidation -> BeginPartialCacheValidation() ->
837 //   BeginCacheValidation() -> ConnectedCallback* -> SetupEntryForRead() ->
838 //   FinishHeaders*
839 //
840 //   Read():
841 //   CacheReadData*
842 //
843 // 14. Cached entry more than 5 minutes old, unused_since_prefetch is true:
844 //   Like examples 2-4, only CacheToggleUnusedSincePrefetch* is inserted between
845 //   CacheReadResponse* and CacheDispatchValidation.
DoLoop(int result)846 int HttpCache::Transaction::DoLoop(int result) {
847   DCHECK_NE(STATE_UNSET, next_state_);
848   DCHECK_NE(STATE_NONE, next_state_);
849   DCHECK(!in_do_loop_);
850 
851   int rv = result;
852   State state = next_state_;
853   do {
854     state = next_state_;
855     next_state_ = STATE_UNSET;
856     base::AutoReset<bool> scoped_in_do_loop(&in_do_loop_, true);
857 
858     switch (state) {
859       case STATE_GET_BACKEND:
860         DCHECK_EQ(OK, rv);
861         rv = DoGetBackend();
862         break;
863       case STATE_GET_BACKEND_COMPLETE:
864         rv = DoGetBackendComplete(rv);
865         break;
866       case STATE_INIT_ENTRY:
867         DCHECK_EQ(OK, rv);
868         rv = DoInitEntry();
869         break;
870       case STATE_OPEN_OR_CREATE_ENTRY:
871         DCHECK_EQ(OK, rv);
872         rv = DoOpenOrCreateEntry();
873         break;
874       case STATE_OPEN_OR_CREATE_ENTRY_COMPLETE:
875         rv = DoOpenOrCreateEntryComplete(rv);
876         break;
877       case STATE_DOOM_ENTRY:
878         DCHECK_EQ(OK, rv);
879         rv = DoDoomEntry();
880         break;
881       case STATE_DOOM_ENTRY_COMPLETE:
882         rv = DoDoomEntryComplete(rv);
883         break;
884       case STATE_CREATE_ENTRY:
885         DCHECK_EQ(OK, rv);
886         rv = DoCreateEntry();
887         break;
888       case STATE_CREATE_ENTRY_COMPLETE:
889         rv = DoCreateEntryComplete(rv);
890         break;
891       case STATE_ADD_TO_ENTRY:
892         DCHECK_EQ(OK, rv);
893         rv = DoAddToEntry();
894         break;
895       case STATE_ADD_TO_ENTRY_COMPLETE:
896         rv = DoAddToEntryComplete(rv);
897         break;
898       case STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE:
899         rv = DoDoneHeadersAddToEntryComplete(rv);
900         break;
901       case STATE_CACHE_READ_RESPONSE:
902         DCHECK_EQ(OK, rv);
903         rv = DoCacheReadResponse();
904         break;
905       case STATE_CACHE_READ_RESPONSE_COMPLETE:
906         rv = DoCacheReadResponseComplete(rv);
907         break;
908       case STATE_WRITE_UPDATED_PREFETCH_RESPONSE:
909         DCHECK_EQ(OK, rv);
910         rv = DoCacheWriteUpdatedPrefetchResponse(rv);
911         break;
912       case STATE_WRITE_UPDATED_PREFETCH_RESPONSE_COMPLETE:
913         rv = DoCacheWriteUpdatedPrefetchResponseComplete(rv);
914         break;
915       case STATE_CACHE_DISPATCH_VALIDATION:
916         DCHECK_EQ(OK, rv);
917         rv = DoCacheDispatchValidation();
918         break;
919       case STATE_CACHE_QUERY_DATA:
920         DCHECK_EQ(OK, rv);
921         rv = DoCacheQueryData();
922         break;
923       case STATE_CACHE_QUERY_DATA_COMPLETE:
924         rv = DoCacheQueryDataComplete(rv);
925         break;
926       case STATE_START_PARTIAL_CACHE_VALIDATION:
927         DCHECK_EQ(OK, rv);
928         rv = DoStartPartialCacheValidation();
929         break;
930       case STATE_COMPLETE_PARTIAL_CACHE_VALIDATION:
931         rv = DoCompletePartialCacheValidation(rv);
932         break;
933       case STATE_CACHE_UPDATE_STALE_WHILE_REVALIDATE_TIMEOUT:
934         DCHECK_EQ(OK, rv);
935         rv = DoCacheUpdateStaleWhileRevalidateTimeout();
936         break;
937       case STATE_CACHE_UPDATE_STALE_WHILE_REVALIDATE_TIMEOUT_COMPLETE:
938         rv = DoCacheUpdateStaleWhileRevalidateTimeoutComplete(rv);
939         break;
940       case STATE_CONNECTED_CALLBACK:
941         rv = DoConnectedCallback();
942         break;
943       case STATE_CONNECTED_CALLBACK_COMPLETE:
944         rv = DoConnectedCallbackComplete(rv);
945         break;
946       case STATE_SETUP_ENTRY_FOR_READ:
947         DCHECK_EQ(OK, rv);
948         rv = DoSetupEntryForRead();
949         break;
950       case STATE_SEND_REQUEST:
951         DCHECK_EQ(OK, rv);
952         rv = DoSendRequest();
953         break;
954       case STATE_SEND_REQUEST_COMPLETE:
955         rv = DoSendRequestComplete(rv);
956         break;
957       case STATE_SUCCESSFUL_SEND_REQUEST:
958         DCHECK_EQ(OK, rv);
959         rv = DoSuccessfulSendRequest();
960         break;
961       case STATE_UPDATE_CACHED_RESPONSE:
962         DCHECK_EQ(OK, rv);
963         rv = DoUpdateCachedResponse();
964         break;
965       case STATE_CACHE_WRITE_UPDATED_RESPONSE:
966         DCHECK_EQ(OK, rv);
967         rv = DoCacheWriteUpdatedResponse();
968         break;
969       case STATE_CACHE_WRITE_UPDATED_RESPONSE_COMPLETE:
970         rv = DoCacheWriteUpdatedResponseComplete(rv);
971         break;
972       case STATE_UPDATE_CACHED_RESPONSE_COMPLETE:
973         rv = DoUpdateCachedResponseComplete(rv);
974         break;
975       case STATE_OVERWRITE_CACHED_RESPONSE:
976         DCHECK_EQ(OK, rv);
977         rv = DoOverwriteCachedResponse();
978         break;
979       case STATE_CACHE_WRITE_RESPONSE:
980         DCHECK_EQ(OK, rv);
981         rv = DoCacheWriteResponse();
982         break;
983       case STATE_CACHE_WRITE_RESPONSE_COMPLETE:
984         rv = DoCacheWriteResponseComplete(rv);
985         break;
986       case STATE_TRUNCATE_CACHED_DATA:
987         DCHECK_EQ(OK, rv);
988         rv = DoTruncateCachedData();
989         break;
990       case STATE_TRUNCATE_CACHED_DATA_COMPLETE:
991         rv = DoTruncateCachedDataComplete(rv);
992         break;
993       case STATE_PARTIAL_HEADERS_RECEIVED:
994         DCHECK_EQ(OK, rv);
995         rv = DoPartialHeadersReceived();
996         break;
997       case STATE_HEADERS_PHASE_CANNOT_PROCEED:
998         rv = DoHeadersPhaseCannotProceed(rv);
999         break;
1000       case STATE_FINISH_HEADERS:
1001         rv = DoFinishHeaders(rv);
1002         break;
1003       case STATE_FINISH_HEADERS_COMPLETE:
1004         rv = DoFinishHeadersComplete(rv);
1005         break;
1006       case STATE_NETWORK_READ_CACHE_WRITE:
1007         DCHECK_EQ(OK, rv);
1008         rv = DoNetworkReadCacheWrite();
1009         break;
1010       case STATE_NETWORK_READ_CACHE_WRITE_COMPLETE:
1011         rv = DoNetworkReadCacheWriteComplete(rv);
1012         break;
1013       case STATE_CACHE_READ_DATA:
1014         DCHECK_EQ(OK, rv);
1015         rv = DoCacheReadData();
1016         break;
1017       case STATE_CACHE_READ_DATA_COMPLETE:
1018         rv = DoCacheReadDataComplete(rv);
1019         break;
1020       case STATE_NETWORK_READ:
1021         DCHECK_EQ(OK, rv);
1022         rv = DoNetworkRead();
1023         break;
1024       case STATE_NETWORK_READ_COMPLETE:
1025         rv = DoNetworkReadComplete(rv);
1026         break;
1027       case STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE:
1028         DCHECK_EQ(0, rv);  // Here "rv" is a count of bytes.
1029         rv = DoMarkSingleKeyedCacheEntryUnusable();
1030         break;
1031       case STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE:
1032         rv = DoMarkSingleKeyedCacheEntryUnusableComplete(rv);
1033         break;
1034       default:
1035         NOTREACHED() << "bad state " << state;
1036         rv = ERR_FAILED;
1037         break;
1038     }
1039     DCHECK(next_state_ != STATE_UNSET) << "Previous state was " << state;
1040 
1041   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
1042 
1043   // Assert Start() state machine's allowed last state in successful cases when
1044   // caching is happening.
1045   DCHECK(reading_ || rv != OK || !entry_ ||
1046          state == STATE_FINISH_HEADERS_COMPLETE);
1047 
1048   if (rv != ERR_IO_PENDING && !callback_.is_null()) {
1049     read_buf_ = nullptr;  // Release the buffer before invoking the callback.
1050     std::move(callback_).Run(rv);
1051   }
1052 
1053   return rv;
1054 }
1055 
DoGetBackend()1056 int HttpCache::Transaction::DoGetBackend() {
1057   cache_pending_ = true;
1058   TransitionToState(STATE_GET_BACKEND_COMPLETE);
1059   net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_GET_BACKEND);
1060   return cache_->GetBackendForTransaction(this);
1061 }
1062 
DoGetBackendComplete(int result)1063 int HttpCache::Transaction::DoGetBackendComplete(int result) {
1064   DCHECK(result == OK || result == ERR_FAILED);
1065   net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_GET_BACKEND,
1066                                     result);
1067   cache_pending_ = false;
1068 
1069   // Reset mode_ that might get set in this function. This is done because this
1070   // function can be invoked multiple times for a transaction.
1071   mode_ = NONE;
1072 
1073   if (!ShouldPassThrough()) {
1074     // The flag `use_single_keyed_cache_` will have been changed back to false
1075     // if the entry was marked unusable and the transaction was restarted in
1076     // DoCacheReadResponseComplete(), even though `request_` will still have a
1077     // checksum. So it needs to be passed explicitly.
1078     cache_key_ =
1079         *cache_->GenerateCacheKeyForRequest(request_, use_single_keyed_cache_);
1080 
1081     // Requested cache access mode.
1082     if (effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
1083       if (effective_load_flags_ & LOAD_BYPASS_CACHE) {
1084         // The client has asked for nonsense.
1085         TransitionToState(STATE_FINISH_HEADERS);
1086         return ERR_CACHE_MISS;
1087       }
1088       mode_ = READ;
1089     } else if (effective_load_flags_ & LOAD_BYPASS_CACHE) {
1090       mode_ = WRITE;
1091     } else {
1092       mode_ = READ_WRITE;
1093     }
1094 
1095     // Downgrade to UPDATE if the request has been externally conditionalized.
1096     if (external_validation_.initialized) {
1097       if (mode_ & WRITE) {
1098         // Strip off the READ_DATA bit (and maybe add back a READ_META bit
1099         // in case READ was off).
1100         mode_ = UPDATE;
1101       } else {
1102         mode_ = NONE;
1103       }
1104     }
1105   }
1106 
1107   // Use PUT, DELETE, and PATCH only to invalidate existing stored entries.
1108   if ((method_ == "PUT" || method_ == "DELETE" || method_ == "PATCH") &&
1109       mode_ != READ_WRITE && mode_ != WRITE) {
1110     mode_ = NONE;
1111   }
1112 
1113   // Note that if mode_ == UPDATE (which is tied to external_validation_), the
1114   // transaction behaves the same for GET and HEAD requests at this point: if it
1115   // was not modified, the entry is updated and a response is not returned from
1116   // the cache. If we receive 200, it doesn't matter if there was a validation
1117   // header or not.
1118   if (method_ == "HEAD" && mode_ == WRITE)
1119     mode_ = NONE;
1120 
1121   // If must use cache, then we must fail.  This can happen for back/forward
1122   // navigations to a page generated via a form post.
1123   if (!(mode_ & READ) && effective_load_flags_ & LOAD_ONLY_FROM_CACHE) {
1124     TransitionToState(STATE_FINISH_HEADERS);
1125     return ERR_CACHE_MISS;
1126   }
1127 
1128   if (mode_ == NONE) {
1129     if (partial_) {
1130       partial_->RestoreHeaders(&custom_request_->extra_headers);
1131       partial_.reset();
1132     }
1133     TransitionToState(STATE_SEND_REQUEST);
1134   } else {
1135     TransitionToState(STATE_INIT_ENTRY);
1136   }
1137 
1138   // This is only set if we have something to do with the response.
1139   range_requested_ = (partial_.get() != nullptr);
1140 
1141   return OK;
1142 }
1143 
DoInitEntry()1144 int HttpCache::Transaction::DoInitEntry() {
1145   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoInitEntry",
1146                          TRACE_ID_LOCAL(trace_id_),
1147                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1148   DCHECK(!new_entry_);
1149 
1150   if (!cache_.get()) {
1151     TransitionToState(STATE_FINISH_HEADERS);
1152     return ERR_UNEXPECTED;
1153   }
1154 
1155   if (mode_ == WRITE) {
1156     TransitionToState(STATE_DOOM_ENTRY);
1157     return OK;
1158   }
1159 
1160   TransitionToState(STATE_OPEN_OR_CREATE_ENTRY);
1161   return OK;
1162 }
1163 
DoOpenOrCreateEntry()1164 int HttpCache::Transaction::DoOpenOrCreateEntry() {
1165   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoOpenOrCreateEntry",
1166                          TRACE_ID_LOCAL(trace_id_),
1167                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1168   DCHECK(!new_entry_);
1169   TransitionToState(STATE_OPEN_OR_CREATE_ENTRY_COMPLETE);
1170   cache_pending_ = true;
1171   net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_OPEN_OR_CREATE_ENTRY);
1172   first_cache_access_since_ = TimeTicks::Now();
1173   const bool has_opened_or_created_entry = has_opened_or_created_entry_;
1174   has_opened_or_created_entry_ = true;
1175   record_entry_open_or_creation_time_ = false;
1176 
1177   // See if we already have something working with this cache key.
1178   new_entry_ = cache_->FindActiveEntry(cache_key_);
1179   if (new_entry_)
1180     return OK;
1181 
1182   // See if we could potentially doom the entry based on hints the backend keeps
1183   // in memory.
1184   // Currently only SimpleCache utilizes in memory hints. If an entry is found
1185   // unsuitable, and thus Doomed, SimpleCache can also optimize the
1186   // OpenOrCreateEntry() call to reduce the overhead of trying to open an entry
1187   // we know is doomed.
1188   uint8_t in_memory_info =
1189       cache_->GetCurrentBackend()->GetEntryInMemoryData(cache_key_);
1190   bool entry_not_suitable = false;
1191   if (MaybeRejectBasedOnEntryInMemoryData(in_memory_info)) {
1192     cache_->GetCurrentBackend()->DoomEntry(cache_key_, priority_,
1193                                            base::DoNothing());
1194     entry_not_suitable = true;
1195     // Documents the case this applies in
1196     DCHECK_EQ(mode_, READ_WRITE);
1197     // Record this as CantConditionalize, but otherwise proceed as we would
1198     // below --- as we've already dropped the old entry.
1199     couldnt_conditionalize_request_ = true;
1200     validation_cause_ = VALIDATION_CAUSE_ZERO_FRESHNESS;
1201     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE);
1202   }
1203 
1204   if (!has_opened_or_created_entry) {
1205     record_entry_open_or_creation_time_ = true;
1206   }
1207 
1208   // mode_ can be anything but NONE or WRITE at this point (READ, UPDATE, or
1209   // READ_WRITE).
1210   // READ, UPDATE, certain READ_WRITEs, and some methods shouldn't create, so
1211   // try only opening.
1212   if (mode_ != READ_WRITE || ShouldOpenOnlyMethods()) {
1213     if (entry_not_suitable) {
1214       // The entry isn't suitable and we can't create a new one.
1215       return net::ERR_CACHE_ENTRY_NOT_SUITABLE;
1216     }
1217 
1218     return cache_->OpenEntry(cache_key_, &new_entry_, this);
1219   }
1220 
1221   return cache_->OpenOrCreateEntry(cache_key_, &new_entry_, this);
1222 }
1223 
DoOpenOrCreateEntryComplete(int result)1224 int HttpCache::Transaction::DoOpenOrCreateEntryComplete(int result) {
1225   TRACE_EVENT_WITH_FLOW1(
1226       "net", "HttpCacheTransaction::DoOpenOrCreateEntryComplete",
1227       TRACE_ID_LOCAL(trace_id_),
1228       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result",
1229       (result == OK ? (new_entry_->opened ? "opened" : "created") : "failed"));
1230 
1231   const bool record_uma =
1232       record_entry_open_or_creation_time_ && cache_ &&
1233       cache_->GetCurrentBackend() &&
1234       cache_->GetCurrentBackend()->GetCacheType() != MEMORY_CACHE;
1235   record_entry_open_or_creation_time_ = false;
1236 
1237   // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is
1238   // OK, otherwise the cache will end up with an active entry without any
1239   // transaction attached.
1240   net_log_.EndEvent(NetLogEventType::HTTP_CACHE_OPEN_OR_CREATE_ENTRY, [&] {
1241     base::Value::Dict params;
1242     if (result == OK) {
1243       params.Set("result", new_entry_->opened ? "opened" : "created");
1244     } else {
1245       params.Set("net_error", result);
1246     }
1247     return params;
1248   });
1249 
1250   cache_pending_ = false;
1251 
1252   if (result == OK) {
1253     if (new_entry_->opened) {
1254       if (record_uma) {
1255         base::UmaHistogramTimes(
1256             "HttpCache.OpenDiskEntry",
1257             base::TimeTicks::Now() - first_cache_access_since_);
1258       }
1259     } else {
1260       if (record_uma) {
1261         base::UmaHistogramTimes(
1262             "HttpCache.CreateDiskEntry",
1263             base::TimeTicks::Now() - first_cache_access_since_);
1264       }
1265 
1266       // Entry was created so mode changes to WRITE.
1267       mode_ = WRITE;
1268     }
1269     TransitionToState(STATE_ADD_TO_ENTRY);
1270     return OK;
1271   }
1272 
1273   if (result == ERR_CACHE_RACE) {
1274     TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
1275     return OK;
1276   }
1277 
1278   // No need to explicitly handle ERR_CACHE_ENTRY_NOT_SUITABLE as the
1279   // ShouldOpenOnlyMethods() check will handle it.
1280 
1281   // We were unable to open or create an entry.
1282   DLOG(WARNING) << "Unable to open or create cache entry";
1283 
1284   if (ShouldOpenOnlyMethods()) {
1285     // These methods, on failure, should bypass the cache.
1286     mode_ = NONE;
1287     TransitionToState(STATE_SEND_REQUEST);
1288     return OK;
1289   }
1290 
1291   // Since the operation failed, what we do next depends on the mode_ which can
1292   // be the following: READ, READ_WRITE, or UPDATE. Note: mode_ cannot be WRITE
1293   // or NONE at this point as DoInitEntry() handled those cases.
1294 
1295   switch (mode_) {
1296     case READ:
1297       // The entry does not exist, and we are not permitted to create a new
1298       // entry, so we must fail.
1299       TransitionToState(STATE_FINISH_HEADERS);
1300       return ERR_CACHE_MISS;
1301     case READ_WRITE:
1302       // Unable to open or create; set the mode to NONE in order to bypass the
1303       // cache entry and read from the network directly.
1304       mode_ = NONE;
1305       if (partial_)
1306         partial_->RestoreHeaders(&custom_request_->extra_headers);
1307       TransitionToState(STATE_SEND_REQUEST);
1308       break;
1309     case UPDATE:
1310       // There is no cache entry to update; proceed without caching.
1311       DCHECK(!partial_);
1312       mode_ = NONE;
1313       TransitionToState(STATE_SEND_REQUEST);
1314       break;
1315     default:
1316       NOTREACHED();
1317   }
1318 
1319   return OK;
1320 }
1321 
DoDoomEntry()1322 int HttpCache::Transaction::DoDoomEntry() {
1323   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoDoomEntry",
1324                          TRACE_ID_LOCAL(trace_id_),
1325                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1326   TransitionToState(STATE_DOOM_ENTRY_COMPLETE);
1327   cache_pending_ = true;
1328   if (first_cache_access_since_.is_null())
1329     first_cache_access_since_ = TimeTicks::Now();
1330   net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_DOOM_ENTRY);
1331   return cache_->DoomEntry(cache_key_, this);
1332 }
1333 
DoDoomEntryComplete(int result)1334 int HttpCache::Transaction::DoDoomEntryComplete(int result) {
1335   TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoDoomEntryComplete",
1336                          TRACE_ID_LOCAL(trace_id_),
1337                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1338                          "result", result);
1339   net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_DOOM_ENTRY,
1340                                     result);
1341   cache_pending_ = false;
1342   TransitionToState(result == ERR_CACHE_RACE
1343                         ? STATE_HEADERS_PHASE_CANNOT_PROCEED
1344                         : STATE_CREATE_ENTRY);
1345   return OK;
1346 }
1347 
DoCreateEntry()1348 int HttpCache::Transaction::DoCreateEntry() {
1349   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoCreateEntry",
1350                          TRACE_ID_LOCAL(trace_id_),
1351                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1352   DCHECK(!new_entry_);
1353   TransitionToState(STATE_CREATE_ENTRY_COMPLETE);
1354   cache_pending_ = true;
1355   net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_CREATE_ENTRY);
1356   return cache_->CreateEntry(cache_key_, &new_entry_, this);
1357 }
1358 
DoCreateEntryComplete(int result)1359 int HttpCache::Transaction::DoCreateEntryComplete(int result) {
1360   TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoCreateEntryComplete",
1361                          TRACE_ID_LOCAL(trace_id_),
1362                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1363                          "result", result);
1364   // It is important that we go to STATE_ADD_TO_ENTRY whenever the result is
1365   // OK, otherwise the cache will end up with an active entry without any
1366   // transaction attached.
1367   net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_CREATE_ENTRY,
1368                                     result);
1369   cache_pending_ = false;
1370   switch (result) {
1371     case OK:
1372       TransitionToState(STATE_ADD_TO_ENTRY);
1373       break;
1374 
1375     case ERR_CACHE_RACE:
1376       TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
1377       break;
1378 
1379     default:
1380       DLOG(WARNING) << "Unable to create cache entry";
1381 
1382       // Set the mode to NONE in order to bypass the cache entry and read from
1383       // the network directly.
1384       mode_ = NONE;
1385       if (!done_headers_create_new_entry_) {
1386         if (partial_)
1387           partial_->RestoreHeaders(&custom_request_->extra_headers);
1388         TransitionToState(STATE_SEND_REQUEST);
1389         return OK;
1390       }
1391       // The headers have already been received as a result of validation,
1392       // triggering the doom of the old entry.  So no network request needs to
1393       // be sent. Note that since mode_ is NONE, the response won't be written
1394       // to cache. Transition to STATE_CACHE_WRITE_RESPONSE as that's the state
1395       // the transaction left off on when it tried to create the new entry.
1396       done_headers_create_new_entry_ = false;
1397       TransitionToState(STATE_CACHE_WRITE_RESPONSE);
1398   }
1399   return OK;
1400 }
1401 
DoAddToEntry()1402 int HttpCache::Transaction::DoAddToEntry() {
1403   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoAddToEntry",
1404                          TRACE_ID_LOCAL(trace_id_),
1405                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1406   DCHECK(new_entry_);
1407   cache_pending_ = true;
1408   net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY);
1409   DCHECK(entry_lock_waiting_since_.is_null());
1410 
1411   // By this point whether the entry was created or opened is no longer relevant
1412   // for this transaction. However there may be queued transactions that want to
1413   // use this entry and from their perspective the entry was opened, so change
1414   // the flag to reflect that.
1415   new_entry_->opened = true;
1416 
1417   int rv = cache_->AddTransactionToEntry(new_entry_, this);
1418   DCHECK_EQ(rv, ERR_IO_PENDING);
1419 
1420   // If headers phase is already done then we are here because of validation not
1421   // matching and creating a new entry. This transaction should be the
1422   // first transaction of that new entry and thus it will not have cache lock
1423   // delays, thus returning early from here.
1424   if (done_headers_create_new_entry_) {
1425     DCHECK_EQ(mode_, WRITE);
1426     TransitionToState(STATE_DONE_HEADERS_ADD_TO_ENTRY_COMPLETE);
1427     return rv;
1428   }
1429 
1430   TransitionToState(STATE_ADD_TO_ENTRY_COMPLETE);
1431 
1432   entry_lock_waiting_since_ = TimeTicks::Now();
1433   AddCacheLockTimeoutHandler(new_entry_);
1434   return rv;
1435 }
1436 
AddCacheLockTimeoutHandler(ActiveEntry * entry)1437 void HttpCache::Transaction::AddCacheLockTimeoutHandler(ActiveEntry* entry) {
1438   DCHECK(next_state_ == STATE_ADD_TO_ENTRY_COMPLETE ||
1439          next_state_ == STATE_FINISH_HEADERS_COMPLETE);
1440   if ((bypass_lock_for_test_ && next_state_ == STATE_ADD_TO_ENTRY_COMPLETE) ||
1441       (bypass_lock_after_headers_for_test_ &&
1442        next_state_ == STATE_FINISH_HEADERS_COMPLETE)) {
1443     base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
1444         FROM_HERE,
1445         base::BindOnce(&HttpCache::Transaction::OnCacheLockTimeout,
1446                        weak_factory_.GetWeakPtr(), entry_lock_waiting_since_));
1447   } else {
1448     int timeout_milliseconds = 20 * 1000;
1449     if (partial_ && entry->writers && !entry->writers->IsEmpty() &&
1450         entry->writers->IsExclusive()) {
1451       // Even though entry_->writers takes care of allowing multiple writers to
1452       // simultaneously govern reading from the network and writing to the cache
1453       // for full requests, partial requests are still blocked by the
1454       // reader/writer lock.
1455       // Bypassing the cache after 25 ms of waiting for the cache lock
1456       // eliminates a long running issue, http://crbug.com/31014, where
1457       // two of the same media resources could not be played back simultaneously
1458       // due to one locking the cache entry until the entire video was
1459       // downloaded.
1460       // Bypassing the cache is not ideal, as we are now ignoring the cache
1461       // entirely for all range requests to a resource beyond the first. This
1462       // is however a much more succinct solution than the alternatives, which
1463       // would require somewhat significant changes to the http caching logic.
1464       //
1465       // Allow some timeout slack for the entry addition to complete in case
1466       // the writer lock is imminently released; we want to avoid skipping
1467       // the cache if at all possible. See http://crbug.com/408765
1468       timeout_milliseconds = 25;
1469     }
1470     base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
1471         FROM_HERE,
1472         base::BindOnce(&HttpCache::Transaction::OnCacheLockTimeout,
1473                        weak_factory_.GetWeakPtr(), entry_lock_waiting_since_),
1474         base::Milliseconds(timeout_milliseconds));
1475   }
1476 }
1477 
DoAddToEntryComplete(int result)1478 int HttpCache::Transaction::DoAddToEntryComplete(int result) {
1479   TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoAddToEntryComplete",
1480                          TRACE_ID_LOCAL(trace_id_),
1481                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1482                          "result", result);
1483   net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_ADD_TO_ENTRY,
1484                                     result);
1485   if (cache_ && cache_->GetCurrentBackend() &&
1486       cache_->GetCurrentBackend()->GetCacheType() != MEMORY_CACHE) {
1487     const base::TimeDelta entry_lock_wait =
1488         TimeTicks::Now() - entry_lock_waiting_since_;
1489     base::UmaHistogramTimes("HttpCache.AddTransactionToEntry", entry_lock_wait);
1490   }
1491 
1492   entry_lock_waiting_since_ = TimeTicks();
1493   DCHECK(new_entry_);
1494   cache_pending_ = false;
1495 
1496   if (result == OK)
1497     entry_ = new_entry_;
1498 
1499   // If there is a failure, the cache should have taken care of new_entry_.
1500   new_entry_ = nullptr;
1501 
1502   if (result == ERR_CACHE_RACE) {
1503     TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
1504     return OK;
1505   }
1506 
1507   if (result == ERR_CACHE_LOCK_TIMEOUT) {
1508     if (mode_ == READ) {
1509       TransitionToState(STATE_FINISH_HEADERS);
1510       return ERR_CACHE_MISS;
1511     }
1512 
1513     // The cache is busy, bypass it for this transaction.
1514     mode_ = NONE;
1515     TransitionToState(STATE_SEND_REQUEST);
1516     if (partial_) {
1517       partial_->RestoreHeaders(&custom_request_->extra_headers);
1518       partial_.reset();
1519     }
1520     return OK;
1521   }
1522 
1523   // TODO(crbug.com/713354) Access timestamp for histograms only if entry is
1524   // already written, to avoid data race since cache thread can also access
1525   // this.
1526   if (!cache_->IsWritingInProgress(entry()))
1527     open_entry_last_used_ = entry_->GetEntry()->GetLastUsed();
1528 
1529   // TODO(jkarlin): We should either handle the case or DCHECK.
1530   if (result != OK) {
1531     NOTREACHED();
1532     TransitionToState(STATE_FINISH_HEADERS);
1533     return result;
1534   }
1535 
1536   if (mode_ == WRITE) {
1537     if (partial_)
1538       partial_->RestoreHeaders(&custom_request_->extra_headers);
1539     TransitionToState(STATE_SEND_REQUEST);
1540   } else {
1541     // We have to read the headers from the cached entry.
1542     DCHECK(mode_ & READ_META);
1543     TransitionToState(STATE_CACHE_READ_RESPONSE);
1544   }
1545   return OK;
1546 }
1547 
DoDoneHeadersAddToEntryComplete(int result)1548 int HttpCache::Transaction::DoDoneHeadersAddToEntryComplete(int result) {
1549   TRACE_EVENT_WITH_FLOW1(
1550       "net", "HttpCacheTransaction::DoDoneHeadersAddToEntryComplete",
1551       TRACE_ID_LOCAL(trace_id_),
1552       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
1553   // This transaction's response headers did not match its ActiveEntry so it
1554   // created a new ActiveEntry (new_entry_) to write to (and doomed the old
1555   // one). Now that the new entry has been created, start writing the response.
1556 
1557   DCHECK_EQ(result, OK);
1558   DCHECK_EQ(mode_, WRITE);
1559   DCHECK(new_entry_);
1560   DCHECK(response_.headers);
1561 
1562   cache_pending_ = false;
1563   done_headers_create_new_entry_ = false;
1564 
1565   // It is unclear exactly how this state is reached with an ERR_CACHE_RACE, but
1566   // this check appears to fix a rare crash. See crbug.com/959194.
1567   if (result == ERR_CACHE_RACE) {
1568     TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
1569     return OK;
1570   }
1571 
1572   entry_ = new_entry_;
1573   DCHECK_NE(response_.headers->response_code(), net::HTTP_NOT_MODIFIED);
1574   DCHECK(cache_->CanTransactionWriteResponseHeaders(
1575       entry_, this, partial_ != nullptr, false));
1576   TransitionToState(STATE_CACHE_WRITE_RESPONSE);
1577   return OK;
1578 }
1579 
DoCacheReadResponse()1580 int HttpCache::Transaction::DoCacheReadResponse() {
1581   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoCacheReadResponse",
1582                          TRACE_ID_LOCAL(trace_id_),
1583                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1584   DCHECK(entry_);
1585   TransitionToState(STATE_CACHE_READ_RESPONSE_COMPLETE);
1586 
1587   io_buf_len_ = entry_->GetEntry()->GetDataSize(kResponseInfoIndex);
1588   read_buf_ = base::MakeRefCounted<IOBuffer>(io_buf_len_);
1589 
1590   net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_INFO);
1591   BeginDiskCacheAccessTimeCount();
1592   return entry_->GetEntry()->ReadData(kResponseInfoIndex, 0, read_buf_.get(),
1593                                       io_buf_len_, io_callback_);
1594 }
1595 
DoCacheReadResponseComplete(int result)1596 int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {
1597   TRACE_EVENT_WITH_FLOW2("net",
1598                          "HttpCacheTransaction::DoCacheReadResponseComplete",
1599                          TRACE_ID_LOCAL(trace_id_),
1600                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1601                          "result", result, "io_buf_len", io_buf_len_);
1602   net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_READ_INFO,
1603                                     result);
1604   EndDiskCacheAccessTimeCount(DiskCacheAccessType::kRead);
1605 
1606   // Record the time immediately before the cached response is parsed.
1607   read_headers_since_ = TimeTicks::Now();
1608 
1609   if (result != io_buf_len_ ||
1610       !HttpCache::ParseResponseInfo(read_buf_->data(), io_buf_len_, &response_,
1611                                     &truncated_)) {
1612     return OnCacheReadError(result, true);
1613   }
1614 
1615   // If the read response matches the clearing filter of FPS, doom the entry
1616   // and restart transaction.
1617   if (ShouldByPassCacheForFirstPartySets(initial_request_->fps_cache_filter,
1618                                          response_.browser_run_id)) {
1619     result = ERR_CACHE_ENTRY_NOT_SUITABLE;
1620     return OnCacheReadError(result, true);
1621   }
1622 
1623   if (response_.single_keyed_cache_entry_unusable) {
1624     RecordPervasivePayloadIndex("Network.CacheTransparency2.MarkedUnusable",
1625                                 request_->pervasive_payloads_index_for_logging);
1626 
1627     // We've read the single keyed entry and it turned out to be unusable. Let's
1628     // retry reading from the split cache.
1629     if (use_single_keyed_cache_) {
1630       DCHECK(!network_trans_);
1631       use_single_keyed_cache_ = false;
1632       DoneWithEntryForRestartWithCache();
1633       TransitionToState(STATE_GET_BACKEND);
1634       return OK;
1635     } else {
1636       LOG(WARNING) << "Unusable flag set on non-single-keyed cache entry; "
1637                    << "possible disk corruption? (cache key: " << cache_key_
1638                    << ")";
1639     }
1640   }
1641 
1642   // TODO(crbug.com/713354) Only get data size if there is no other transaction
1643   // currently writing the response body due to the data race mentioned in the
1644   // associated bug.
1645   if (!cache_->IsWritingInProgress(entry())) {
1646     int current_size = entry_->GetEntry()->GetDataSize(kResponseContentIndex);
1647     int64_t full_response_length = response_.headers->GetContentLength();
1648 
1649     // Some resources may have slipped in as truncated when they're not.
1650     if (full_response_length == current_size)
1651       truncated_ = false;
1652 
1653     // The state machine's handling of StopCaching unfortunately doesn't deal
1654     // well with resources that are larger than 2GB when there is a truncated or
1655     // sparse cache entry. While the state machine is reworked to resolve this,
1656     // the following logic is put in place to defer such requests to the
1657     // network. The cache should not be storing multi gigabyte resources. See
1658     // http://crbug.com/89567.
1659     if ((truncated_ ||
1660          response_.headers->response_code() == net::HTTP_PARTIAL_CONTENT) &&
1661         !range_requested_ &&
1662         full_response_length > std::numeric_limits<int32_t>::max()) {
1663       DCHECK(!partial_);
1664 
1665       // Doom the entry so that no other transaction gets added to this entry
1666       // and avoid a race of not being able to check this condition because
1667       // writing is in progress.
1668       DoneWithEntry(false);
1669       TransitionToState(STATE_SEND_REQUEST);
1670       return OK;
1671     }
1672   }
1673 
1674   if (response_.restricted_prefetch &&
1675       !(request_->load_flags & LOAD_CAN_USE_RESTRICTED_PREFETCH)) {
1676     TransitionToState(STATE_SEND_REQUEST);
1677     return OK;
1678   }
1679 
1680   // When a restricted prefetch is reused, we lift its reuse restriction.
1681   bool restricted_prefetch_reuse =
1682       response_.restricted_prefetch &&
1683       request_->load_flags & LOAD_CAN_USE_RESTRICTED_PREFETCH;
1684   DCHECK(!restricted_prefetch_reuse || response_.unused_since_prefetch);
1685 
1686   if (response_.unused_since_prefetch !=
1687       !!(request_->load_flags & LOAD_PREFETCH)) {
1688     // Either this is the first use of an entry since it was prefetched XOR
1689     // this is a prefetch. The value of response.unused_since_prefetch is
1690     // valid for this transaction but the bit needs to be flipped in storage.
1691     DCHECK(!updated_prefetch_response_);
1692     updated_prefetch_response_ = std::make_unique<HttpResponseInfo>(response_);
1693     updated_prefetch_response_->unused_since_prefetch =
1694         !response_.unused_since_prefetch;
1695     if (response_.restricted_prefetch &&
1696         request_->load_flags & LOAD_CAN_USE_RESTRICTED_PREFETCH) {
1697       updated_prefetch_response_->restricted_prefetch = false;
1698     }
1699 
1700     base::UmaHistogramEnumeration("HttpCache.RestrictedPrefetchReuse",
1701                                   restricted_prefetch_reuse
1702                                       ? RestrictedPrefetchReused::kReused
1703                                       : RestrictedPrefetchReused::kNotReused);
1704 
1705     TransitionToState(STATE_WRITE_UPDATED_PREFETCH_RESPONSE);
1706     return OK;
1707   }
1708 
1709   TransitionToState(STATE_CACHE_DISPATCH_VALIDATION);
1710   return OK;
1711 }
1712 
DoCacheWriteUpdatedPrefetchResponse(int result)1713 int HttpCache::Transaction::DoCacheWriteUpdatedPrefetchResponse(int result) {
1714   TRACE_EVENT_WITH_FLOW0(
1715       "net", "HttpCacheTransaction::DoCacheWriteUpdatedPrefetchResponse",
1716       TRACE_ID_LOCAL(trace_id_),
1717       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1718   DCHECK(updated_prefetch_response_);
1719   // TODO(jkarlin): If DoUpdateCachedResponse is also called for this
1720   // transaction then metadata will be written to cache twice. If prefetching
1721   // becomes more common, consider combining the writes.
1722   TransitionToState(STATE_WRITE_UPDATED_PREFETCH_RESPONSE_COMPLETE);
1723   return WriteResponseInfoToEntry(*updated_prefetch_response_.get(),
1724                                   truncated_);
1725 }
1726 
DoCacheWriteUpdatedPrefetchResponseComplete(int result)1727 int HttpCache::Transaction::DoCacheWriteUpdatedPrefetchResponseComplete(
1728     int result) {
1729   TRACE_EVENT_WITH_FLOW0(
1730       "net",
1731       "HttpCacheTransaction::DoCacheWriteUpdatedPrefetchResponseComplete",
1732       TRACE_ID_LOCAL(trace_id_),
1733       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1734   updated_prefetch_response_.reset();
1735   TransitionToState(STATE_CACHE_DISPATCH_VALIDATION);
1736   return OnWriteResponseInfoToEntryComplete(result);
1737 }
1738 
DoCacheDispatchValidation()1739 int HttpCache::Transaction::DoCacheDispatchValidation() {
1740   TRACE_EVENT_WITH_FLOW0("net",
1741                          "HttpCacheTransaction::DoCacheDispatchValidation",
1742                          TRACE_ID_LOCAL(trace_id_),
1743                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1744   if (!entry_) {
1745     // Entry got destroyed when twiddling unused-since-prefetch bit.
1746     TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
1747     return OK;
1748   }
1749 
1750   // We now have access to the cache entry.
1751   //
1752   //  o if we are a reader for the transaction, then we can start reading the
1753   //    cache entry.
1754   //
1755   //  o if we can read or write, then we should check if the cache entry needs
1756   //    to be validated and then issue a network request if needed or just read
1757   //    from the cache if the cache entry is already valid.
1758   //
1759   //  o if we are set to UPDATE, then we are handling an externally
1760   //    conditionalized request (if-modified-since / if-none-match). We check
1761   //    if the request headers define a validation request.
1762   //
1763   int result = ERR_FAILED;
1764   switch (mode_) {
1765     case READ:
1766       UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_USED);
1767       result = BeginCacheRead();
1768       break;
1769     case READ_WRITE:
1770       result = BeginPartialCacheValidation();
1771       break;
1772     case UPDATE:
1773       result = BeginExternallyConditionalizedRequest();
1774       break;
1775     case WRITE:
1776     default:
1777       NOTREACHED();
1778   }
1779   return result;
1780 }
1781 
DoCacheQueryData()1782 int HttpCache::Transaction::DoCacheQueryData() {
1783   TransitionToState(STATE_CACHE_QUERY_DATA_COMPLETE);
1784   return entry_->GetEntry()->ReadyForSparseIO(io_callback_);
1785 }
1786 
DoCacheQueryDataComplete(int result)1787 int HttpCache::Transaction::DoCacheQueryDataComplete(int result) {
1788   DCHECK_EQ(OK, result);
1789   if (!cache_.get()) {
1790     TransitionToState(STATE_FINISH_HEADERS);
1791     return ERR_UNEXPECTED;
1792   }
1793 
1794   return ValidateEntryHeadersAndContinue();
1795 }
1796 
1797 // We may end up here multiple times for a given request.
DoStartPartialCacheValidation()1798 int HttpCache::Transaction::DoStartPartialCacheValidation() {
1799   if (mode_ == NONE) {
1800     TransitionToState(STATE_FINISH_HEADERS);
1801     return OK;
1802   }
1803 
1804   TransitionToState(STATE_COMPLETE_PARTIAL_CACHE_VALIDATION);
1805   return partial_->ShouldValidateCache(entry_->GetEntry(), io_callback_);
1806 }
1807 
DoCompletePartialCacheValidation(int result)1808 int HttpCache::Transaction::DoCompletePartialCacheValidation(int result) {
1809   if (!result && reading_) {
1810     // This is the end of the request.
1811     DoneWithEntry(true);
1812     TransitionToState(STATE_FINISH_HEADERS);
1813     return result;
1814   }
1815 
1816   if (result < 0) {
1817     TransitionToState(STATE_FINISH_HEADERS);
1818     return result;
1819   }
1820 
1821   partial_->PrepareCacheValidation(entry_->GetEntry(),
1822                                    &custom_request_->extra_headers);
1823 
1824   if (reading_ && partial_->IsCurrentRangeCached()) {
1825     // We're about to read a range of bytes from the cache. Signal it to the
1826     // consumer through the "connected" callback.
1827     TransitionToState(STATE_CONNECTED_CALLBACK);
1828     return OK;
1829   }
1830 
1831   return BeginCacheValidation();
1832 }
1833 
DoCacheUpdateStaleWhileRevalidateTimeout()1834 int HttpCache::Transaction::DoCacheUpdateStaleWhileRevalidateTimeout() {
1835   TRACE_EVENT_WITH_FLOW0(
1836       "net", "HttpCacheTransaction::DoCacheUpdateStaleWhileRevalidateTimeout",
1837       TRACE_ID_LOCAL(trace_id_),
1838       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1839   response_.stale_revalidate_timeout =
1840       cache_->clock_->Now() + kStaleRevalidateTimeout;
1841   TransitionToState(STATE_CACHE_UPDATE_STALE_WHILE_REVALIDATE_TIMEOUT_COMPLETE);
1842 
1843   // We shouldn't be using stale truncated entries; if we did, the false below
1844   // would be wrong.
1845   DCHECK(!truncated_);
1846   return WriteResponseInfoToEntry(response_, false);
1847 }
1848 
DoCacheUpdateStaleWhileRevalidateTimeoutComplete(int result)1849 int HttpCache::Transaction::DoCacheUpdateStaleWhileRevalidateTimeoutComplete(
1850     int result) {
1851   TRACE_EVENT_WITH_FLOW0(
1852       "net",
1853       "HttpCacheTransaction::DoCacheUpdateStaleWhileRevalidateTimeoutComplete",
1854       TRACE_ID_LOCAL(trace_id_),
1855       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1856   DCHECK(!reading_);
1857   TransitionToState(STATE_CONNECTED_CALLBACK);
1858   return OnWriteResponseInfoToEntryComplete(result);
1859 }
1860 
DoSendRequest()1861 int HttpCache::Transaction::DoSendRequest() {
1862   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoSendRequest",
1863                          TRACE_ID_LOCAL(trace_id_),
1864                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1865   DCHECK(mode_ & WRITE || mode_ == NONE);
1866   DCHECK(!network_trans_.get());
1867 
1868   send_request_since_ = TimeTicks::Now();
1869 
1870   // Create a network transaction.
1871   int rv =
1872       cache_->network_layer_->CreateTransaction(priority_, &network_trans_);
1873 
1874   if (rv != OK) {
1875     TransitionToState(STATE_FINISH_HEADERS);
1876     return rv;
1877   }
1878 
1879   network_trans_->SetBeforeNetworkStartCallback(
1880       std::move(before_network_start_callback_));
1881   network_trans_->SetConnectedCallback(connected_callback_);
1882   network_trans_->SetRequestHeadersCallback(request_headers_callback_);
1883   network_trans_->SetEarlyResponseHeadersCallback(
1884       early_response_headers_callback_);
1885   network_trans_->SetResponseHeadersCallback(response_headers_callback_);
1886 
1887   // Old load timing information, if any, is now obsolete.
1888   network_transaction_info_.old_network_trans_load_timing.reset();
1889   network_transaction_info_.old_remote_endpoint = IPEndPoint();
1890 
1891   if (websocket_handshake_stream_base_create_helper_)
1892     network_trans_->SetWebSocketHandshakeStreamCreateHelper(
1893         websocket_handshake_stream_base_create_helper_);
1894 
1895   TransitionToState(STATE_SEND_REQUEST_COMPLETE);
1896   rv = network_trans_->Start(request_, io_callback_, net_log_);
1897   return rv;
1898 }
1899 
DoSendRequestComplete(int result)1900 int HttpCache::Transaction::DoSendRequestComplete(int result) {
1901   TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoSendRequestComplete",
1902                          TRACE_ID_LOCAL(trace_id_),
1903                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
1904                          "result", result);
1905   if (!cache_.get()) {
1906     TransitionToState(STATE_FINISH_HEADERS);
1907     return ERR_UNEXPECTED;
1908   }
1909 
1910   // If we tried to conditionalize the request and failed, we know
1911   // we won't be reading from the cache after this point.
1912   if (couldnt_conditionalize_request_)
1913     mode_ = WRITE;
1914 
1915   if (result == OK) {
1916     TransitionToState(STATE_SUCCESSFUL_SEND_REQUEST);
1917     return OK;
1918   }
1919 
1920   const HttpResponseInfo* response = network_trans_->GetResponseInfo();
1921   response_.network_accessed = response->network_accessed;
1922   response_.was_fetched_via_proxy = response->was_fetched_via_proxy;
1923   response_.proxy_server = response->proxy_server;
1924   response_.restricted_prefetch = response->restricted_prefetch;
1925   response_.resolve_error_info = response->resolve_error_info;
1926 
1927   // Do not record requests that have network errors or restarts.
1928   UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
1929   if (IsCertificateError(result)) {
1930     // If we get a certificate error, then there is a certificate in ssl_info,
1931     // so GetResponseInfo() should never return NULL here.
1932     DCHECK(response);
1933     response_.ssl_info = response->ssl_info;
1934   } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
1935     DCHECK(response);
1936     response_.cert_request_info = response->cert_request_info;
1937   } else if (result == ERR_INCONSISTENT_IP_ADDRESS_SPACE) {
1938     DoomInconsistentEntry();
1939   } else if (response_.was_cached) {
1940     DoneWithEntry(/*entry_is_complete=*/true);
1941   }
1942 
1943   TransitionToState(STATE_FINISH_HEADERS);
1944   return result;
1945 }
1946 
1947 // We received the response headers and there is no error.
DoSuccessfulSendRequest()1948 int HttpCache::Transaction::DoSuccessfulSendRequest() {
1949   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoSuccessfulSendRequest",
1950                          TRACE_ID_LOCAL(trace_id_),
1951                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
1952   DCHECK(!new_response_);
1953   const HttpResponseInfo* new_response = network_trans_->GetResponseInfo();
1954 
1955   if (new_response->headers->response_code() == net::HTTP_UNAUTHORIZED ||
1956       new_response->headers->response_code() ==
1957           net::HTTP_PROXY_AUTHENTICATION_REQUIRED) {
1958     SetAuthResponse(*new_response);
1959     if (!reading_) {
1960       TransitionToState(STATE_FINISH_HEADERS);
1961       return OK;
1962     }
1963 
1964     // We initiated a second request the caller doesn't know about. We should be
1965     // able to authenticate this request because we should have authenticated
1966     // this URL moments ago.
1967     if (IsReadyToRestartForAuth()) {
1968       TransitionToState(STATE_SEND_REQUEST_COMPLETE);
1969       // In theory we should check to see if there are new cookies, but there
1970       // is no way to do that from here.
1971       return network_trans_->RestartWithAuth(AuthCredentials(), io_callback_);
1972     }
1973 
1974     // We have to perform cleanup at this point so that at least the next
1975     // request can succeed.  We do not retry at this point, because data
1976     // has been read and we have no way to gather credentials.  We would
1977     // fail again, and potentially loop.  This can happen if the credentials
1978     // expire while chrome is suspended.
1979     if (entry_)
1980       DoomPartialEntry(false);
1981     mode_ = NONE;
1982     partial_.reset();
1983     ResetNetworkTransaction();
1984     TransitionToState(STATE_FINISH_HEADERS);
1985     return ERR_CACHE_AUTH_FAILURE_AFTER_READ;
1986   }
1987 
1988   // The single-keyed cache only accepts responses with code 200 or 304.
1989   // Anything else is considered unusable.
1990   if (use_single_keyed_cache_ &&
1991       !(new_response->headers->response_code() == 200 ||
1992         new_response->headers->response_code() == 304)) {
1993     // Either the new response will be written back to the cache, in which case
1994     // it will not be reused due to the flag, or it will not be, in which case
1995     // it will not be reused anyway.
1996     mark_single_keyed_cache_entry_unusable_ = true;
1997   }
1998 
1999   new_response_ = new_response;
2000   if (!ValidatePartialResponse() && !auth_response_.headers.get()) {
2001     // Something went wrong with this request and we have to restart it.
2002     // If we have an authentication response, we are exposed to weird things
2003     // hapenning if the user cancels the authentication before we receive
2004     // the new response.
2005     net_log_.AddEvent(NetLogEventType::HTTP_CACHE_RE_SEND_PARTIAL_REQUEST);
2006     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
2007     SetResponse(HttpResponseInfo());
2008     ResetNetworkTransaction();
2009     new_response_ = nullptr;
2010     TransitionToState(STATE_SEND_REQUEST);
2011     return OK;
2012   }
2013 
2014   if (handling_206_ && mode_ == READ_WRITE && !truncated_ && !is_sparse_) {
2015     // We have stored the full entry, but it changed and the server is
2016     // sending a range. We have to delete the old entry.
2017     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
2018     DoneWithEntry(false);
2019   }
2020 
2021   if (mode_ == WRITE &&
2022       cache_entry_status_ != CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE) {
2023     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_NOT_IN_CACHE);
2024   }
2025 
2026   // Invalidate any cached GET with a successful PUT, DELETE, or PATCH.
2027   if (mode_ == WRITE &&
2028       (method_ == "PUT" || method_ == "DELETE" || method_ == "PATCH")) {
2029     if (NonErrorResponse(new_response_->headers->response_code()) &&
2030         (entry_ && !entry_->doomed)) {
2031       int ret = cache_->DoomEntry(cache_key_, nullptr);
2032       DCHECK_EQ(OK, ret);
2033     }
2034     // Do not invalidate the entry if the request failed.
2035     DoneWithEntry(true);
2036   }
2037 
2038   // Invalidate any cached GET with a successful POST. If the network isolation
2039   // key isn't populated with the split cache active, there will be nothing to
2040   // invalidate in the cache.
2041   if (!(effective_load_flags_ & LOAD_DISABLE_CACHE) && method_ == "POST" &&
2042       NonErrorResponse(new_response_->headers->response_code()) &&
2043       (!HttpCache::IsSplitCacheEnabled() ||
2044        request_->network_isolation_key.IsFullyPopulated())) {
2045     cache_->DoomMainEntryForUrl(request_->url, request_->network_isolation_key,
2046                                 request_->is_subframe_document_resource);
2047   }
2048 
2049   if (new_response_->headers->response_code() ==
2050           net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE &&
2051       (method_ == "GET" || method_ == "POST")) {
2052     // If there is an active entry it may be destroyed with this transaction.
2053     SetResponse(*new_response_);
2054     TransitionToState(STATE_FINISH_HEADERS);
2055     return OK;
2056   }
2057 
2058   // Are we expecting a response to a conditional query?
2059   if (mode_ == READ_WRITE || mode_ == UPDATE) {
2060     if (new_response->headers->response_code() == net::HTTP_NOT_MODIFIED ||
2061         handling_206_) {
2062       UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_VALIDATED);
2063       TransitionToState(STATE_UPDATE_CACHED_RESPONSE);
2064       return OK;
2065     }
2066     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_UPDATED);
2067     mode_ = WRITE;
2068   }
2069 
2070   TransitionToState(STATE_OVERWRITE_CACHED_RESPONSE);
2071   return OK;
2072 }
2073 
2074 // We received 304 or 206 and we want to update the cached response headers.
DoUpdateCachedResponse()2075 int HttpCache::Transaction::DoUpdateCachedResponse() {
2076   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoUpdateCachedResponse",
2077                          TRACE_ID_LOCAL(trace_id_),
2078                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
2079   int rv = OK;
2080   // Update the cached response based on the headers and properties of
2081   // new_response_.
2082   response_.headers->Update(*new_response_->headers.get());
2083   response_.stale_revalidate_timeout = base::Time();
2084   response_.response_time = new_response_->response_time;
2085   response_.request_time = new_response_->request_time;
2086   response_.network_accessed = new_response_->network_accessed;
2087   response_.unused_since_prefetch = new_response_->unused_since_prefetch;
2088   response_.restricted_prefetch = new_response_->restricted_prefetch;
2089   response_.ssl_info = new_response_->ssl_info;
2090   response_.dns_aliases = new_response_->dns_aliases;
2091 
2092   // Be careful never to set single_keyed_cache_entry_unusable back to false
2093   // from true.
2094   if (mark_single_keyed_cache_entry_unusable_) {
2095     response_.single_keyed_cache_entry_unusable = true;
2096   }
2097 
2098   // If the new response didn't have a vary header, we continue to use the
2099   // header from the stored response per the effect of headers->Update().
2100   // Update the data with the new/updated request headers.
2101   response_.vary_data.Init(*request_, *response_.headers);
2102 
2103   if (ShouldDisableCaching(*response_.headers)) {
2104     if (!entry_->doomed) {
2105       int ret = cache_->DoomEntry(cache_key_, nullptr);
2106       DCHECK_EQ(OK, ret);
2107     }
2108     TransitionToState(STATE_UPDATE_CACHED_RESPONSE_COMPLETE);
2109   } else {
2110     if (use_single_keyed_cache_) {
2111       DCHECK_EQ(method_, "GET");
2112       ChecksumHeaders();
2113     }
2114 
2115     // If we are already reading, we already updated the headers for this
2116     // request; doing it again will change Content-Length.
2117     if (!reading_) {
2118       TransitionToState(STATE_CACHE_WRITE_UPDATED_RESPONSE);
2119       rv = OK;
2120     } else {
2121       TransitionToState(STATE_UPDATE_CACHED_RESPONSE_COMPLETE);
2122     }
2123   }
2124 
2125   return rv;
2126 }
2127 
DoCacheWriteUpdatedResponse()2128 int HttpCache::Transaction::DoCacheWriteUpdatedResponse() {
2129   TRACE_EVENT_WITH_FLOW0("net",
2130                          "HttpCacheTransaction::DoCacheWriteUpdatedResponse",
2131                          TRACE_ID_LOCAL(trace_id_),
2132                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
2133   TransitionToState(STATE_CACHE_WRITE_UPDATED_RESPONSE_COMPLETE);
2134   return WriteResponseInfoToEntry(response_, false);
2135 }
2136 
DoCacheWriteUpdatedResponseComplete(int result)2137 int HttpCache::Transaction::DoCacheWriteUpdatedResponseComplete(int result) {
2138   TRACE_EVENT_WITH_FLOW0(
2139       "net", "HttpCacheTransaction::DoCacheWriteUpdatedResponseComplete",
2140       TRACE_ID_LOCAL(trace_id_),
2141       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
2142   TransitionToState(STATE_UPDATE_CACHED_RESPONSE_COMPLETE);
2143   return OnWriteResponseInfoToEntryComplete(result);
2144 }
2145 
DoUpdateCachedResponseComplete(int result)2146 int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) {
2147   TRACE_EVENT_WITH_FLOW1(
2148       "net", "HttpCacheTransaction::DoUpdateCachedResponseComplete",
2149       TRACE_ID_LOCAL(trace_id_),
2150       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
2151   if (mode_ == UPDATE) {
2152     DCHECK(!handling_206_);
2153     // We got a "not modified" response and already updated the corresponding
2154     // cache entry above.
2155     //
2156     // By stopping to write to the cache now, we make sure that the 304 rather
2157     // than the cached 200 response, is what will be returned to the user.
2158     UpdateSecurityHeadersBeforeForwarding();
2159     DoneWithEntry(true);
2160   } else if (entry_ && !handling_206_) {
2161     DCHECK_EQ(READ_WRITE, mode_);
2162     if ((!partial_ && !cache_->IsWritingInProgress(entry_)) ||
2163         (partial_ && partial_->IsLastRange())) {
2164       mode_ = READ;
2165     }
2166     // We no longer need the network transaction, so destroy it.
2167     if (network_trans_)
2168       ResetNetworkTransaction();
2169   } else if (entry_ && handling_206_ && truncated_ &&
2170              partial_->initial_validation()) {
2171     // We just finished the validation of a truncated entry, and the server
2172     // is willing to resume the operation. Now we go back and start serving
2173     // the first part to the user.
2174     if (network_trans_)
2175       ResetNetworkTransaction();
2176     new_response_ = nullptr;
2177     TransitionToState(STATE_START_PARTIAL_CACHE_VALIDATION);
2178     partial_->SetRangeToStartDownload();
2179     return OK;
2180   }
2181   TransitionToState(STATE_OVERWRITE_CACHED_RESPONSE);
2182   return OK;
2183 }
2184 
DoOverwriteCachedResponse()2185 int HttpCache::Transaction::DoOverwriteCachedResponse() {
2186   TRACE_EVENT_WITH_FLOW0("net",
2187                          "HttpCacheTransaction::DoOverwriteCachedResponse",
2188                          TRACE_ID_LOCAL(trace_id_),
2189                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
2190   if (mode_ & READ) {
2191     TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED);
2192     return OK;
2193   }
2194 
2195   // We change the value of Content-Length for partial content.
2196   if (handling_206_ && partial_)
2197     partial_->FixContentLength(new_response_->headers.get());
2198 
2199   SetResponse(*new_response_);
2200 
2201   if (use_single_keyed_cache_) {
2202     DCHECK_EQ(method_, "GET");
2203     ChecksumHeaders();
2204   }
2205 
2206   if (method_ == "HEAD") {
2207     // This response is replacing the cached one.
2208     DoneWithEntry(false);
2209     new_response_ = nullptr;
2210     TransitionToState(STATE_FINISH_HEADERS);
2211     return OK;
2212   }
2213 
2214   if (handling_206_ && !CanResume(false)) {
2215     // There is no point in storing this resource because it will never be used.
2216     // This may change if we support LOAD_ONLY_FROM_CACHE with sparse entries.
2217     DoneWithEntry(false);
2218     if (partial_)
2219       partial_->FixResponseHeaders(response_.headers.get(), true);
2220     TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED);
2221     return OK;
2222   }
2223   // Mark the response with browser_run_id before it gets written.
2224   if (initial_request_->browser_run_id.has_value())
2225     response_.browser_run_id = initial_request_->browser_run_id;
2226 
2227   TransitionToState(STATE_CACHE_WRITE_RESPONSE);
2228   return OK;
2229 }
2230 
DoCacheWriteResponse()2231 int HttpCache::Transaction::DoCacheWriteResponse() {
2232   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoCacheWriteResponse",
2233                          TRACE_ID_LOCAL(trace_id_),
2234                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
2235   DCHECK(response_.headers);
2236   // Invalidate any current entry with a successful response if this transaction
2237   // cannot write to this entry. This transaction then continues to read from
2238   // the network without writing to the backend.
2239   bool is_match = response_.headers->response_code() == net::HTTP_NOT_MODIFIED;
2240   if (entry_ && !cache_->CanTransactionWriteResponseHeaders(
2241                     entry_, this, partial_ != nullptr, is_match)) {
2242     done_headers_create_new_entry_ = true;
2243 
2244     // The transaction needs to overwrite this response. Doom the current entry,
2245     // create a new one (by going to STATE_INIT_ENTRY), and then jump straight
2246     // to writing out the response, bypassing the headers checks. The mode_ is
2247     // set to WRITE in order to doom any other existing entries that might exist
2248     // so that this transaction can go straight to writing a response.
2249     mode_ = WRITE;
2250     TransitionToState(STATE_INIT_ENTRY);
2251     cache_->DoomEntryValidationNoMatch(entry_);
2252     entry_ = nullptr;
2253     return OK;
2254   }
2255 
2256   // Be careful never to set single_keyed_cache_entry_unusable back to false
2257   // from true.
2258   if (mark_single_keyed_cache_entry_unusable_) {
2259     response_.single_keyed_cache_entry_unusable = true;
2260   }
2261 
2262   TransitionToState(STATE_CACHE_WRITE_RESPONSE_COMPLETE);
2263   return WriteResponseInfoToEntry(response_, truncated_);
2264 }
2265 
DoCacheWriteResponseComplete(int result)2266 int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) {
2267   TRACE_EVENT_WITH_FLOW1(
2268       "net", "HttpCacheTransaction::DoCacheWriteResponseComplete",
2269       TRACE_ID_LOCAL(trace_id_),
2270       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
2271   TransitionToState(STATE_TRUNCATE_CACHED_DATA);
2272   return OnWriteResponseInfoToEntryComplete(result);
2273 }
2274 
DoTruncateCachedData()2275 int HttpCache::Transaction::DoTruncateCachedData() {
2276   TRACE_EVENT_WITH_FLOW0("net", "HttpCacheTransaction::DoTruncateCachedData",
2277                          TRACE_ID_LOCAL(trace_id_),
2278                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
2279   TransitionToState(STATE_TRUNCATE_CACHED_DATA_COMPLETE);
2280   if (!entry_)
2281     return OK;
2282   net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_WRITE_DATA);
2283   BeginDiskCacheAccessTimeCount();
2284   // Truncate the stream.
2285   return entry_->GetEntry()->WriteData(kResponseContentIndex, /*offset=*/0,
2286                                        /*buf=*/nullptr, /*buf_len=*/0,
2287                                        io_callback_, /*truncate=*/true);
2288 }
2289 
DoTruncateCachedDataComplete(int result)2290 int HttpCache::Transaction::DoTruncateCachedDataComplete(int result) {
2291   TRACE_EVENT_WITH_FLOW1(
2292       "net", "HttpCacheTransaction::DoTruncateCachedDataComplete",
2293       TRACE_ID_LOCAL(trace_id_),
2294       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
2295   EndDiskCacheAccessTimeCount(DiskCacheAccessType::kWrite);
2296   if (entry_) {
2297     net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_DATA,
2298                                       result);
2299   }
2300 
2301   TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED);
2302   return OK;
2303 }
2304 
DoPartialHeadersReceived()2305 int HttpCache::Transaction::DoPartialHeadersReceived() {
2306   new_response_ = nullptr;
2307 
2308   if (partial_ && mode_ != NONE && !reading_) {
2309     // We are about to return the headers for a byte-range request to the user,
2310     // so let's fix them.
2311     partial_->FixResponseHeaders(response_.headers.get(), true);
2312   }
2313   TransitionToState(STATE_FINISH_HEADERS);
2314   return OK;
2315 }
2316 
DoHeadersPhaseCannotProceed(int result)2317 int HttpCache::Transaction::DoHeadersPhaseCannotProceed(int result) {
2318   // If its the Start state machine and it cannot proceed due to a cache
2319   // failure, restart this transaction.
2320   DCHECK(!reading_);
2321 
2322   // Reset before invoking SetRequest() which can reset the request info sent to
2323   // network transaction.
2324   if (network_trans_)
2325     network_trans_.reset();
2326 
2327   new_response_ = nullptr;
2328 
2329   SetRequest(net_log_);
2330 
2331   entry_ = nullptr;
2332   new_entry_ = nullptr;
2333   last_disk_cache_access_start_time_ = TimeTicks();
2334 
2335   // TODO(https://crbug.com/1219402): This should probably clear `response_`,
2336   // too, once things are fixed so it's safe to do so.
2337 
2338   // Bypass the cache for timeout scenario.
2339   if (result == ERR_CACHE_LOCK_TIMEOUT)
2340     effective_load_flags_ |= LOAD_DISABLE_CACHE;
2341 
2342   TransitionToState(STATE_GET_BACKEND);
2343   return OK;
2344 }
2345 
DoFinishHeaders(int result)2346 int HttpCache::Transaction::DoFinishHeaders(int result) {
2347   TRACE_EVENT_WITH_FLOW1(
2348       "net", "HttpCacheTransaction::DoFinishHeaders", TRACE_ID_LOCAL(trace_id_),
2349       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
2350   if (!cache_.get() || !entry_ || result != OK) {
2351     TransitionToState(STATE_NONE);
2352     return result;
2353   }
2354 
2355   TransitionToState(STATE_FINISH_HEADERS_COMPLETE);
2356 
2357   // If it was an auth failure, this transaction should continue to be
2358   // headers_transaction till consumer takes an action, so no need to do
2359   // anything now.
2360   // TODO(crbug.com/740947). See the issue for a suggestion for cleaning the
2361   // state machine to be able to remove this condition.
2362   if (auth_response_.headers.get())
2363     return OK;
2364 
2365   // If the transaction needs to wait because another transaction is still
2366   // writing the response body, it will return ERR_IO_PENDING now and the
2367   // io_callback_ will be invoked when the wait is done.
2368   int rv = cache_->DoneWithResponseHeaders(entry_, this, partial_ != nullptr);
2369   DCHECK(!reading_ || rv == OK) << "Expected OK, but got " << rv;
2370 
2371   if (rv == ERR_IO_PENDING) {
2372     DCHECK(entry_lock_waiting_since_.is_null());
2373     entry_lock_waiting_since_ = TimeTicks::Now();
2374     AddCacheLockTimeoutHandler(entry_);
2375   }
2376   return rv;
2377 }
2378 
DoFinishHeadersComplete(int rv)2379 int HttpCache::Transaction::DoFinishHeadersComplete(int rv) {
2380   TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoFinishHeadersComplete",
2381                          TRACE_ID_LOCAL(trace_id_),
2382                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
2383                          "result", rv);
2384   entry_lock_waiting_since_ = TimeTicks();
2385   if (rv == ERR_CACHE_RACE || rv == ERR_CACHE_LOCK_TIMEOUT) {
2386     TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
2387     return rv;
2388   }
2389 
2390   if (network_trans_ && InWriters()) {
2391     entry_->writers->SetNetworkTransaction(this, std::move(network_trans_),
2392                                            std::move(checksum_));
2393     moved_network_transaction_to_writers_ = true;
2394   }
2395 
2396   // If already reading, that means it is a partial request coming back to the
2397   // headers phase, continue to the appropriate reading state.
2398   if (reading_) {
2399     int reading_state_rv = TransitionToReadingState();
2400     DCHECK_EQ(OK, reading_state_rv);
2401     return OK;
2402   }
2403 
2404   TransitionToState(STATE_NONE);
2405   return rv;
2406 }
2407 
DoNetworkReadCacheWrite()2408 int HttpCache::Transaction::DoNetworkReadCacheWrite() {
2409   TRACE_EVENT_WITH_FLOW2("net", "HttpCacheTransaction::DoNetworkReadCacheWrite",
2410                          TRACE_ID_LOCAL(trace_id_),
2411                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
2412                          "read_offset", read_offset_, "read_buf_len",
2413                          read_buf_len_);
2414   DCHECK(InWriters());
2415   TransitionToState(STATE_NETWORK_READ_CACHE_WRITE_COMPLETE);
2416   return entry_->writers->Read(read_buf_, read_buf_len_, io_callback_, this);
2417 }
2418 
DoNetworkReadCacheWriteComplete(int result)2419 int HttpCache::Transaction::DoNetworkReadCacheWriteComplete(int result) {
2420   TRACE_EVENT_WITH_FLOW1(
2421       "net", "HttpCacheTransaction::DoNetworkReadCacheWriteComplete",
2422       TRACE_ID_LOCAL(trace_id_),
2423       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result", result);
2424   if (!cache_.get()) {
2425     TransitionToState(STATE_NONE);
2426     return ERR_UNEXPECTED;
2427   }
2428   // |result| will be error code in case of network read failure and |this|
2429   // cannot proceed further, so set entry_ to null. |result| will not be error
2430   // in case of cache write failure since |this| can continue to read from the
2431   // network. If response is completed, then also set entry to null.
2432   if (result < 0) {
2433     // We should have discovered this error in WriterAboutToBeRemovedFromEntry
2434     DCHECK_EQ(result, shared_writing_error_);
2435     DCHECK_EQ(NONE, mode_);
2436     DCHECK(!entry_);
2437     TransitionToState(STATE_NONE);
2438     return result;
2439   }
2440 
2441   if (partial_) {
2442     return DoPartialNetworkReadCompleted(result);
2443   }
2444 
2445   if (result == 0) {
2446     DCHECK_EQ(NONE, mode_);
2447     DCHECK(!entry_);
2448   } else {
2449     read_offset_ += result;
2450     if (checksum_)
2451       checksum_->Update(read_buf_->data(), result);
2452   }
2453   TransitionToState(STATE_NONE);
2454   return result;
2455 }
2456 
DoPartialNetworkReadCompleted(int result)2457 int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) {
2458   DCHECK(partial_);
2459 
2460   // Go to the next range if nothing returned or return the result.
2461   // TODO(shivanisha) Simplify this condition if possible. It was introduced
2462   // in https://codereview.chromium.org/545101
2463   if (result != 0 || truncated_ ||
2464       !(partial_->IsLastRange() || mode_ == WRITE)) {
2465     partial_->OnNetworkReadCompleted(result);
2466 
2467     if (result == 0) {
2468       // We need to move on to the next range.
2469       if (network_trans_) {
2470         ResetNetworkTransaction();
2471       } else if (InWriters() && entry_->writers->network_transaction()) {
2472         SaveNetworkTransactionInfo(*(entry_->writers->network_transaction()));
2473         entry_->writers->ResetNetworkTransaction();
2474       }
2475       TransitionToState(STATE_START_PARTIAL_CACHE_VALIDATION);
2476     } else {
2477       TransitionToState(STATE_NONE);
2478     }
2479     return result;
2480   }
2481 
2482   // Request completed.
2483   if (result == 0) {
2484     DoneWithEntry(true);
2485   }
2486 
2487   TransitionToState(STATE_NONE);
2488   return result;
2489 }
2490 
DoNetworkRead()2491 int HttpCache::Transaction::DoNetworkRead() {
2492   TRACE_EVENT_WITH_FLOW2(
2493       "net", "HttpCacheTransaction::DoNetworkRead", TRACE_ID_LOCAL(trace_id_),
2494       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "read_offset",
2495       read_offset_, "read_buf_len", read_buf_len_);
2496   TransitionToState(STATE_NETWORK_READ_COMPLETE);
2497   return network_trans_->Read(read_buf_.get(), read_buf_len_, io_callback_);
2498 }
2499 
DoNetworkReadComplete(int result)2500 int HttpCache::Transaction::DoNetworkReadComplete(int result) {
2501   TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoNetworkReadComplete",
2502                          TRACE_ID_LOCAL(trace_id_),
2503                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
2504                          "result", result);
2505 
2506   if (!cache_.get()) {
2507     TransitionToState(STATE_NONE);
2508     return ERR_UNEXPECTED;
2509   }
2510 
2511   if (partial_)
2512     return DoPartialNetworkReadCompleted(result);
2513 
2514   TransitionToState(STATE_NONE);
2515   return result;
2516 }
2517 
DoCacheReadData()2518 int HttpCache::Transaction::DoCacheReadData() {
2519   if (entry_) {
2520     DCHECK(InWriters() || entry_->TransactionInReaders(this));
2521   }
2522 
2523   TRACE_EVENT_WITH_FLOW2(
2524       "net", "HttpCacheTransaction::DoCacheReadData", TRACE_ID_LOCAL(trace_id_),
2525       TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "read_offset",
2526       read_offset_, "read_buf_len", read_buf_len_);
2527 
2528   if (method_ == "HEAD") {
2529     TransitionToState(STATE_NONE);
2530     return 0;
2531   }
2532 
2533   DCHECK(entry_);
2534   TransitionToState(STATE_CACHE_READ_DATA_COMPLETE);
2535 
2536   net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_READ_DATA);
2537   if (partial_) {
2538     return partial_->CacheRead(entry_->GetEntry(), read_buf_.get(),
2539                                read_buf_len_, io_callback_);
2540   }
2541 
2542   BeginDiskCacheAccessTimeCount();
2543   return entry_->GetEntry()->ReadData(kResponseContentIndex, read_offset_,
2544                                       read_buf_.get(), read_buf_len_,
2545                                       io_callback_);
2546 }
2547 
DoCacheReadDataComplete(int result)2548 int HttpCache::Transaction::DoCacheReadDataComplete(int result) {
2549   EndDiskCacheAccessTimeCount(DiskCacheAccessType::kRead);
2550   if (entry_) {
2551     DCHECK(InWriters() || entry_->TransactionInReaders(this));
2552   }
2553 
2554   TRACE_EVENT_WITH_FLOW1("net", "HttpCacheTransaction::DoCacheReadDataComplete",
2555                          TRACE_ID_LOCAL(trace_id_),
2556                          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
2557                          "result", result);
2558   net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_READ_DATA,
2559                                     result);
2560 
2561   if (!cache_.get()) {
2562     TransitionToState(STATE_NONE);
2563     return ERR_UNEXPECTED;
2564   }
2565 
2566   if (partial_) {
2567     // Partial requests are confusing to report in histograms because they may
2568     // have multiple underlying requests.
2569     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
2570     return DoPartialCacheReadCompleted(result);
2571   }
2572 
2573   if (result > 0) {
2574     read_offset_ += result;
2575     if (checksum_)
2576       checksum_->Update(read_buf_->data(), result);
2577   } else if (result == 0) {  // End of file.
2578     if (!FinishAndCheckChecksum()) {
2579       TransitionToState(STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE);
2580       return result;
2581     }
2582 
2583     DoneWithEntry(true);
2584   } else {
2585     return OnCacheReadError(result, false);
2586   }
2587 
2588   TransitionToState(STATE_NONE);
2589   return result;
2590 }
2591 
DoMarkSingleKeyedCacheEntryUnusable()2592 int HttpCache::Transaction::DoMarkSingleKeyedCacheEntryUnusable() {
2593   DCHECK(use_single_keyed_cache_);
2594   response_.single_keyed_cache_entry_unusable = true;
2595   TransitionToState(STATE_MARK_SINGLE_KEYED_CACHE_ENTRY_UNUSABLE_COMPLETE);
2596   return WriteResponseInfoToEntry(response_, /*truncated=*/false);
2597 }
2598 
DoMarkSingleKeyedCacheEntryUnusableComplete(int result)2599 int HttpCache::Transaction::DoMarkSingleKeyedCacheEntryUnusableComplete(
2600     int result) {
2601   DCHECK_NE(result, ERR_IO_PENDING);
2602   TransitionToState(STATE_NONE);
2603   DoneWithEntry(/*entry_is_complete=*/true);
2604   if (result < 0)
2605     return result;
2606 
2607   // Return 0 to indicate that we've finished reading the body.
2608   return 0;
2609 }
2610 
2611 //-----------------------------------------------------------------------------
2612 
SetRequest(const NetLogWithSource & net_log)2613 void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log) {
2614   net_log_ = net_log;
2615 
2616   // Reset the variables that might get set in this function. This is done
2617   // because this function can be invoked multiple times for a transaction.
2618   cache_entry_status_ = CacheEntryStatus::ENTRY_UNDEFINED;
2619   external_validation_.Reset();
2620   range_requested_ = false;
2621   partial_.reset();
2622 
2623   request_ = initial_request_;
2624   custom_request_.reset();
2625 
2626   effective_load_flags_ = request_->load_flags;
2627   method_ = request_->method;
2628 
2629   if (!request_->checksum.empty())
2630     use_single_keyed_cache_ = true;
2631 
2632   if (cache_->mode() == DISABLE)
2633     effective_load_flags_ |= LOAD_DISABLE_CACHE;
2634 
2635   // Some headers imply load flags.  The order here is significant.
2636   //
2637   //   LOAD_DISABLE_CACHE   : no cache read or write
2638   //   LOAD_BYPASS_CACHE    : no cache read
2639   //   LOAD_VALIDATE_CACHE  : no cache read unless validation
2640   //
2641   // The former modes trump latter modes, so if we find a matching header we
2642   // can stop iterating kSpecialHeaders.
2643   //
2644   static const struct {
2645     // This field is not a raw_ptr<> because it was filtered by the rewriter
2646     // for: #global-scope
2647     RAW_PTR_EXCLUSION const HeaderNameAndValue* search;
2648     int load_flag;
2649   } kSpecialHeaders[] = {
2650     { kPassThroughHeaders, LOAD_DISABLE_CACHE },
2651     { kForceFetchHeaders, LOAD_BYPASS_CACHE },
2652     { kForceValidateHeaders, LOAD_VALIDATE_CACHE },
2653   };
2654 
2655   bool range_found = false;
2656   bool external_validation_error = false;
2657   bool special_headers = false;
2658 
2659   if (request_->extra_headers.HasHeader(HttpRequestHeaders::kRange))
2660     range_found = true;
2661 
2662   for (const auto& special_header : kSpecialHeaders) {
2663     if (HeaderMatches(request_->extra_headers, special_header.search)) {
2664       effective_load_flags_ |= special_header.load_flag;
2665       special_headers = true;
2666       break;
2667     }
2668   }
2669 
2670   // Check for conditionalization headers which may correspond with a
2671   // cache validation request.
2672   for (size_t i = 0; i < std::size(kValidationHeaders); ++i) {
2673     const ValidationHeaderInfo& info = kValidationHeaders[i];
2674     std::string validation_value;
2675     if (request_->extra_headers.GetHeader(
2676             info.request_header_name, &validation_value)) {
2677       if (!external_validation_.values[i].empty() ||
2678           validation_value.empty()) {
2679         external_validation_error = true;
2680       }
2681       external_validation_.values[i] = validation_value;
2682       external_validation_.initialized = true;
2683     }
2684   }
2685 
2686   if (range_found || special_headers || external_validation_.initialized) {
2687     // Log the headers before request_ is modified.
2688     std::string empty;
2689     NetLogRequestHeaders(net_log_,
2690                          NetLogEventType::HTTP_CACHE_CALLER_REQUEST_HEADERS,
2691                          empty, &request_->extra_headers);
2692   }
2693 
2694   // We don't support ranges and validation headers.
2695   if (range_found && external_validation_.initialized) {
2696     LOG(WARNING) << "Byte ranges AND validation headers found.";
2697     effective_load_flags_ |= LOAD_DISABLE_CACHE;
2698   }
2699 
2700   // If there is more than one validation header, we can't treat this request as
2701   // a cache validation, since we don't know for sure which header the server
2702   // will give us a response for (and they could be contradictory).
2703   if (external_validation_error) {
2704     LOG(WARNING) << "Multiple or malformed validation headers found.";
2705     effective_load_flags_ |= LOAD_DISABLE_CACHE;
2706   }
2707 
2708   if (range_found && !(effective_load_flags_ & LOAD_DISABLE_CACHE)) {
2709     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
2710     partial_ = std::make_unique<PartialData>();
2711     if (method_ == "GET" && partial_->Init(request_->extra_headers)) {
2712       // We will be modifying the actual range requested to the server, so
2713       // let's remove the header here.
2714       // Note that custom_request_ is a shallow copy so will keep the same
2715       // pointer to upload data stream as in the original request.
2716       custom_request_ = std::make_unique<HttpRequestInfo>(*request_);
2717       custom_request_->extra_headers.RemoveHeader(HttpRequestHeaders::kRange);
2718       request_ = custom_request_.get();
2719       partial_->SetHeaders(custom_request_->extra_headers);
2720     } else {
2721       // The range is invalid or we cannot handle it properly.
2722       VLOG(1) << "Invalid byte range found.";
2723       effective_load_flags_ |= LOAD_DISABLE_CACHE;
2724       partial_.reset(nullptr);
2725     }
2726   }
2727 }
2728 
ShouldPassThrough()2729 bool HttpCache::Transaction::ShouldPassThrough() {
2730   bool cacheable = true;
2731 
2732   // We may have a null disk_cache if there is an error we cannot recover from,
2733   // like not enough disk space, or sharing violations.
2734   if (!cache_->disk_cache_.get()) {
2735     cacheable = false;
2736   } else if (effective_load_flags_ & LOAD_DISABLE_CACHE) {
2737     cacheable = false;
2738   }
2739   // Prevent resources whose origin is opaque from being cached. Blink's memory
2740   // cache should take care of reusing resources within the current page load,
2741   // but otherwise a resource with an opaque top-frame origin won’t be used
2742   // again. Also, if the request does not have a top frame origin, bypass the
2743   // cache otherwise resources from different pages could share a cached entry
2744   // in such cases.
2745   else if (HttpCache::IsSplitCacheEnabled() &&
2746            request_->network_isolation_key.IsTransient()) {
2747     cacheable = false;
2748   } else if (method_ == "GET" || method_ == "HEAD") {
2749   } else if (method_ == "POST" && request_->upload_data_stream &&
2750              request_->upload_data_stream->identifier()) {
2751   } else if (method_ == "PUT" && request_->upload_data_stream) {
2752   }
2753   // DELETE and PATCH requests may result in invalidating the cache, so cannot
2754   // just pass through.
2755   else if (method_ == "DELETE" || method_ == "PATCH") {
2756   } else {
2757     cacheable = false;
2758   }
2759 
2760   return !cacheable;
2761 }
2762 
BeginCacheRead()2763 int HttpCache::Transaction::BeginCacheRead() {
2764   // We don't support any combination of LOAD_ONLY_FROM_CACHE and byte ranges.
2765   // It's possible to trigger this from JavaScript using the Fetch API with
2766   // `cache: 'only-if-cached'` so ideally we should support it.
2767   // TODO(ricea): Correctly read from the cache in this case.
2768   if (response_.headers->response_code() == net::HTTP_PARTIAL_CONTENT ||
2769       partial_) {
2770     TransitionToState(STATE_FINISH_HEADERS);
2771     return ERR_CACHE_MISS;
2772   }
2773 
2774   // We don't have the whole resource.
2775   if (truncated_) {
2776     TransitionToState(STATE_FINISH_HEADERS);
2777     return ERR_CACHE_MISS;
2778   }
2779 
2780   if (RequiresValidation() != VALIDATION_NONE) {
2781     TransitionToState(STATE_FINISH_HEADERS);
2782     return ERR_CACHE_MISS;
2783   }
2784 
2785   if (method_ == "HEAD")
2786     FixHeadersForHead();
2787 
2788   TransitionToState(STATE_FINISH_HEADERS);
2789   return OK;
2790 }
2791 
BeginCacheValidation()2792 int HttpCache::Transaction::BeginCacheValidation() {
2793   DCHECK_EQ(mode_, READ_WRITE);
2794 
2795   ValidationType required_validation = RequiresValidation();
2796 
2797   bool skip_validation = (required_validation == VALIDATION_NONE);
2798   bool needs_stale_while_revalidate_cache_update = false;
2799 
2800   if ((effective_load_flags_ & LOAD_SUPPORT_ASYNC_REVALIDATION) &&
2801       required_validation == VALIDATION_ASYNCHRONOUS) {
2802     DCHECK_EQ(request_->method, "GET");
2803     skip_validation = true;
2804     response_.async_revalidation_requested = true;
2805     needs_stale_while_revalidate_cache_update =
2806         response_.stale_revalidate_timeout.is_null();
2807   }
2808 
2809   if (method_ == "HEAD" && (truncated_ || response_.headers->response_code() ==
2810                                               net::HTTP_PARTIAL_CONTENT)) {
2811     DCHECK(!partial_);
2812     if (skip_validation) {
2813       DCHECK(!reading_);
2814       TransitionToState(STATE_CONNECTED_CALLBACK);
2815       return OK;
2816     }
2817 
2818     // Bail out!
2819     TransitionToState(STATE_SEND_REQUEST);
2820     mode_ = NONE;
2821     return OK;
2822   }
2823 
2824   if (truncated_) {
2825     // Truncated entries can cause partial gets, so we shouldn't record this
2826     // load in histograms.
2827     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
2828     skip_validation = !partial_->initial_validation();
2829   }
2830 
2831   // If this is the first request (!reading_) of a 206 entry (is_sparse_) that
2832   // doesn't actually cover the entire file (which with !reading would require
2833   // partial->IsLastRange()), and the user is requesting the whole thing
2834   // (!partial_->range_requested()), make sure to validate the first chunk,
2835   // since afterwards it will be too late if it's actually out-of-date (or the
2836   // server bungles invalidation). This is limited to the whole-file request
2837   // as a targeted fix for https://crbug.com/888742 while avoiding extra
2838   // requests in other cases, but the problem can occur more generally as well;
2839   // it's just a lot less likely with applications actively using ranges.
2840   // See https://crbug.com/902724 for the more general case.
2841   bool first_read_of_full_from_partial =
2842       is_sparse_ && !reading_ &&
2843       (partial_ && !partial_->range_requested() && !partial_->IsLastRange());
2844 
2845   if (partial_ && (is_sparse_ || truncated_) &&
2846       (!partial_->IsCurrentRangeCached() || invalid_range_ ||
2847        first_read_of_full_from_partial)) {
2848     // Force revalidation for sparse or truncated entries. Note that we don't
2849     // want to ignore the regular validation logic just because a byte range was
2850     // part of the request.
2851     skip_validation = false;
2852   }
2853 
2854   if (skip_validation) {
2855     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_USED);
2856     DCHECK(!reading_);
2857     TransitionToState(needs_stale_while_revalidate_cache_update
2858                           ? STATE_CACHE_UPDATE_STALE_WHILE_REVALIDATE_TIMEOUT
2859                           : STATE_CONNECTED_CALLBACK);
2860     return OK;
2861   } else {
2862     // Make the network request conditional, to see if we may reuse our cached
2863     // response.  If we cannot do so, then we just resort to a normal fetch.
2864     // Our mode remains READ_WRITE for a conditional request.  Even if the
2865     // conditionalization fails, we don't switch to WRITE mode until we
2866     // know we won't be falling back to using the cache entry in the
2867     // LOAD_FROM_CACHE_IF_OFFLINE case.
2868     if (!ConditionalizeRequest()) {
2869       couldnt_conditionalize_request_ = true;
2870       UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE);
2871       if (partial_)
2872         return DoRestartPartialRequest();
2873 
2874       DCHECK_NE(net::HTTP_PARTIAL_CONTENT, response_.headers->response_code());
2875     }
2876     TransitionToState(STATE_SEND_REQUEST);
2877   }
2878   return OK;
2879 }
2880 
BeginPartialCacheValidation()2881 int HttpCache::Transaction::BeginPartialCacheValidation() {
2882   DCHECK_EQ(mode_, READ_WRITE);
2883 
2884   if (response_.headers->response_code() != net::HTTP_PARTIAL_CONTENT &&
2885       !partial_ && !truncated_)
2886     return BeginCacheValidation();
2887 
2888   // Partial requests should not be recorded in histograms.
2889   UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
2890   if (method_ == "HEAD")
2891     return BeginCacheValidation();
2892 
2893   if (!range_requested_) {
2894     // The request is not for a range, but we have stored just ranges.
2895 
2896     partial_ = std::make_unique<PartialData>();
2897     partial_->SetHeaders(request_->extra_headers);
2898     if (!custom_request_.get()) {
2899       custom_request_ = std::make_unique<HttpRequestInfo>(*request_);
2900       request_ = custom_request_.get();
2901     }
2902   }
2903 
2904   TransitionToState(STATE_CACHE_QUERY_DATA);
2905   return OK;
2906 }
2907 
2908 // This should only be called once per request.
ValidateEntryHeadersAndContinue()2909 int HttpCache::Transaction::ValidateEntryHeadersAndContinue() {
2910   DCHECK_EQ(mode_, READ_WRITE);
2911 
2912   if (!partial_->UpdateFromStoredHeaders(
2913           response_.headers.get(), entry_->GetEntry(), truncated_,
2914           cache_->IsWritingInProgress(entry()))) {
2915     return DoRestartPartialRequest();
2916   }
2917 
2918   if (response_.headers->response_code() == net::HTTP_PARTIAL_CONTENT)
2919     is_sparse_ = true;
2920 
2921   if (!partial_->IsRequestedRangeOK()) {
2922     // The stored data is fine, but the request may be invalid.
2923     invalid_range_ = true;
2924   }
2925 
2926   TransitionToState(STATE_START_PARTIAL_CACHE_VALIDATION);
2927   return OK;
2928 }
2929 
2930 bool HttpCache::Transaction::
ExternallyConditionalizedValidationHeadersMatchEntry() const2931     ExternallyConditionalizedValidationHeadersMatchEntry() const {
2932   DCHECK(external_validation_.initialized);
2933 
2934   for (size_t i = 0; i < std::size(kValidationHeaders); i++) {
2935     if (external_validation_.values[i].empty())
2936       continue;
2937 
2938     // Retrieve either the cached response's "etag" or "last-modified" header.
2939     std::string validator;
2940     response_.headers->EnumerateHeader(
2941         nullptr, kValidationHeaders[i].related_response_header_name,
2942         &validator);
2943 
2944     if (validator != external_validation_.values[i]) {
2945       return false;
2946     }
2947   }
2948 
2949   return true;
2950 }
2951 
BeginExternallyConditionalizedRequest()2952 int HttpCache::Transaction::BeginExternallyConditionalizedRequest() {
2953   DCHECK_EQ(UPDATE, mode_);
2954 
2955   if (response_.headers->response_code() != net::HTTP_OK || truncated_ ||
2956       !ExternallyConditionalizedValidationHeadersMatchEntry()) {
2957     // The externally conditionalized request is not a validation request
2958     // for our existing cache entry. Proceed with caching disabled.
2959     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
2960     DoneWithEntry(true);
2961   }
2962 
2963   TransitionToState(STATE_SEND_REQUEST);
2964   return OK;
2965 }
2966 
RestartNetworkRequest()2967 int HttpCache::Transaction::RestartNetworkRequest() {
2968   DCHECK(mode_ & WRITE || mode_ == NONE);
2969   DCHECK(network_trans_.get());
2970   DCHECK_EQ(STATE_NONE, next_state_);
2971 
2972   next_state_ = STATE_SEND_REQUEST_COMPLETE;
2973   int rv = network_trans_->RestartIgnoringLastError(io_callback_);
2974   if (rv != ERR_IO_PENDING)
2975     return DoLoop(rv);
2976   return rv;
2977 }
2978 
RestartNetworkRequestWithCertificate(scoped_refptr<X509Certificate> client_cert,scoped_refptr<SSLPrivateKey> client_private_key)2979 int HttpCache::Transaction::RestartNetworkRequestWithCertificate(
2980     scoped_refptr<X509Certificate> client_cert,
2981     scoped_refptr<SSLPrivateKey> client_private_key) {
2982   DCHECK(mode_ & WRITE || mode_ == NONE);
2983   DCHECK(network_trans_.get());
2984   DCHECK_EQ(STATE_NONE, next_state_);
2985 
2986   next_state_ = STATE_SEND_REQUEST_COMPLETE;
2987   int rv = network_trans_->RestartWithCertificate(
2988       std::move(client_cert), std::move(client_private_key), io_callback_);
2989   if (rv != ERR_IO_PENDING)
2990     return DoLoop(rv);
2991   return rv;
2992 }
2993 
RestartNetworkRequestWithAuth(const AuthCredentials & credentials)2994 int HttpCache::Transaction::RestartNetworkRequestWithAuth(
2995     const AuthCredentials& credentials) {
2996   DCHECK(mode_ & WRITE || mode_ == NONE);
2997   DCHECK(network_trans_.get());
2998   DCHECK_EQ(STATE_NONE, next_state_);
2999 
3000   next_state_ = STATE_SEND_REQUEST_COMPLETE;
3001   int rv = network_trans_->RestartWithAuth(credentials, io_callback_);
3002   if (rv != ERR_IO_PENDING)
3003     return DoLoop(rv);
3004   return rv;
3005 }
3006 
3007 // These values are persisted to logs. Entries should not be renumbered and
3008 // numeric values should never be reused.
3009 enum class PrefetchReuseState : uint8_t {
3010   kNone = 0,
3011 
3012   // Bit 0 represents if it's reused first time
3013   kFirstReuse = 1 << 0,
3014 
3015   // Bit 1 represents if it's reused within the time window
3016   kReusedWithinTimeWindow = 1 << 1,
3017 
3018   // Bit 2-3 represents the freshness based on cache headers
3019   kFresh = 0 << 2,
3020   kAlwaysValidate = 1 << 2,
3021   kExpired = 2 << 2,
3022   kStale = 3 << 2,
3023 
3024   // histograms require a named max value
3025   kBitMaskForAllAttributes = kStale | kReusedWithinTimeWindow | kFirstReuse,
3026   kMaxValue = kBitMaskForAllAttributes
3027 };
3028 
3029 namespace {
to_underlying(PrefetchReuseState state)3030 std::underlying_type<PrefetchReuseState>::type to_underlying(
3031     PrefetchReuseState state) {
3032   DCHECK_LE(PrefetchReuseState::kNone, state);
3033   DCHECK_LE(state, PrefetchReuseState::kMaxValue);
3034 
3035   return static_cast<std::underlying_type<PrefetchReuseState>::type>(state);
3036 }
3037 
to_reuse_state(std::underlying_type<PrefetchReuseState>::type value)3038 PrefetchReuseState to_reuse_state(
3039     std::underlying_type<PrefetchReuseState>::type value) {
3040   PrefetchReuseState state = static_cast<PrefetchReuseState>(value);
3041   DCHECK_LE(PrefetchReuseState::kNone, state);
3042   DCHECK_LE(state, PrefetchReuseState::kMaxValue);
3043   return state;
3044 }
3045 }  // namespace
3046 
ComputePrefetchReuseState(ValidationType type,bool first_reuse,bool reused_within_time_window,bool validate_flag)3047 PrefetchReuseState ComputePrefetchReuseState(ValidationType type,
3048                                              bool first_reuse,
3049                                              bool reused_within_time_window,
3050                                              bool validate_flag) {
3051   std::underlying_type<PrefetchReuseState>::type reuse_state =
3052       to_underlying(PrefetchReuseState::kNone);
3053 
3054   if (first_reuse)
3055     reuse_state |= to_underlying(PrefetchReuseState::kFirstReuse);
3056 
3057   if (reused_within_time_window)
3058     reuse_state |= to_underlying(PrefetchReuseState::kReusedWithinTimeWindow);
3059 
3060   if (validate_flag)
3061     reuse_state |= to_underlying(PrefetchReuseState::kAlwaysValidate);
3062   else {
3063     switch (type) {
3064       case VALIDATION_SYNCHRONOUS:
3065         reuse_state |= to_underlying(PrefetchReuseState::kExpired);
3066         break;
3067       case VALIDATION_ASYNCHRONOUS:
3068         reuse_state |= to_underlying(PrefetchReuseState::kStale);
3069         break;
3070       case VALIDATION_NONE:
3071         reuse_state |= to_underlying(PrefetchReuseState::kFresh);
3072         break;
3073     }
3074   }
3075   return to_reuse_state(reuse_state);
3076 }
3077 
RequiresValidation()3078 ValidationType HttpCache::Transaction::RequiresValidation() {
3079   // TODO(darin): need to do more work here:
3080   //  - make sure we have a matching request method
3081   //  - watch out for cached responses that depend on authentication
3082 
3083   if (!(effective_load_flags_ & LOAD_SKIP_VARY_CHECK) &&
3084       response_.vary_data.is_valid() &&
3085       !response_.vary_data.MatchesRequest(*request_,
3086                                           *response_.headers.get())) {
3087     vary_mismatch_ = true;
3088     validation_cause_ = VALIDATION_CAUSE_VARY_MISMATCH;
3089     return VALIDATION_SYNCHRONOUS;
3090   }
3091 
3092   if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION)
3093     return VALIDATION_NONE;
3094 
3095   if (method_ == "PUT" || method_ == "DELETE" || method_ == "PATCH")
3096     return VALIDATION_SYNCHRONOUS;
3097 
3098   bool validate_flag = effective_load_flags_ & LOAD_VALIDATE_CACHE;
3099 
3100   ValidationType validation_required_by_headers =
3101       validate_flag ? VALIDATION_SYNCHRONOUS
3102                     : response_.headers->RequiresValidation(
3103                           response_.request_time, response_.response_time,
3104                           cache_->clock_->Now());
3105 
3106   base::TimeDelta response_time_in_cache =
3107       cache_->clock_->Now() - response_.response_time;
3108 
3109   if (!base::FeatureList::IsEnabled(
3110           features::kPrefetchFollowsNormalCacheSemantics) &&
3111       !(effective_load_flags_ & LOAD_PREFETCH) &&
3112       (response_time_in_cache >= base::TimeDelta())) {
3113     bool reused_within_time_window =
3114         response_time_in_cache < base::Minutes(kPrefetchReuseMins);
3115     bool first_reuse = response_.unused_since_prefetch;
3116 
3117     base::UmaHistogramLongTimes("HttpCache.PrefetchReuseTime",
3118                                 response_time_in_cache);
3119     if (first_reuse) {
3120       base::UmaHistogramLongTimes("HttpCache.PrefetchFirstReuseTime",
3121                                   response_time_in_cache);
3122     }
3123 
3124     base::UmaHistogramEnumeration(
3125         "HttpCache.PrefetchReuseState",
3126         ComputePrefetchReuseState(validation_required_by_headers, first_reuse,
3127                                   reused_within_time_window, validate_flag));
3128     // The first use of a resource after prefetch within a short window skips
3129     // validation.
3130     if (first_reuse && reused_within_time_window) {
3131       return VALIDATION_NONE;
3132     }
3133   }
3134 
3135   if (validate_flag) {
3136     validation_cause_ = VALIDATION_CAUSE_VALIDATE_FLAG;
3137     return VALIDATION_SYNCHRONOUS;
3138   }
3139 
3140   if (validation_required_by_headers != VALIDATION_NONE) {
3141     HttpResponseHeaders::FreshnessLifetimes lifetimes =
3142         response_.headers->GetFreshnessLifetimes(response_.response_time);
3143     if (lifetimes.freshness == base::TimeDelta()) {
3144       validation_cause_ = VALIDATION_CAUSE_ZERO_FRESHNESS;
3145     } else {
3146       validation_cause_ = VALIDATION_CAUSE_STALE;
3147     }
3148   }
3149 
3150   if (validation_required_by_headers == VALIDATION_ASYNCHRONOUS) {
3151     // Asynchronous revalidation is only supported for GET methods.
3152     if (request_->method != "GET")
3153       return VALIDATION_SYNCHRONOUS;
3154 
3155     // If the timeout on the staleness revalidation is set don't hand out
3156     // a resource that hasn't been async validated.
3157     if (!response_.stale_revalidate_timeout.is_null() &&
3158         response_.stale_revalidate_timeout < cache_->clock_->Now()) {
3159       return VALIDATION_SYNCHRONOUS;
3160     }
3161   }
3162 
3163   return validation_required_by_headers;
3164 }
3165 
IsResponseConditionalizable(std::string * etag_value,std::string * last_modified_value) const3166 bool HttpCache::Transaction::IsResponseConditionalizable(
3167     std::string* etag_value,
3168     std::string* last_modified_value) const {
3169   DCHECK(response_.headers.get());
3170 
3171   // This only makes sense for cached 200 or 206 responses.
3172   if (response_.headers->response_code() != net::HTTP_OK &&
3173       response_.headers->response_code() != net::HTTP_PARTIAL_CONTENT) {
3174     return false;
3175   }
3176 
3177   // Just use the first available ETag and/or Last-Modified header value.
3178   // TODO(darin): Or should we use the last?
3179 
3180   if (response_.headers->GetHttpVersion() >= HttpVersion(1, 1))
3181     response_.headers->EnumerateHeader(nullptr, "etag", etag_value);
3182 
3183   response_.headers->EnumerateHeader(nullptr, "last-modified",
3184                                      last_modified_value);
3185 
3186   if (etag_value->empty() && last_modified_value->empty())
3187     return false;
3188 
3189   return true;
3190 }
3191 
ShouldOpenOnlyMethods() const3192 bool HttpCache::Transaction::ShouldOpenOnlyMethods() const {
3193   // These methods indicate that we should only try to open an entry and not
3194   // fallback to create.
3195   return method_ == "PUT" || method_ == "DELETE" || method_ == "PATCH" ||
3196          (method_ == "HEAD" && mode_ == READ_WRITE);
3197 }
3198 
ConditionalizeRequest()3199 bool HttpCache::Transaction::ConditionalizeRequest() {
3200   DCHECK(response_.headers.get());
3201 
3202   if (method_ == "PUT" || method_ == "DELETE" || method_ == "PATCH")
3203     return false;
3204 
3205   if (fail_conditionalization_for_test_)
3206     return false;
3207 
3208   std::string etag_value;
3209   std::string last_modified_value;
3210   if (!IsResponseConditionalizable(&etag_value, &last_modified_value))
3211     return false;
3212 
3213   DCHECK(response_.headers->response_code() != net::HTTP_PARTIAL_CONTENT ||
3214          response_.headers->HasStrongValidators());
3215 
3216   if (vary_mismatch_) {
3217     // Can't rely on last-modified if vary is different.
3218     last_modified_value.clear();
3219     if (etag_value.empty())
3220       return false;
3221   }
3222 
3223   if (!partial_) {
3224     // Need to customize the request, so this forces us to allocate :(
3225     custom_request_ = std::make_unique<HttpRequestInfo>(*request_);
3226     request_ = custom_request_.get();
3227   }
3228   DCHECK(custom_request_.get());
3229 
3230   bool use_if_range =
3231       partial_ && !partial_->IsCurrentRangeCached() && !invalid_range_;
3232 
3233   if (!etag_value.empty()) {
3234     if (use_if_range) {
3235       // We don't want to switch to WRITE mode if we don't have this block of a
3236       // byte-range request because we may have other parts cached.
3237       custom_request_->extra_headers.SetHeader(
3238           HttpRequestHeaders::kIfRange, etag_value);
3239     } else {
3240       custom_request_->extra_headers.SetHeader(
3241           HttpRequestHeaders::kIfNoneMatch, etag_value);
3242     }
3243     // For byte-range requests, make sure that we use only one way to validate
3244     // the request.
3245     if (partial_ && !partial_->IsCurrentRangeCached())
3246       return true;
3247   }
3248 
3249   if (!last_modified_value.empty()) {
3250     if (use_if_range) {
3251       custom_request_->extra_headers.SetHeader(
3252           HttpRequestHeaders::kIfRange, last_modified_value);
3253     } else {
3254       custom_request_->extra_headers.SetHeader(
3255           HttpRequestHeaders::kIfModifiedSince, last_modified_value);
3256     }
3257   }
3258 
3259   return true;
3260 }
3261 
MaybeRejectBasedOnEntryInMemoryData(uint8_t in_memory_info)3262 bool HttpCache::Transaction::MaybeRejectBasedOnEntryInMemoryData(
3263     uint8_t in_memory_info) {
3264   // Not going to be clever with those...
3265   if (partial_)
3266     return false;
3267 
3268   // Avoiding open based on in-memory hints requires us to be permitted to
3269   // modify the cache, including deleting an old entry. Only the READ_WRITE
3270   // and WRITE modes permit that... and WRITE never tries to open entries in the
3271   // first place, so we shouldn't see it here.
3272   DCHECK_NE(mode_, WRITE);
3273   if (mode_ != READ_WRITE)
3274     return false;
3275 
3276   // If we are loading ignoring cache validity (aka back button), obviously
3277   // can't reject things based on it.  Also if LOAD_ONLY_FROM_CACHE there is no
3278   // hope of network offering anything better.
3279   if (effective_load_flags_ & LOAD_SKIP_CACHE_VALIDATION ||
3280       effective_load_flags_ & LOAD_ONLY_FROM_CACHE)
3281     return false;
3282 
3283   return (in_memory_info & HINT_UNUSABLE_PER_CACHING_HEADERS) ==
3284          HINT_UNUSABLE_PER_CACHING_HEADERS;
3285 }
3286 
ComputeUnusablePerCachingHeaders()3287 bool HttpCache::Transaction::ComputeUnusablePerCachingHeaders() {
3288   // unused_since_prefetch overrides some caching headers, so it may be useful
3289   // regardless of what they say.
3290   if (response_.unused_since_prefetch)
3291     return false;
3292 
3293   // Has an e-tag or last-modified: we can probably send a conditional request,
3294   // so it's potentially useful.
3295   std::string etag_ignored, last_modified_ignored;
3296   if (IsResponseConditionalizable(&etag_ignored, &last_modified_ignored))
3297     return false;
3298 
3299   // If none of the above is true and the entry has zero freshness, then it
3300   // won't be usable absent load flag override.
3301   return response_.headers->GetFreshnessLifetimes(response_.response_time)
3302       .freshness.is_zero();
3303 }
3304 
3305 // We just received some headers from the server. We may have asked for a range,
3306 // in which case partial_ has an object. This could be the first network request
3307 // we make to fulfill the original request, or we may be already reading (from
3308 // the net and / or the cache). If we are not expecting a certain response, we
3309 // just bypass the cache for this request (but again, maybe we are reading), and
3310 // delete partial_ (so we are not able to "fix" the headers that we return to
3311 // the user). This results in either a weird response for the caller (we don't
3312 // expect it after all), or maybe a range that was not exactly what it was asked
3313 // for.
3314 //
3315 // If the server is simply telling us that the resource has changed, we delete
3316 // the cached entry and restart the request as the caller intended (by returning
3317 // false from this method). However, we may not be able to do that at any point,
3318 // for instance if we already returned the headers to the user.
3319 //
3320 // WARNING: Whenever this code returns false, it has to make sure that the next
3321 // time it is called it will return true so that we don't keep retrying the
3322 // request.
ValidatePartialResponse()3323 bool HttpCache::Transaction::ValidatePartialResponse() {
3324   const HttpResponseHeaders* headers = new_response_->headers.get();
3325   int response_code = headers->response_code();
3326   bool partial_response = (response_code == net::HTTP_PARTIAL_CONTENT);
3327   handling_206_ = false;
3328 
3329   if (!entry_ || method_ != "GET")
3330     return true;
3331 
3332   if (invalid_range_) {
3333     // We gave up trying to match this request with the stored data. If the
3334     // server is ok with the request, delete the entry, otherwise just ignore
3335     // this request
3336     DCHECK(!reading_);
3337     if (partial_response || response_code == net::HTTP_OK) {
3338       DoomPartialEntry(true);
3339       mode_ = NONE;
3340     } else {
3341       if (response_code == net::HTTP_NOT_MODIFIED) {
3342         // Change the response code of the request to be 416 (Requested range
3343         // not satisfiable).
3344         SetResponse(*new_response_);
3345         partial_->FixResponseHeaders(response_.headers.get(), false);
3346       }
3347       IgnoreRangeRequest();
3348     }
3349     return true;
3350   }
3351 
3352   if (!partial_) {
3353     // We are not expecting 206 but we may have one.
3354     if (partial_response)
3355       IgnoreRangeRequest();
3356 
3357     return true;
3358   }
3359 
3360   // TODO(rvargas): Do we need to consider other results here?.
3361   bool failure = response_code == net::HTTP_OK ||
3362                  response_code == net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE;
3363 
3364   if (partial_->IsCurrentRangeCached()) {
3365     // We asked for "If-None-Match: " so a 206 means a new object.
3366     if (partial_response)
3367       failure = true;
3368 
3369     if (response_code == net::HTTP_NOT_MODIFIED &&
3370         partial_->ResponseHeadersOK(headers))
3371       return true;
3372   } else {
3373     // We asked for "If-Range: " so a 206 means just another range.
3374     if (partial_response) {
3375       if (partial_->ResponseHeadersOK(headers)) {
3376         handling_206_ = true;
3377         return true;
3378       } else {
3379         failure = true;
3380       }
3381     }
3382 
3383     if (!reading_ && !is_sparse_ && !partial_response) {
3384       // See if we can ignore the fact that we issued a byte range request.
3385       // If the server sends 200, just store it. If it sends an error, redirect
3386       // or something else, we may store the response as long as we didn't have
3387       // anything already stored.
3388       if (response_code == net::HTTP_OK ||
3389           (!truncated_ && response_code != net::HTTP_NOT_MODIFIED &&
3390            response_code != net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE)) {
3391         // The server is sending something else, and we can save it.
3392         DCHECK((truncated_ && !partial_->IsLastRange()) || range_requested_);
3393         partial_.reset();
3394         truncated_ = false;
3395         return true;
3396       }
3397     }
3398 
3399     // 304 is not expected here, but we'll spare the entry (unless it was
3400     // truncated).
3401     if (truncated_)
3402       failure = true;
3403   }
3404 
3405   if (failure) {
3406     // We cannot truncate this entry, it has to be deleted.
3407     UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
3408     mode_ = NONE;
3409     if (is_sparse_ || truncated_) {
3410       // There was something cached to start with, either sparsed data (206), or
3411       // a truncated 200, which means that we probably modified the request,
3412       // adding a byte range or modifying the range requested by the caller.
3413       if (!reading_ && !partial_->IsLastRange()) {
3414         // We have not returned anything to the caller yet so it should be safe
3415         // to issue another network request, this time without us messing up the
3416         // headers.
3417         ResetPartialState(true);
3418         return false;
3419       }
3420       LOG(WARNING) << "Failed to revalidate partial entry";
3421     }
3422     DoomPartialEntry(true);
3423     return true;
3424   }
3425 
3426   IgnoreRangeRequest();
3427   return true;
3428 }
3429 
IgnoreRangeRequest()3430 void HttpCache::Transaction::IgnoreRangeRequest() {
3431   // We have a problem. We may or may not be reading already (in which case we
3432   // returned the headers), but we'll just pretend that this request is not
3433   // using the cache and see what happens. Most likely this is the first
3434   // response from the server (it's not changing its mind midway, right?).
3435   UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
3436   DoneWithEntry(mode_ != WRITE);
3437   partial_.reset(nullptr);
3438 }
3439 
3440 // Called to signal to the consumer that we are about to read headers from a
3441 // cached entry originally read from a given IP endpoint.
DoConnectedCallback()3442 int HttpCache::Transaction::DoConnectedCallback() {
3443   TransitionToState(STATE_CONNECTED_CALLBACK_COMPLETE);
3444   if (connected_callback_.is_null()) {
3445     return OK;
3446   }
3447 
3448   auto type = response_.was_fetched_via_proxy ? TransportType::kCachedFromProxy
3449                                               : TransportType::kCached;
3450   return connected_callback_.Run(
3451       TransportInfo(type, response_.remote_endpoint, ""), io_callback_);
3452 }
3453 
DoConnectedCallbackComplete(int result)3454 int HttpCache::Transaction::DoConnectedCallbackComplete(int result) {
3455   if (result != OK) {
3456     if (result ==
3457         ERR_CACHED_IP_ADDRESS_SPACE_BLOCKED_BY_LOCAL_NETWORK_ACCESS_POLICY) {
3458       DoomInconsistentEntry();
3459       UpdateCacheEntryStatus(CacheEntryStatus::ENTRY_OTHER);
3460       TransitionToState(reading_ ? STATE_SEND_REQUEST
3461                                  : STATE_HEADERS_PHASE_CANNOT_PROCEED);
3462       return OK;
3463     }
3464 
3465     if (result == ERR_INCONSISTENT_IP_ADDRESS_SPACE) {
3466       DoomInconsistentEntry();
3467     } else {
3468       // Release the entry for further use - we are done using it.
3469       DoneWithEntry(/*entry_is_complete=*/true);
3470     }
3471 
3472     TransitionToState(STATE_NONE);
3473     return result;
3474   }
3475 
3476   if (reading_) {
3477     // We can only get here if we're reading a partial range of bytes from the
3478     // cache. In that case, proceed to read the bytes themselves.
3479     DCHECK(partial_);
3480     TransitionToState(STATE_CACHE_READ_DATA);
3481   } else {
3482     // Otherwise, we have just read headers from the cache.
3483     TransitionToState(STATE_SETUP_ENTRY_FOR_READ);
3484   }
3485   return OK;
3486 }
3487 
DoomInconsistentEntry()3488 void HttpCache::Transaction::DoomInconsistentEntry() {
3489   // Explicitly call `DoomActiveEntry()` ourselves before calling
3490   // `DoneWithEntry()` because we cannot rely on the latter doing it for us.
3491   // Indeed, `DoneWithEntry(false)` does not call `DoomActiveEntry()` if either
3492   // of the following conditions hold:
3493   //
3494   //  - the transaction uses the cache in read-only mode
3495   //  - the transaction has passed the headers phase and is reading
3496   //
3497   // Inconsistent cache entries can cause deterministic failures even in
3498   // read-only mode, so they should be doomed anyway. They can also be detected
3499   // during the reading phase in the case of split range requests, since those
3500   // requests can result in multiple connections being obtained to different
3501   // remote endpoints.
3502   cache_->DoomActiveEntry(cache_key_);
3503   DoneWithEntry(/*entry_is_complete=*/false);
3504 }
3505 
FixHeadersForHead()3506 void HttpCache::Transaction::FixHeadersForHead() {
3507   if (response_.headers->response_code() == net::HTTP_PARTIAL_CONTENT) {
3508     response_.headers->RemoveHeader("Content-Range");
3509     response_.headers->ReplaceStatusLine("HTTP/1.1 200 OK");
3510   }
3511 }
3512 
DoSetupEntryForRead()3513 int HttpCache::Transaction::DoSetupEntryForRead() {
3514   if (network_trans_)
3515     ResetNetworkTransaction();
3516 
3517   if (!entry_) {
3518     // Entry got destroyed when twiddling SWR bits.
3519     TransitionToState(STATE_HEADERS_PHASE_CANNOT_PROCEED);
3520     return OK;
3521   }
3522 
3523   if (partial_) {
3524     if (truncated_ || is_sparse_ ||
3525         (!invalid_range_ &&
3526          (response_.headers->response_code() == net::HTTP_OK ||
3527           response_.headers->response_code() == net::HTTP_PARTIAL_CONTENT))) {
3528       // We are going to return the saved response headers to the caller, so
3529       // we may need to adjust them first. In cases we are handling a range
3530       // request to a regular entry, we want the response to be a 200 or 206,
3531       // since others can't really be turned into a 206.
3532       TransitionToState(STATE_PARTIAL_HEADERS_RECEIVED);
3533       return OK;
3534     } else {
3535       partial_.reset();
3536     }
3537   }
3538 
3539   if (!cache_->IsWritingInProgress(entry_))
3540     mode_ = READ;
3541 
3542   if (method_ == "HEAD")
3543     FixHeadersForHead();
3544 
3545   TransitionToState(STATE_FINISH_HEADERS);
3546   return OK;
3547 }
3548 
WriteResponseInfoToEntry(const HttpResponseInfo & response,bool truncated)3549 int HttpCache::Transaction::WriteResponseInfoToEntry(
3550     const HttpResponseInfo& response,
3551     bool truncated) {
3552   DCHECK(response.headers);
3553 
3554   if (!entry_)
3555     return OK;
3556 
3557   net_log_.BeginEvent(NetLogEventType::HTTP_CACHE_WRITE_INFO);
3558 
3559   // Do not cache content with cert errors. This is to prevent not reporting net
3560   // errors when loading a resource from the cache.  When we load a page over
3561   // HTTPS with a cert error we show an SSL blocking page.  If the user clicks
3562   // proceed we reload the resource ignoring the errors.  The loaded resource is
3563   // then cached.  If that resource is subsequently loaded from the cache, no
3564   // net error is reported (even though the cert status contains the actual
3565   // errors) and no SSL blocking page is shown.  An alternative would be to
3566   // reverse-map the cert status to a net error and replay the net error.
3567   if (IsCertStatusError(response.ssl_info.cert_status) ||
3568       ShouldDisableCaching(*response.headers)) {
3569     if (partial_)
3570       partial_->FixResponseHeaders(response_.headers.get(), true);
3571 
3572     bool stopped = StopCachingImpl(false);
3573     DCHECK(stopped);
3574     net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_INFO,
3575                                       OK);
3576     return OK;
3577   }
3578 
3579   if (truncated)
3580     DCHECK_EQ(net::HTTP_OK, response.headers->response_code());
3581 
3582   // When writing headers, we normally only write the non-transient headers.
3583   bool skip_transient_headers = true;
3584   auto data = base::MakeRefCounted<PickledIOBuffer>();
3585   response.Persist(data->pickle(), skip_transient_headers, truncated);
3586   data->Done();
3587 
3588   io_buf_len_ = data->pickle()->size();
3589 
3590   // Summarize some info on cacheability in memory. Don't do it if doomed
3591   // since then |entry_| isn't definitive for |cache_key_|.
3592   if (!entry_->doomed) {
3593     cache_->GetCurrentBackend()->SetEntryInMemoryData(
3594         cache_key_, ComputeUnusablePerCachingHeaders()
3595                         ? HINT_UNUSABLE_PER_CACHING_HEADERS
3596                         : 0);
3597   }
3598 
3599   BeginDiskCacheAccessTimeCount();
3600   return entry_->disk_entry->WriteData(kResponseInfoIndex, 0, data.get(),
3601                                        io_buf_len_, io_callback_, true);
3602 }
3603 
OnWriteResponseInfoToEntryComplete(int result)3604 int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) {
3605   EndDiskCacheAccessTimeCount(DiskCacheAccessType::kWrite);
3606   if (!entry_)
3607     return OK;
3608   net_log_.EndEventWithNetErrorCode(NetLogEventType::HTTP_CACHE_WRITE_INFO,
3609                                     result);
3610 
3611   if (result != io_buf_len_) {
3612     DLOG(ERROR) << "failed to write response info to cache";
3613     DoneWithEntry(false);
3614   }
3615   return OK;
3616 }
3617 
StopCachingImpl(bool success)3618 bool HttpCache::Transaction::StopCachingImpl(bool success) {
3619   bool stopped = false;
3620   // Let writers know so that it doesn't attempt to write to the cache.
3621   if (InWriters()) {
3622     stopped = entry_->writers->StopCaching(success /* keep_entry */);
3623     if (stopped)
3624       mode_ = NONE;
3625   } else if (entry_) {
3626     stopped = true;
3627     DoneWithEntry(success /* entry_is_complete */);
3628   }
3629   return stopped;
3630 }
3631 
DoneWithEntry(bool entry_is_complete)3632 void HttpCache::Transaction::DoneWithEntry(bool entry_is_complete) {
3633   if (!entry_)
3634     return;
3635 
3636   cache_->DoneWithEntry(entry_, this, entry_is_complete, partial_ != nullptr);
3637   entry_ = nullptr;
3638   mode_ = NONE;  // switch to 'pass through' mode
3639 }
3640 
DoneWithEntryForRestartWithCache()3641 void HttpCache::Transaction::DoneWithEntryForRestartWithCache() {
3642   if (!entry_)
3643     return;
3644 
3645   cache_->DoneWithEntry(entry_, this, /*entry_is_complete=*/true,
3646                         partial_ != nullptr);
3647   entry_ = nullptr;
3648   new_entry_ = nullptr;
3649 }
3650 
OnCacheReadError(int result,bool restart)3651 int HttpCache::Transaction::OnCacheReadError(int result, bool restart) {
3652   DLOG(ERROR) << "ReadData failed: " << result;
3653   const int result_for_histogram = std::max(0, -result);
3654   if (restart) {
3655     base::UmaHistogramSparse("HttpCache.ReadErrorRestartable",
3656                              result_for_histogram);
3657   } else {
3658     base::UmaHistogramSparse("HttpCache.ReadErrorNonRestartable",
3659                              result_for_histogram);
3660   }
3661 
3662   // Avoid using this entry in the future.
3663   if (cache_.get())
3664     cache_->DoomActiveEntry(cache_key_);
3665 
3666   if (restart) {
3667     DCHECK(!reading_);
3668     DCHECK(!network_trans_.get());
3669 
3670     // Since we are going to add this to a new entry, not recording histograms
3671     // or setting mode to NONE at this point by invoking the wrapper
3672     // DoneWithEntry.
3673     cache_->DoneWithEntry(entry_, this, true /* entry_is_complete */,
3674                           partial_ != nullptr);
3675     entry_ = nullptr;
3676     is_sparse_ = false;
3677     // It's OK to use PartialData::RestoreHeaders here as |restart| is only set
3678     // when the HttpResponseInfo couldn't even be read, at which point it's
3679     // too early for range info in |partial_| to have changed.
3680     if (partial_)
3681       partial_->RestoreHeaders(&custom_request_->extra_headers);
3682     partial_.reset();
3683     TransitionToState(STATE_GET_BACKEND);
3684     return OK;
3685   }
3686 
3687   TransitionToState(STATE_NONE);
3688   return ERR_CACHE_READ_FAILURE;
3689 }
3690 
OnCacheLockTimeout(base::TimeTicks start_time)3691 void HttpCache::Transaction::OnCacheLockTimeout(base::TimeTicks start_time) {
3692   if (entry_lock_waiting_since_ != start_time)
3693     return;
3694 
3695   DCHECK(next_state_ == STATE_ADD_TO_ENTRY_COMPLETE ||
3696          next_state_ == STATE_FINISH_HEADERS_COMPLETE);
3697 
3698   if (!cache_)
3699     return;
3700 
3701   if (next_state_ == STATE_ADD_TO_ENTRY_COMPLETE)
3702     cache_->RemovePendingTransaction(this);
3703   else
3704     DoneWithEntry(false /* entry_is_complete */);
3705   OnIOComplete(ERR_CACHE_LOCK_TIMEOUT);
3706 }
3707 
DoomPartialEntry(bool delete_object)3708 void HttpCache::Transaction::DoomPartialEntry(bool delete_object) {
3709   DVLOG(2) << "DoomPartialEntry";
3710   if (entry_ && !entry_->doomed) {
3711     int rv = cache_->DoomEntry(cache_key_, nullptr);
3712     DCHECK_EQ(OK, rv);
3713   }
3714 
3715   cache_->DoneWithEntry(entry_, this, false /* entry_is_complete */,
3716                         partial_ != nullptr);
3717   entry_ = nullptr;
3718   is_sparse_ = false;
3719   truncated_ = false;
3720   if (delete_object)
3721     partial_.reset(nullptr);
3722 }
3723 
DoPartialCacheReadCompleted(int result)3724 int HttpCache::Transaction::DoPartialCacheReadCompleted(int result) {
3725   partial_->OnCacheReadCompleted(result);
3726 
3727   if (result == 0 && mode_ == READ_WRITE) {
3728     // We need to move on to the next range.
3729     TransitionToState(STATE_START_PARTIAL_CACHE_VALIDATION);
3730   } else if (result < 0) {
3731     return OnCacheReadError(result, false);
3732   } else {
3733     TransitionToState(STATE_NONE);
3734   }
3735   return result;
3736 }
3737 
DoRestartPartialRequest()3738 int HttpCache::Transaction::DoRestartPartialRequest() {
3739   // The stored data cannot be used. Get rid of it and restart this request.
3740   net_log_.AddEvent(NetLogEventType::HTTP_CACHE_RESTART_PARTIAL_REQUEST);
3741 
3742   // WRITE + Doom + STATE_INIT_ENTRY == STATE_CREATE_ENTRY (without an attempt
3743   // to Doom the entry again).
3744   ResetPartialState(!range_requested_);
3745 
3746   // Change mode to WRITE after ResetPartialState as that may have changed the
3747   // mode to NONE.
3748   mode_ = WRITE;
3749   TransitionToState(STATE_CREATE_ENTRY);
3750   return OK;
3751 }
3752 
ResetPartialState(bool delete_object)3753 void HttpCache::Transaction::ResetPartialState(bool delete_object) {
3754   partial_->RestoreHeaders(&custom_request_->extra_headers);
3755   DoomPartialEntry(delete_object);
3756 
3757   if (!delete_object) {
3758     // The simplest way to re-initialize partial_ is to create a new object.
3759     partial_ = std::make_unique<PartialData>();
3760 
3761     // Reset the range header to the original value (http://crbug.com/820599).
3762     custom_request_->extra_headers.RemoveHeader(HttpRequestHeaders::kRange);
3763     if (partial_->Init(initial_request_->extra_headers))
3764       partial_->SetHeaders(custom_request_->extra_headers);
3765     else
3766       partial_.reset();
3767   }
3768 }
3769 
ResetNetworkTransaction()3770 void HttpCache::Transaction::ResetNetworkTransaction() {
3771   SaveNetworkTransactionInfo(*network_trans_);
3772   network_trans_.reset();
3773 }
3774 
network_transaction() const3775 const HttpTransaction* HttpCache::Transaction::network_transaction() const {
3776   if (network_trans_)
3777     return network_trans_.get();
3778   if (InWriters())
3779     return entry_->writers->network_transaction();
3780   return nullptr;
3781 }
3782 
3783 const HttpTransaction*
GetOwnedOrMovedNetworkTransaction() const3784 HttpCache::Transaction::GetOwnedOrMovedNetworkTransaction() const {
3785   if (network_trans_)
3786     return network_trans_.get();
3787   if (InWriters() && moved_network_transaction_to_writers_)
3788     return entry_->writers->network_transaction();
3789   return nullptr;
3790 }
3791 
network_transaction()3792 HttpTransaction* HttpCache::Transaction::network_transaction() {
3793   return const_cast<HttpTransaction*>(
3794       static_cast<const Transaction*>(this)->network_transaction());
3795 }
3796 
3797 // Histogram data from the end of 2010 show the following distribution of
3798 // response headers:
3799 //
3800 //   Content-Length............... 87%
3801 //   Date......................... 98%
3802 //   Last-Modified................ 49%
3803 //   Etag......................... 19%
3804 //   Accept-Ranges: bytes......... 25%
3805 //   Accept-Ranges: none.......... 0.4%
3806 //   Strong Validator............. 50%
3807 //   Strong Validator + ranges.... 24%
3808 //   Strong Validator + CL........ 49%
3809 //
CanResume(bool has_data)3810 bool HttpCache::Transaction::CanResume(bool has_data) {
3811   // Double check that there is something worth keeping.
3812   if (has_data && !entry_->GetEntry()->GetDataSize(kResponseContentIndex))
3813     return false;
3814 
3815   if (method_ != "GET")
3816     return false;
3817 
3818   // Note that if this is a 206, content-length was already fixed after calling
3819   // PartialData::ResponseHeadersOK().
3820   if (response_.headers->GetContentLength() <= 0 ||
3821       response_.headers->HasHeaderValue("Accept-Ranges", "none") ||
3822       !response_.headers->HasStrongValidators()) {
3823     return false;
3824   }
3825 
3826   return true;
3827 }
3828 
SetResponse(const HttpResponseInfo & response)3829 void HttpCache::Transaction::SetResponse(const HttpResponseInfo& response) {
3830   response_ = response;
3831 
3832   if (response_.headers) {
3833     DCHECK(request_);
3834     response_.vary_data.Init(*request_, *response_.headers);
3835   }
3836 
3837   SyncCacheEntryStatusToResponse();
3838 }
3839 
SetAuthResponse(const HttpResponseInfo & auth_response)3840 void HttpCache::Transaction::SetAuthResponse(
3841     const HttpResponseInfo& auth_response) {
3842   auth_response_ = auth_response;
3843   SyncCacheEntryStatusToResponse();
3844 }
3845 
UpdateCacheEntryStatus(CacheEntryStatus new_cache_entry_status)3846 void HttpCache::Transaction::UpdateCacheEntryStatus(
3847     CacheEntryStatus new_cache_entry_status) {
3848   DCHECK_NE(CacheEntryStatus::ENTRY_UNDEFINED, new_cache_entry_status);
3849   if (cache_entry_status_ == CacheEntryStatus::ENTRY_OTHER)
3850     return;
3851   DCHECK(cache_entry_status_ == CacheEntryStatus::ENTRY_UNDEFINED ||
3852          new_cache_entry_status == CacheEntryStatus::ENTRY_OTHER);
3853   cache_entry_status_ = new_cache_entry_status;
3854   SyncCacheEntryStatusToResponse();
3855 }
3856 
SyncCacheEntryStatusToResponse()3857 void HttpCache::Transaction::SyncCacheEntryStatusToResponse() {
3858   if (cache_entry_status_ == CacheEntryStatus::ENTRY_UNDEFINED)
3859     return;
3860   response_.cache_entry_status = cache_entry_status_;
3861   if (auth_response_.headers.get()) {
3862     auth_response_.cache_entry_status = cache_entry_status_;
3863   }
3864 }
3865 
RecordHistograms()3866 void HttpCache::Transaction::RecordHistograms() {
3867   DCHECK(!recorded_histograms_);
3868   recorded_histograms_ = true;
3869 
3870   web_fonts_histogram::MaybeRecordCacheStatus(
3871       cache_entry_status_,
3872       HttpCache::GetResourceURLFromHttpCacheKey(cache_key_));
3873 
3874   if (CacheEntryStatus::ENTRY_UNDEFINED == cache_entry_status_)
3875     return;
3876 
3877   if (!cache_.get() || !cache_->GetCurrentBackend() ||
3878       cache_->GetCurrentBackend()->GetCacheType() != DISK_CACHE ||
3879       cache_->mode() != NORMAL || method_ != "GET") {
3880     return;
3881   }
3882 
3883   bool is_third_party = false;
3884 
3885   // Given that cache_entry_status_ is not ENTRY_UNDEFINED, the request must
3886   // have started and so request_ should exist.
3887   DCHECK(request_);
3888   if (request_->possibly_top_frame_origin) {
3889     is_third_party =
3890         !request_->possibly_top_frame_origin->IsSameOriginWith(request_->url);
3891   }
3892 
3893   std::string mime_type;
3894   HttpResponseHeaders* response_headers = GetResponseInfo()->headers.get();
3895   const bool is_no_store = response_headers && response_headers->HasHeaderValue(
3896                                                    "cache-control", "no-store");
3897   if (response_headers && response_headers->GetMimeType(&mime_type)) {
3898     // Record the cache pattern by resource type. The type is inferred by
3899     // response header mime type, which could be incorrect, so this is just an
3900     // estimate.
3901     if (mime_type == "text/html" &&
3902         (effective_load_flags_ & LOAD_MAIN_FRAME_DEPRECATED)) {
3903       CACHE_STATUS_HISTOGRAMS(".MainFrameHTML");
3904       IS_NO_STORE_HISTOGRAMS(".MainFrameHTML", is_no_store);
3905     } else if (mime_type == "text/html") {
3906       CACHE_STATUS_HISTOGRAMS(".NonMainFrameHTML");
3907     } else if (mime_type == "text/css") {
3908       if (is_third_party) {
3909         CACHE_STATUS_HISTOGRAMS(".CSSThirdParty");
3910       }
3911       CACHE_STATUS_HISTOGRAMS(".CSS");
3912     } else if (base::StartsWith(mime_type, "image/",
3913                                 base::CompareCase::SENSITIVE)) {
3914       int64_t content_length = response_headers->GetContentLength();
3915       if (content_length >= 0 && content_length < 100) {
3916         CACHE_STATUS_HISTOGRAMS(".TinyImage");
3917       } else if (content_length >= 100) {
3918         CACHE_STATUS_HISTOGRAMS(".NonTinyImage");
3919       }
3920       CACHE_STATUS_HISTOGRAMS(".Image");
3921     } else if (base::EndsWith(mime_type, "javascript",
3922                               base::CompareCase::SENSITIVE) ||
3923                base::EndsWith(mime_type, "ecmascript",
3924                               base::CompareCase::SENSITIVE)) {
3925       if (is_third_party) {
3926         CACHE_STATUS_HISTOGRAMS(".JavaScriptThirdParty");
3927       }
3928       CACHE_STATUS_HISTOGRAMS(".JavaScript");
3929     } else if (mime_type.find("font") != std::string::npos) {
3930       if (is_third_party) {
3931         CACHE_STATUS_HISTOGRAMS(".FontThirdParty");
3932       }
3933       CACHE_STATUS_HISTOGRAMS(".Font");
3934     } else if (base::StartsWith(mime_type, "audio/",
3935                                 base::CompareCase::SENSITIVE)) {
3936       CACHE_STATUS_HISTOGRAMS(".Audio");
3937     } else if (base::StartsWith(mime_type, "video/",
3938                                 base::CompareCase::SENSITIVE)) {
3939       CACHE_STATUS_HISTOGRAMS(".Video");
3940     }
3941   }
3942 
3943   CACHE_STATUS_HISTOGRAMS("");
3944   IS_NO_STORE_HISTOGRAMS("", is_no_store);
3945 
3946   if (cache_entry_status_ == CacheEntryStatus::ENTRY_OTHER)
3947     return;
3948 
3949   DCHECK(!range_requested_) << "Cache entry status " << cache_entry_status_;
3950   DCHECK(!first_cache_access_since_.is_null());
3951 
3952   base::TimeTicks now = base::TimeTicks::Now();
3953   base::TimeDelta total_time = now - first_cache_access_since_;
3954 
3955   UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone", total_time);
3956 
3957   bool did_send_request = !send_request_since_.is_null();
3958 
3959   // TODO(ricea): Understand why this DCHECK is failing in the wild, fix it, and
3960   // remove it. See https://crbug.com/1409150.
3961   if (did_send_request) {
3962     DCHECK_NE(cache_entry_status_, CacheEntryStatus::ENTRY_USED);
3963   }
3964   // This DCHECK() should not fire, because the one above should catch all the
3965   // erroneous cases.
3966   DCHECK(
3967       (did_send_request &&
3968        (cache_entry_status_ == CacheEntryStatus::ENTRY_NOT_IN_CACHE ||
3969         cache_entry_status_ == CacheEntryStatus::ENTRY_VALIDATED ||
3970         cache_entry_status_ == CacheEntryStatus::ENTRY_UPDATED ||
3971         cache_entry_status_ == CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE)) ||
3972       (!did_send_request &&
3973        (cache_entry_status_ == CacheEntryStatus::ENTRY_USED ||
3974         cache_entry_status_ == CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE)));
3975 
3976   if (!did_send_request) {
3977     if (cache_entry_status_ == CacheEntryStatus::ENTRY_USED)
3978       UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.Used", total_time);
3979     return;
3980   }
3981 
3982   base::TimeDelta before_send_time =
3983       send_request_since_ - first_cache_access_since_;
3984 
3985   UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.SentRequest", total_time);
3986   UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend", before_send_time);
3987 
3988   // TODO(gavinp): Remove or minimize these histograms, particularly the ones
3989   // below this comment after we have received initial data.
3990   switch (cache_entry_status_) {
3991     case CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE: {
3992       UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.CantConditionalize",
3993                           before_send_time);
3994       break;
3995     }
3996     case CacheEntryStatus::ENTRY_NOT_IN_CACHE: {
3997       UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.NotCached", before_send_time);
3998       break;
3999     }
4000     case CacheEntryStatus::ENTRY_VALIDATED: {
4001       UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.Validated", before_send_time);
4002       break;
4003     }
4004     case CacheEntryStatus::ENTRY_UPDATED: {
4005       UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.Updated", before_send_time);
4006       break;
4007     }
4008     default:
4009       // STATUS_UNDEFINED and STATUS_OTHER are explicitly handled earlier in
4010       // the function so shouldn't reach here. STATUS_MAX should never be set.
4011       // Originally it was asserted that STATUS_USED couldn't happen here, but
4012       // it turns out that it can. We don't have histograms for it, so just
4013       // ignore it.
4014       DCHECK_EQ(cache_entry_status_, CacheEntryStatus::ENTRY_USED);
4015       break;
4016   }
4017 
4018   if (!total_disk_cache_read_time_.is_zero()) {
4019     base::UmaHistogramTimes("HttpCache.TotalDiskCacheTimePerTransaction.Read",
4020                             total_disk_cache_read_time_);
4021   }
4022   if (!total_disk_cache_write_time_.is_zero()) {
4023     base::UmaHistogramTimes("HttpCache.TotalDiskCacheTimePerTransaction.Write",
4024                             total_disk_cache_write_time_);
4025   }
4026 }
4027 
InWriters() const4028 bool HttpCache::Transaction::InWriters() const {
4029   return entry_ && entry_->writers && entry_->writers->HasTransaction(this);
4030 }
4031 
4032 HttpCache::Transaction::NetworkTransactionInfo::NetworkTransactionInfo() =
4033     default;
4034 HttpCache::Transaction::NetworkTransactionInfo::~NetworkTransactionInfo() =
4035     default;
4036 
SaveNetworkTransactionInfo(const HttpTransaction & transaction)4037 void HttpCache::Transaction::SaveNetworkTransactionInfo(
4038     const HttpTransaction& transaction) {
4039   DCHECK(!network_transaction_info_.old_network_trans_load_timing);
4040   LoadTimingInfo load_timing;
4041   if (transaction.GetLoadTimingInfo(&load_timing)) {
4042     network_transaction_info_.old_network_trans_load_timing =
4043         std::make_unique<LoadTimingInfo>(load_timing);
4044   }
4045 
4046   network_transaction_info_.total_received_bytes +=
4047       transaction.GetTotalReceivedBytes();
4048   network_transaction_info_.total_sent_bytes += transaction.GetTotalSentBytes();
4049 
4050   ConnectionAttempts attempts = transaction.GetConnectionAttempts();
4051   for (const auto& attempt : attempts)
4052     network_transaction_info_.old_connection_attempts.push_back(attempt);
4053   network_transaction_info_.old_remote_endpoint = IPEndPoint();
4054   transaction.GetRemoteEndpoint(&network_transaction_info_.old_remote_endpoint);
4055 }
4056 
OnIOComplete(int result)4057 void HttpCache::Transaction::OnIOComplete(int result) {
4058   DoLoop(result);
4059 }
4060 
TransitionToState(State state)4061 void HttpCache::Transaction::TransitionToState(State state) {
4062   // Ensure that the state is only set once per Do* state.
4063   DCHECK(in_do_loop_);
4064   DCHECK_EQ(STATE_UNSET, next_state_) << "Next state is " << state;
4065   next_state_ = state;
4066 }
4067 
ShouldDisableCaching(const HttpResponseHeaders & headers) const4068 bool HttpCache::Transaction::ShouldDisableCaching(
4069     const HttpResponseHeaders& headers) const {
4070   // Do not cache no-store content.
4071   if (headers.HasHeaderValue("cache-control", "no-store")) {
4072     return true;
4073   }
4074 
4075   bool disable_caching = false;
4076   if (base::FeatureList::IsEnabled(
4077           features::kTurnOffStreamingMediaCachingAlways) ||
4078       (base::FeatureList::IsEnabled(
4079            features::kTurnOffStreamingMediaCachingOnBattery) &&
4080        IsOnBatteryPower())) {
4081     // If the feature is always enabled or enabled while we're running on
4082     // battery, and the acquired content is 'large' and not already cached, and
4083     // we have a MIME type of audio or video, then disable the cache for this
4084     // response. We based our initial definition of 'large' on the disk cache
4085     // maximum block size of 16K, which we observed captures the majority of
4086     // responses from various MSE implementations.
4087     static constexpr int kMaxContentSize = 4096 * 4;
4088     std::string mime_type;
4089     base::CompareCase insensitive_ascii = base::CompareCase::INSENSITIVE_ASCII;
4090     if (headers.GetContentLength() > kMaxContentSize &&
4091         headers.response_code() != net::HTTP_NOT_MODIFIED &&
4092         headers.GetMimeType(&mime_type) &&
4093         (base::StartsWith(mime_type, "video", insensitive_ascii) ||
4094          base::StartsWith(mime_type, "audio", insensitive_ascii))) {
4095       disable_caching = true;
4096       MediaCacheStatusResponseHistogram(
4097           MediaResponseCacheType::kMediaResponseTransactionCacheDisabled);
4098     } else {
4099       MediaCacheStatusResponseHistogram(
4100           MediaResponseCacheType::kMediaResponseTransactionCacheEnabled);
4101     }
4102   }
4103   return disable_caching;
4104 }
4105 
UpdateSecurityHeadersBeforeForwarding()4106 void HttpCache::Transaction::UpdateSecurityHeadersBeforeForwarding() {
4107   // Because of COEP, we need to add CORP to the 304 of resources that set it
4108   // previously. It will be blocked in the network service otherwise.
4109   std::string stored_corp_header;
4110   response_.headers->GetNormalizedHeader("Cross-Origin-Resource-Policy",
4111                                          &stored_corp_header);
4112   if (!stored_corp_header.empty()) {
4113     new_response_->headers->SetHeader("Cross-Origin-Resource-Policy",
4114                                       stored_corp_header);
4115   }
4116   return;
4117 }
4118 
ChecksumHeaders()4119 void HttpCache::Transaction::ChecksumHeaders() {
4120   DCHECK(use_single_keyed_cache_);
4121   DCHECK(!checksum_);
4122   checksum_ = crypto::SecureHash::Create(crypto::SecureHash::SHA256);
4123   // For efficiency and concision, we list known headers matching a wildcard
4124   // explicitly rather than doing prefix matching.
4125   constexpr auto kHeadersToInclude = base::MakeFixedFlatSet<base::StringPiece>({
4126       "access-control-allow-credentials",
4127       "access-control-allow-headers",
4128       "access-control-allow-methods",
4129       "access-control-allow-origin",
4130       "access-control-expose-headers",
4131       "access-control-max-age",
4132       "access-control-request-headers",
4133       "access-control-request-method",
4134       "clear-site-data",
4135       "content-encoding",
4136       "content-security-policy",
4137       "content-type",
4138       "cross-origin-embedder-policy",
4139       "cross-origin-opener-policy",
4140       "cross-origin-resource-policy",
4141       "location",
4142       "sec-websocket-accept",
4143       "sec-websocket-extensions",
4144       "sec-websocket-key",
4145       "sec-websocket-protocol",
4146       "sec-websocket-version",
4147       "upgrade",
4148       "vary",
4149   });
4150   // Pairs of (lower_case_header_name, header_value).
4151   std::vector<std::pair<std::string, std::string>> filtered_headers;
4152   // It's good to set the initial allocation size of the vector to the
4153   // expected size to avoid a lot of reallocations. This value was chosen as
4154   // it is a nice round number.
4155   filtered_headers.reserve(16);
4156   {
4157     // Iterate the response headers looking for matches.
4158     size_t iter = 0;
4159     std::string name;
4160     std::string value;
4161     while (response_.headers->EnumerateHeaderLines(&iter, &name, &value)) {
4162       std::string lowered_name = base::ToLowerASCII(name);
4163       if (kHeadersToInclude.contains(lowered_name)) {
4164         filtered_headers.emplace_back(lowered_name, value);
4165       }
4166     }
4167   }
4168   std::sort(filtered_headers.begin(), filtered_headers.end());
4169   for (const auto& [name, value] : filtered_headers) {
4170     checksum_->Update(name.data(), name.size());
4171     checksum_->Update(": ", 2);
4172     checksum_->Update(value.data(), value.size());
4173     checksum_->Update("\n", 1);
4174   }
4175   checksum_->Update("\n", 1);
4176 }
4177 
FinishAndCheckChecksum()4178 bool HttpCache::Transaction::FinishAndCheckChecksum() {
4179   if (!checksum_)
4180     return true;
4181 
4182   DCHECK(use_single_keyed_cache_);
4183   return ResponseChecksumMatches(std::move(checksum_));
4184 }
4185 
BeginDiskCacheAccessTimeCount()4186 void HttpCache::Transaction::BeginDiskCacheAccessTimeCount() {
4187   DCHECK(last_disk_cache_access_start_time_.is_null());
4188   if (partial_) {
4189     return;
4190   }
4191   last_disk_cache_access_start_time_ = TimeTicks::Now();
4192 }
4193 
EndDiskCacheAccessTimeCount(DiskCacheAccessType type)4194 void HttpCache::Transaction::EndDiskCacheAccessTimeCount(
4195     DiskCacheAccessType type) {
4196   // We may call this function without actual disk cache access as a result of
4197   // state change.
4198   if (last_disk_cache_access_start_time_.is_null()) {
4199     return;
4200   }
4201   base::TimeDelta elapsed =
4202       TimeTicks::Now() - last_disk_cache_access_start_time_;
4203   switch (type) {
4204     case DiskCacheAccessType::kRead:
4205       total_disk_cache_read_time_ += elapsed;
4206       break;
4207     case DiskCacheAccessType::kWrite:
4208       total_disk_cache_write_time_ += elapsed;
4209       break;
4210   }
4211   last_disk_cache_access_start_time_ = TimeTicks();
4212 }
4213 
4214 }  // namespace net
4215