chromium/net/http/http_cache_transaction.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif

#include "net/http/http_cache_transaction.h"

#include "base/time/time.h"
#include "build/build_config.h"  // For IS_POSIX

#if BUILDFLAG(IS_POSIX)
#include <unistd.h>
#endif

#include <algorithm>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>

#include "base/auto_reset.h"
#include "base/compiler_specific.h"
#include "base/containers/fixed_flat_set.h"
#include "base/containers/span.h"
#include "base/feature_list.h"
#include "base/format_macros.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/memory/stack_allocated.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/power_monitor/power_monitor.h"
#include "base/strings/string_util.h"  // For EqualsCaseInsensitiveASCII.
#include "base/task/single_thread_task_runner.h"
#include "base/time/clock.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/values.h"
#include "net/base/auth.h"
#include "net/base/features.h"
#include "net/base/load_flags.h"
#include "net/base/load_timing_info.h"
#include "net/base/trace_constants.h"
#include "net/base/tracing.h"
#include "net/base/transport_info.h"
#include "net/base/upload_data_stream.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/x509_certificate.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_cache.h"
#include "net/http/http_cache_writers.h"
#include "net/http/http_log_util.h"
#include "net/http/http_network_session.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
#include "net/http/http_util.h"
#include "net/log/net_log_event_type.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_config_service.h"

Time;
TimeTicks;

namespace net {

CacheEntryStatus;

namespace {

constexpr base::TimeDelta kStaleRevalidateTimeout =;

uint64_t GetNextTraceId(HttpCache* cache) {}

// From http://tools.ietf.org/html/draft-ietf-httpbis-p6-cache-21#section-6
//      a "non-error response" is one with a 2xx (Successful) or 3xx
//      (Redirection) status code.
bool NonErrorResponse(int status_code) {}

bool IsOnBatteryPower() {}

enum ExternallyConditionalizedType {};

bool ShouldByPassCacheForFirstPartySets(
    const std::optional<int64_t>& clear_at_run_id,
    const std::optional<int64_t>& written_at_run_id) {}

struct HeaderNameAndValue {};

// If the request includes one of these request headers, then avoid caching
// to avoid getting confused.
constexpr HeaderNameAndValue kPassThroughHeaders[] =;

struct ValidationHeaderInfo {};

constexpr ValidationHeaderInfo kValidationHeaders[] =;

// If the request includes one of these request headers, then avoid reusing
// our cached copy if any.
constexpr HeaderNameAndValue kForceFetchHeaders[] =;

// If the request includes one of these request headers, then force our
// cached copy (if any) to be revalidated before reusing it.
constexpr HeaderNameAndValue kForceValidateHeaders[] =;

bool HeaderMatches(const HttpRequestHeaders& headers,
                   const HeaderNameAndValue* search) {}

}  // namespace

#define CACHE_STATUS_HISTOGRAMS(type)

#define IS_NO_STORE_HISTOGRAMS(type, is_no_store)

//-----------------------------------------------------------------------------

HttpCache::Transaction::Transaction(RequestPriority priority, HttpCache* cache)
    :{}

HttpCache::Transaction::~Transaction() {}

HttpCache::Transaction::Mode HttpCache::Transaction::mode() const {}

LoadState HttpCache::Transaction::GetWriterLoadState() const {}

const NetLogWithSource& HttpCache::Transaction::net_log() const {}

int HttpCache::Transaction::Start(const HttpRequestInfo* request,
                                  CompletionOnceCallback callback,
                                  const NetLogWithSource& net_log) {}

int HttpCache::Transaction::RestartIgnoringLastError(
    CompletionOnceCallback callback) {}

int HttpCache::Transaction::RestartWithCertificate(
    scoped_refptr<X509Certificate> client_cert,
    scoped_refptr<SSLPrivateKey> client_private_key,
    CompletionOnceCallback callback) {}

int HttpCache::Transaction::RestartWithAuth(const AuthCredentials& credentials,
                                            CompletionOnceCallback callback) {}

bool HttpCache::Transaction::IsReadyToRestartForAuth() {}

int HttpCache::Transaction::Read(IOBuffer* buf,
                                 int buf_len,
                                 CompletionOnceCallback callback) {}

int HttpCache::Transaction::TransitionToReadingState() {}

void HttpCache::Transaction::StopCaching() {}

int64_t HttpCache::Transaction::GetTotalReceivedBytes() const {}

int64_t HttpCache::Transaction::GetTotalSentBytes() const {}

int64_t HttpCache::Transaction::GetReceivedBodyBytes() const {}

void HttpCache::Transaction::DoneReading() {}

const HttpResponseInfo* HttpCache::Transaction::GetResponseInfo() const {}

LoadState HttpCache::Transaction::GetLoadState() const {}

void HttpCache::Transaction::SetQuicServerInfo(
    QuicServerInfo* quic_server_info) {}

bool HttpCache::Transaction::GetLoadTimingInfo(
    LoadTimingInfo* load_timing_info) const {}

bool HttpCache::Transaction::GetRemoteEndpoint(IPEndPoint* endpoint) const {}

void HttpCache::Transaction::PopulateNetErrorDetails(
    NetErrorDetails* details) const {}

void HttpCache::Transaction::SetPriority(RequestPriority priority) {}

void HttpCache::Transaction::SetWebSocketHandshakeStreamCreateHelper(
    WebSocketHandshakeStreamBase::CreateHelper* create_helper) {}

void HttpCache::Transaction::SetBeforeNetworkStartCallback(
    BeforeNetworkStartCallback callback) {}

void HttpCache::Transaction::SetConnectedCallback(
    const ConnectedCallback& callback) {}

void HttpCache::Transaction::SetRequestHeadersCallback(
    RequestHeadersCallback callback) {}

void HttpCache::Transaction::SetResponseHeadersCallback(
    ResponseHeadersCallback callback) {}

void HttpCache::Transaction::SetEarlyResponseHeadersCallback(
    ResponseHeadersCallback callback) {}

void HttpCache::Transaction::SetModifyRequestHeadersCallback(
    base::RepeatingCallback<void(HttpRequestHeaders*)> callback) {}

void HttpCache::Transaction::SetIsSharedDictionaryReadAllowedCallback(
    base::RepeatingCallback<bool()> callback) {}

int HttpCache::Transaction::ResumeNetworkStart() {}

ConnectionAttempts HttpCache::Transaction::GetConnectionAttempts() const {}

void HttpCache::Transaction::CloseConnectionOnDestruction() {}

bool HttpCache::Transaction::IsMdlMatchForMetrics() const {}

void HttpCache::Transaction::SetValidatingCannotProceed() {}

void HttpCache::Transaction::WriterAboutToBeRemovedFromEntry(int result) {}

void HttpCache::Transaction::WriteModeTransactionAboutToBecomeReader() {}

void HttpCache::Transaction::AddDiskCacheWriteTime(base::TimeDelta elapsed) {}

//-----------------------------------------------------------------------------

// A few common patterns: (Foo* means Foo -> FooComplete)
//
// 1. Not-cached entry:
//   Start():
//   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
//   SendRequest* -> SuccessfulSendRequest -> OverwriteCachedResponse ->
//   CacheWriteResponse* -> TruncateCachedData* -> PartialHeadersReceived ->
//   FinishHeaders*
//
//   Read():
//   NetworkReadCacheWrite*/CacheReadData* (if other writers are also writing to
//   the cache)
//
// 2. Cached entry, no validation:
//   Start():
//   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
//   CacheReadResponse* -> CacheDispatchValidation ->
//   BeginPartialCacheValidation() -> BeginCacheValidation() ->
//   ConnectedCallback* -> SetupEntryForRead() -> FinishHeaders*
//
//   Read():
//   CacheReadData*
//
// 3. Cached entry, validation (304):
//   Start():
//   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
//   CacheReadResponse* -> CacheDispatchValidation ->
//   BeginPartialCacheValidation() -> BeginCacheValidation() -> SendRequest* ->
//   SuccessfulSendRequest -> UpdateCachedResponse -> CacheWriteUpdatedResponse*
//   -> UpdateCachedResponseComplete -> OverwriteCachedResponse ->
//   PartialHeadersReceived -> FinishHeaders*
//
//   Read():
//   CacheReadData*
//
// 4. Cached entry, validation and replace (200):
//   Start():
//   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
//   CacheReadResponse* -> CacheDispatchValidation ->
//   BeginPartialCacheValidation() -> BeginCacheValidation() -> SendRequest* ->
//   SuccessfulSendRequest -> OverwriteCachedResponse -> CacheWriteResponse* ->
//   DoTruncateCachedData* -> PartialHeadersReceived -> FinishHeaders*
//
//   Read():
//   NetworkReadCacheWrite*/CacheReadData* (if other writers are also writing to
//   the cache)
//
// 5. Sparse entry, partially cached, byte range request:
//   Start():
//   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
//   CacheReadResponse* -> CacheDispatchValidation ->
//   BeginPartialCacheValidation() -> CacheQueryData* ->
//   ValidateEntryHeadersAndContinue() -> StartPartialCacheValidation ->
//   CompletePartialCacheValidation -> BeginCacheValidation() -> SendRequest* ->
//   SuccessfulSendRequest -> UpdateCachedResponse -> CacheWriteUpdatedResponse*
//   -> UpdateCachedResponseComplete -> OverwriteCachedResponse ->
//   PartialHeadersReceived -> FinishHeaders*
//
//   Read() 1:
//   NetworkReadCacheWrite*
//
//   Read() 2:
//   NetworkReadCacheWrite* -> StartPartialCacheValidation ->
//   CompletePartialCacheValidation -> ConnectedCallback* -> CacheReadData*
//
//   Read() 3:
//   CacheReadData* -> StartPartialCacheValidation ->
//   CompletePartialCacheValidation -> BeginCacheValidation() -> SendRequest* ->
//   SuccessfulSendRequest -> UpdateCachedResponse* -> OverwriteCachedResponse
//   -> PartialHeadersReceived -> NetworkReadCacheWrite*
//
// 6. HEAD. Not-cached entry:
//   Pass through. Don't save a HEAD by itself.
//   Start():
//   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> SendRequest*
//
// 7. HEAD. Cached entry, no validation:
//   Start():
//   The same flow as for a GET request (example #2)
//
//   Read():
//   CacheReadData (returns 0)
//
// 8. HEAD. Cached entry, validation (304):
//   The request updates the stored headers.
//   Start(): Same as for a GET request (example #3)
//
//   Read():
//   CacheReadData (returns 0)
//
// 9. HEAD. Cached entry, validation and replace (200):
//   Pass through. The request dooms the old entry, as a HEAD won't be stored by
//   itself.
//   Start():
//   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
//   CacheReadResponse* -> CacheDispatchValidation ->
//   BeginPartialCacheValidation() -> BeginCacheValidation() -> SendRequest* ->
//   SuccessfulSendRequest -> OverwriteCachedResponse -> FinishHeaders*
//
// 10. HEAD. Sparse entry, partially cached:
//   Serve the request from the cache, as long as it doesn't require
//   revalidation. Ignore missing ranges when deciding to revalidate. If the
//   entry requires revalidation, ignore the whole request and go to full pass
//   through (the result of the HEAD request will NOT update the entry).
//
//   Start(): Basically the same as example 7, as we never create a partial_
//   object for this request.
//
// 11. Prefetch, not-cached entry:
//   The same as example 1. The "unused_since_prefetch" bit is stored as true in
//   UpdateCachedResponse.
//
// 12. Prefetch, cached entry:
//   Like examples 2-4, only CacheWriteUpdatedPrefetchResponse* is inserted
//   between CacheReadResponse* and CacheDispatchValidation if the
//   unused_since_prefetch bit is unset.
//
// 13. Cached entry less than 5 minutes old, unused_since_prefetch is true:
//   Skip validation, similar to example 2.
//   GetBackend* -> InitEntry -> OpenOrCreateEntry* -> AddToEntry* ->
//   CacheReadResponse* -> CacheToggleUnusedSincePrefetch* ->
//   CacheDispatchValidation -> BeginPartialCacheValidation() ->
//   BeginCacheValidation() -> ConnectedCallback* -> SetupEntryForRead() ->
//   FinishHeaders*
//
//   Read():
//   CacheReadData*
//
// 14. Cached entry more than 5 minutes old, unused_since_prefetch is true:
//   Like examples 2-4, only CacheToggleUnusedSincePrefetch* is inserted between
//   CacheReadResponse* and CacheDispatchValidation.
int HttpCache::Transaction::DoLoop(int result) {}

int HttpCache::Transaction::DoGetBackend() {}

int HttpCache::Transaction::DoGetBackendComplete(int result) {}

int HttpCache::Transaction::DoInitEntry() {}

int HttpCache::Transaction::DoOpenOrCreateEntry() {}

int HttpCache::Transaction::DoOpenOrCreateEntryComplete(int result) {}

int HttpCache::Transaction::DoDoomEntry() {}

int HttpCache::Transaction::DoDoomEntryComplete(int result) {}

int HttpCache::Transaction::DoCreateEntry() {}

int HttpCache::Transaction::DoCreateEntryComplete(int result) {}

int HttpCache::Transaction::DoAddToEntry() {}

void HttpCache::Transaction::AddCacheLockTimeoutHandler(ActiveEntry* entry) {}

int HttpCache::Transaction::DoAddToEntryComplete(int result) {}

int HttpCache::Transaction::DoDoneHeadersAddToEntryComplete(int result) {}

int HttpCache::Transaction::DoCacheReadResponse() {}

int HttpCache::Transaction::DoCacheReadResponseComplete(int result) {}

int HttpCache::Transaction::DoCacheWriteUpdatedPrefetchResponse(int result) {}

int HttpCache::Transaction::DoCacheWriteUpdatedPrefetchResponseComplete(
    int result) {}

int HttpCache::Transaction::DoCacheDispatchValidation() {}

int HttpCache::Transaction::DoCacheQueryData() {}

int HttpCache::Transaction::DoCacheQueryDataComplete(int result) {}

// We may end up here multiple times for a given request.
int HttpCache::Transaction::DoStartPartialCacheValidation() {}

int HttpCache::Transaction::DoCompletePartialCacheValidation(int result) {}

int HttpCache::Transaction::DoCacheUpdateStaleWhileRevalidateTimeout() {}

int HttpCache::Transaction::DoCacheUpdateStaleWhileRevalidateTimeoutComplete(
    int result) {}

int HttpCache::Transaction::DoSendRequest() {}

int HttpCache::Transaction::DoSendRequestComplete(int result) {}

// We received the response headers and there is no error.
int HttpCache::Transaction::DoSuccessfulSendRequest() {}

// We received 304 or 206 and we want to update the cached response headers.
int HttpCache::Transaction::DoUpdateCachedResponse() {}

int HttpCache::Transaction::DoCacheWriteUpdatedResponse() {}

int HttpCache::Transaction::DoCacheWriteUpdatedResponseComplete(int result) {}

int HttpCache::Transaction::DoUpdateCachedResponseComplete(int result) {}

int HttpCache::Transaction::DoOverwriteCachedResponse() {}

int HttpCache::Transaction::DoCacheWriteResponse() {}

int HttpCache::Transaction::DoCacheWriteResponseComplete(int result) {}

int HttpCache::Transaction::DoTruncateCachedData() {}

int HttpCache::Transaction::DoTruncateCachedDataComplete(int result) {}

int HttpCache::Transaction::DoPartialHeadersReceived() {}

int HttpCache::Transaction::DoHeadersPhaseCannotProceed(int result) {}

int HttpCache::Transaction::DoFinishHeaders(int result) {}

int HttpCache::Transaction::DoFinishHeadersComplete(int rv) {}

int HttpCache::Transaction::DoNetworkReadCacheWrite() {}

int HttpCache::Transaction::DoNetworkReadCacheWriteComplete(int result) {}

int HttpCache::Transaction::DoPartialNetworkReadCompleted(int result) {}

int HttpCache::Transaction::DoNetworkRead() {}

int HttpCache::Transaction::DoNetworkReadComplete(int result) {}

int HttpCache::Transaction::DoCacheReadData() {}

int HttpCache::Transaction::DoCacheReadDataComplete(int result) {}

//-----------------------------------------------------------------------------

void HttpCache::Transaction::SetRequest(const NetLogWithSource& net_log) {}

bool HttpCache::Transaction::ShouldPassThrough() {}

int HttpCache::Transaction::BeginCacheRead() {}

int HttpCache::Transaction::BeginCacheValidation() {}

int HttpCache::Transaction::BeginPartialCacheValidation() {}

// This should only be called once per request.
int HttpCache::Transaction::ValidateEntryHeadersAndContinue() {}

bool HttpCache::Transaction::
    ExternallyConditionalizedValidationHeadersMatchEntry() const {}

int HttpCache::Transaction::BeginExternallyConditionalizedRequest() {}

int HttpCache::Transaction::RestartNetworkRequest() {}

int HttpCache::Transaction::RestartNetworkRequestWithCertificate(
    scoped_refptr<X509Certificate> client_cert,
    scoped_refptr<SSLPrivateKey> client_private_key) {}

int HttpCache::Transaction::RestartNetworkRequestWithAuth(
    const AuthCredentials& credentials) {}

ValidationType HttpCache::Transaction::RequiresValidation() {}

bool HttpCache::Transaction::IsResponseConditionalizable(
    std::string* etag_value,
    std::string* last_modified_value) const {}

bool HttpCache::Transaction::ShouldOpenOnlyMethods() const {}

bool HttpCache::Transaction::ConditionalizeRequest() {}

bool HttpCache::Transaction::MaybeRejectBasedOnEntryInMemoryData(
    uint8_t in_memory_info) {}

bool HttpCache::Transaction::ComputeUnusablePerCachingHeaders() {}

// We just received some headers from the server. We may have asked for a range,
// in which case partial_ has an object. This could be the first network request
// we make to fulfill the original request, or we may be already reading (from
// the net and / or the cache). If we are not expecting a certain response, we
// just bypass the cache for this request (but again, maybe we are reading), and
// delete partial_ (so we are not able to "fix" the headers that we return to
// the user). This results in either a weird response for the caller (we don't
// expect it after all), or maybe a range that was not exactly what it was asked
// for.
//
// If the server is simply telling us that the resource has changed, we delete
// the cached entry and restart the request as the caller intended (by returning
// false from this method). However, we may not be able to do that at any point,
// for instance if we already returned the headers to the user.
//
// WARNING: Whenever this code returns false, it has to make sure that the next
// time it is called it will return true so that we don't keep retrying the
// request.
bool HttpCache::Transaction::ValidatePartialResponse() {}

void HttpCache::Transaction::IgnoreRangeRequest() {}

// Called to signal to the consumer that we are about to read headers from a
// cached entry originally read from a given IP endpoint.
int HttpCache::Transaction::DoConnectedCallback() {}

int HttpCache::Transaction::DoConnectedCallbackComplete(int result) {}

void HttpCache::Transaction::DoomInconsistentEntry() {}

void HttpCache::Transaction::FixHeadersForHead() {}

int HttpCache::Transaction::DoSetupEntryForRead() {}

int HttpCache::Transaction::WriteResponseInfoToEntry(
    const HttpResponseInfo& response,
    bool truncated) {}

int HttpCache::Transaction::OnWriteResponseInfoToEntryComplete(int result) {}

bool HttpCache::Transaction::StopCachingImpl(bool success) {}

void HttpCache::Transaction::DoneWithEntry(bool entry_is_complete) {}

int HttpCache::Transaction::OnCacheReadError(int result, bool restart) {}

void HttpCache::Transaction::OnCacheLockTimeout(base::TimeTicks start_time) {}

void HttpCache::Transaction::DoomPartialEntry(bool delete_object) {}

int HttpCache::Transaction::DoPartialCacheReadCompleted(int result) {}

int HttpCache::Transaction::DoRestartPartialRequest() {}

void HttpCache::Transaction::ResetPartialState(bool delete_object) {}

void HttpCache::Transaction::ResetNetworkTransaction() {}

const HttpTransaction* HttpCache::Transaction::network_transaction() const {}

const HttpTransaction*
HttpCache::Transaction::GetOwnedOrMovedNetworkTransaction() const {}

HttpTransaction* HttpCache::Transaction::network_transaction() {}

// Histogram data from the end of 2010 show the following distribution of
// response headers:
//
//   Content-Length............... 87%
//   Date......................... 98%
//   Last-Modified................ 49%
//   Etag......................... 19%
//   Accept-Ranges: bytes......... 25%
//   Accept-Ranges: none.......... 0.4%
//   Strong Validator............. 50%
//   Strong Validator + ranges.... 24%
//   Strong Validator + CL........ 49%
//
bool HttpCache::Transaction::CanResume(bool has_data) {}

void HttpCache::Transaction::SetResponse(const HttpResponseInfo& response) {}

void HttpCache::Transaction::SetAuthResponse(
    const HttpResponseInfo& auth_response) {}

void HttpCache::Transaction::UpdateCacheEntryStatus(
    CacheEntryStatus new_cache_entry_status) {}

void HttpCache::Transaction::SyncCacheEntryStatusToResponse() {}

void HttpCache::Transaction::RecordHistograms() {}

bool HttpCache::Transaction::InWriters() const {}

HttpCache::Transaction::NetworkTransactionInfo::NetworkTransactionInfo() =
    default;
HttpCache::Transaction::NetworkTransactionInfo::~NetworkTransactionInfo() =
    default;

void HttpCache::Transaction::SaveNetworkTransactionInfo(
    const HttpTransaction& transaction) {}

void HttpCache::Transaction::OnIOComplete(int result) {}

void HttpCache::Transaction::OnCacheIOComplete(int result) {}

void HttpCache::Transaction::TransitionToState(State state) {}

bool HttpCache::Transaction::UpdateAndReportCacheability(
    const HttpResponseHeaders& headers) {}

void HttpCache::Transaction::UpdateSecurityHeadersBeforeForwarding() {}

void HttpCache::Transaction::BeginDiskCacheAccessTimeCount() {}

void HttpCache::Transaction::EndDiskCacheAccessTimeCount(
    DiskCacheAccessType type) {}

}  // namespace net