blob: d78b426e45a805ce03ec9ad6e160995f18d6ff24 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_NETWORK_URL_LOADER_H_
#define SERVICES_NETWORK_URL_LOADER_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/component_export.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/numerics/safe_conversions.h"
#include "base/types/optional_ref.h"
#include "base/unguessable_token.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "net/base/load_states.h"
#include "net/base/network_delegate.h"
#include "net/base/transport_info.h"
#include "net/base/upload_progress.h"
#include "net/cookies/cookie_setting_override.h"
#include "net/cookies/cookie_util.h"
#include "net/socket/socket_tag.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_request.h"
#include "services/network/ad_auction/event_record_request_helper.h"
#include "services/network/devtools_durable_msg.h"
#include "services/network/keepalive_statistics_recorder.h"
#include "services/network/network_service.h"
#include "services/network/observer_wrapper.h"
#include "services/network/partial_decoder.h"
#include "services/network/private_network_access_url_loader_interceptor.h"
#include "services/network/public/cpp/cors/cors_error_status.h"
#include "services/network/public/cpp/initiator_lock_compatibility.h"
#include "services/network/public/cpp/orb/orb_api.h"
#include "services/network/public/cpp/permissions_policy/permissions_policy.h"
#include "services/network/public/mojom/accept_ch_frame_observer.mojom.h"
#include "services/network/public/mojom/client_security_state.mojom.h"
#include "services/network/public/mojom/cookie_access_observer.mojom.h"
#include "services/network/public/mojom/cross_origin_embedder_policy.mojom-forward.h"
#include "services/network/public/mojom/device_bound_sessions.mojom.h"
#include "services/network/public/mojom/devtools_observer.mojom.h"
#include "services/network/public/mojom/fetch_api.mojom.h"
#include "services/network/public/mojom/ip_address_space.mojom-forward.h"
#include "services/network/public/mojom/ip_address_space.mojom-shared.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/network/public/mojom/trust_token_access_observer.mojom.h"
#include "services/network/public/mojom/trust_tokens.mojom-shared.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom-forward.h"
#include "services/network/resource_scheduler/resource_scheduler.h"
#include "services/network/resource_scheduler/resource_scheduler_client.h"
#include "services/network/shared_dictionary/shared_dictionary_access_checker.h"
#include "services/network/shared_storage/shared_storage_request_helper.h"
#include "services/network/trust_tokens/trust_token_request_helper_factory.h"
#include "services/network/upload_progress_tracker.h"
#include "services/network/url_loader_context.h"
namespace net {
class HttpResponseHeaders;
class IOBufferWithSize;
class IPEndPoint;
class URLRequestContext;
struct RedirectInfo;
} // namespace net
namespace network {
namespace cors {
class OriginAccessList;
}
namespace internal {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(FetchKeepAliveRequestNetworkMetricType)
enum class FetchKeepAliveRequestNetworkMetricType {
kOnCreate = 0,
kOnResponse = 1,
kMaxValue = kOnResponse
};
// LINT.ThenChange(//tools/metrics/histograms/enums.xml:FetchKeepAliveRequestNetworkMetricType)
} // namespace internal
class AcceptCHFrameInterceptor;
class FileOpenerForUpload;
class KeepaliveStatisticsRecorder;
class NetToMojoPendingBuffer;
class ScopedThrottlingToken;
class SharedDictionaryManager;
class SharedResourceChecker;
class SlopBucket;
class TrustTokenUrlLoaderInterceptor;
class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
: public mojom::URLLoader,
public net::URLRequest::Delegate,
public mojom::AuthChallengeResponder,
public mojom::ClientCertificateResponder {
public:
using DeleteCallback = base::OnceCallback<void(URLLoader* loader)>;
// Holds a sync and async implementation of URLLoaderClient. The sync
// implementation can be used if present to avoid posting a task to call back
// into CorsURLLoader.
class MaybeSyncURLLoaderClient {
public:
MaybeSyncURLLoaderClient(
mojo::PendingRemote<mojom::URLLoaderClient> mojo_client,
base::WeakPtr<mojom::URLLoaderClient> sync_client);
~MaybeSyncURLLoaderClient();
// Resets both URLLoaderClients.
void Reset();
// Rebinds the mojo URLLoaderClient and uses it for future calls.
mojo::PendingReceiver<mojom::URLLoaderClient> BindNewPipeAndPassReceiver();
// Gets the sync URLLoaderClient if available, otherwise the mojo remote.
mojom::URLLoaderClient* Get();
private:
mojo::Remote<mojom::URLLoaderClient> mojo_client_;
base::WeakPtr<mojom::URLLoaderClient> sync_client_;
};
// `delete_callback` tells the URLLoader's owner to destroy the URLLoader.
//
// `trust_token_helper_factory` must be non-null exactly when the request has
// Trust Tokens parameters.
//
// The caller needs to guarantee that the pointers/references in the
// `context` will live longer than the constructed URLLoader. One
// (incomplete) reason why this guarantee is true in production code is that
// `context` is implemented by URLLoaderFactory which outlives the lifecycle
// of the URLLoader (and some pointers in `context` point to objects owned by
// URLLoaderFactory).
//
// Pointers from the `url_loader_context` will be used if
// `dev_tools_observer`, `cookie_access_observer`,
// `url_loader_network_observer`, or `device_bound_session_observer`
// are not provided.
URLLoader(
URLLoaderContext& context,
DeleteCallback delete_callback,
mojo::PendingReceiver<mojom::URLLoader> url_loader_receiver,
int32_t options,
const ResourceRequest& request,
mojo::PendingRemote<mojom::URLLoaderClient> url_loader_client,
base::WeakPtr<mojom::URLLoaderClient> sync_url_loader_client,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
base::StrictNumeric<int32_t> request_id,
int keepalive_request_size,
base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder,
std::unique_ptr<TrustTokenRequestHelperFactory>
trust_token_helper_factory,
SharedDictionaryManager* shared_dictionary_manager,
std::unique_ptr<SharedDictionaryAccessChecker> shared_dictionary_checker,
ObserverWrapper<mojom::CookieAccessObserver> cookie_observer,
ObserverWrapper<mojom::TrustTokenAccessObserver> trust_token_observer,
ObserverWrapper<mojom::URLLoaderNetworkServiceObserver>
url_loader_network_observer,
ObserverWrapper<mojom::DevToolsObserver> devtools_observer,
ObserverWrapper<mojom::DeviceBoundSessionAccessObserver>
device_bound_session_observer,
mojo::PendingRemote<mojom::AcceptCHFrameObserver>
accept_ch_frame_observer,
bool shared_storage_writable_eligible,
SharedResourceChecker& shared_resource_checker,
base::WeakPtr<DevtoolsDurableMessage> devtools_durable_message);
URLLoader(const URLLoader&) = delete;
URLLoader& operator=(const URLLoader&) = delete;
~URLLoader() override;
// mojom::URLLoader implementation:
void FollowRedirect(
const std::vector<std::string>& removed_headers,
const net::HttpRequestHeaders& modified_headers,
const net::HttpRequestHeaders& modified_cors_exempt_headers,
const std::optional<GURL>& new_url) override;
void SetPriority(net::RequestPriority priority,
int32_t intra_priority_value) override;
// net::URLRequest::Delegate implementation:
int OnConnected(net::URLRequest* url_request,
const net::TransportInfo& info,
net::CompletionOnceCallback callback) override;
void OnReceivedRedirect(net::URLRequest* url_request,
const net::RedirectInfo& redirect_info,
bool* defer_redirect) override;
void OnAuthRequired(net::URLRequest* request,
const net::AuthChallengeInfo& info) override;
void OnCertificateRequested(net::URLRequest* request,
net::SSLCertRequestInfo* info) override;
void OnSSLCertificateError(net::URLRequest* request,
int net_error,
const net::SSLInfo& info,
bool fatal) override;
void OnResponseStarted(net::URLRequest* url_request, int net_error) override;
void OnReadCompleted(net::URLRequest* url_request, int bytes_read) override;
// These methods are called by the network delegate to forward these events to
// the |header_client_|.
int OnBeforeStartTransaction(
const net::HttpRequestHeaders& headers,
net::NetworkDelegate::OnBeforeStartTransactionCallback callback);
int OnHeadersReceived(
net::CompletionOnceCallback callback,
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
const net::IPEndPoint& endpoint,
std::optional<GURL>* preserve_fragment_on_redirect_url);
mojom::URLLoaderNetworkServiceObserver* GetURLLoaderNetworkServiceObserver()
const {
return url_loader_network_observer_.get();
}
// mojom::AuthChallengeResponder:
void OnAuthCredentials(
const std::optional<net::AuthCredentials>& credentials) override;
// mojom::ClientCertificateResponder:
void ContinueWithCertificate(
const scoped_refptr<net::X509Certificate>& x509_certificate,
const std::string& provider_name,
const std::vector<uint16_t>& algorithm_preferences,
mojo::PendingRemote<mojom::SSLPrivateKey> ssl_private_key) override;
void ContinueWithoutCertificate() override;
void CancelRequest() override;
// Cancel the request because network revocation was triggered.
void CancelRequestIfNonceMatchesAndUrlNotExempted(
const base::UnguessableToken& nonce,
const std::set<GURL>& exemptions);
net::LoadState GetLoadState() const;
net::UploadProgress GetUploadProgress() const;
int32_t GetProcessId() const;
uint32_t GetResourceType() const;
// Whether this URLLoader should allow sending/setting any cookies.
// This decision is based on the options passed to
// URLLoaderFactory::CreateLoaderAndStart().
bool CookiesDisabled() const;
// Whether this URLLoader should allow sending/setting cookies for requests
// with |url| and |site_for_cookies|. This decision is based on the options
// passed to URLLoaderFactory::CreateLoaderAndStart().
// If this returns false, partitioned cookies could still be provided if
// CookiesDisabled returns false.
bool AllowFullCookies(const GURL& url,
const net::SiteForCookies& site_for_cookies) const;
// Returns whether a particular cookie is allowed to be sent for requests
// with |url| and |site_for_cookies|. This decision is based on the options
// passed to URLLoaderFactory::CreateLoaderAndStart().
bool AllowCookie(const net::CanonicalCookie& cookie,
const GURL& url,
const net::SiteForCookies& site_for_cookies) const;
const std::optional<GURL>& new_redirect_url() const {
return new_redirect_url_;
}
const std::optional<std::string>& devtools_request_id() const {
return devtools_request_id_;
}
SharedStorageRequestHelper* shared_storage_request_helper() const {
return shared_storage_request_helper_.get();
}
void set_partial_decoder_decoding_buffer_size_for_testing(
int partial_decoder_decoding_buffer_size) {
partial_decoder_decoding_buffer_size_ =
partial_decoder_decoding_buffer_size;
}
// Gets the URLLoader associated with this request.
static URLLoader* ForRequest(const net::URLRequest& request);
static const void* const kUserDataKey;
// Returns an optional reference to a constant permissions policy that belongs
// to the request. `this` must outlive the caller of this method.
base::optional_ref<const network::PermissionsPolicy> GetPermissionsPolicy()
const {
return permissions_policy_;
}
private:
// This class is used to set the URLLoader as user data on a URLRequest. This
// is used instead of URLLoader directly because SetUserData requires a
// std::unique_ptr. This is safe because URLLoader owns the URLRequest, so is
// guaranteed to outlive it.
class UnownedPointer : public base::SupportsUserData::Data {
public:
explicit UnownedPointer(URLLoader* pointer) : pointer_(pointer) {}
UnownedPointer(const UnownedPointer&) = delete;
UnownedPointer& operator=(const UnownedPointer&) = delete;
URLLoader* get() const { return pointer_; }
private:
const raw_ptr<URLLoader> pointer_;
};
// An enum class representing the result of keepalive requests. This is used
// for UMA so do NOT re-assign values.
enum class KeepaliveRequestResult {
kOk = 0,
kMojoConnectionErrorBeforeResponseArrival = 1,
kMojoConnectionErrorAfterResponseArrival = 2,
kErrorBeforeResponseArrival = 3,
kErrorAfterResponseArrival = 4,
kMaxValue = kErrorAfterResponseArrival,
};
// Sets various callbacks on the internal `url_request_`.
void SetUpUrlRequestCallbacks(
SharedDictionaryManager* shared_dictionary_manager);
void OpenFilesForUpload(const ResourceRequest& request);
void SetUpUpload(const ResourceRequest& request,
base::expected<std::vector<base::File>, net::Error>);
// A continuation of `OnConnected` to process the result of the asynchronous
// Local Network Access permission check.
void ProcessLocalNetworkAccessPermissionResultOnConnected(
const net::TransportInfo& info,
net::CompletionOnceCallback callback,
net::Error pna_result);
// A continuation of `OnConnected` to handle an ACCEPT_CH frame, if present.
int ProcessAcceptCHFrameOnConnected(const net::TransportInfo& info,
net::CompletionOnceCallback callback);
// A `ResourceRequest` where `shared_storage_writable_eligible` is true, is
// eligible for shared storage operations via response headers.
//
// Outbound control flow:
//
// Start in `ProcessOutboundSharedStorageInterceptor()`
// - Execute `SharedStorageRequestHelper::ProcessOutgoingRequest`, which will
// add the `kSecSharedStorageWritableHeader` request header to the
// `URLRequest` if `ResourceRequest::shared_storage_writable_eligible` is true
// and there is a `mojom::URLLoaderNetworkServiceObserver*` available to
// forward processed headers to.
// - `ScheduleStart` immediately afterwards regardless of eligibility for
// shared storage
//
// Outbound redirection control flow:
//
// Start in `FollowRedirect`
// - Execute
// `SharedStorageRequestHelper::UpdateSharedStorageWritableEligible`
// to remove or restore the `kSecSharedStorageWritableHeader` request header
// if eligibility has been lost or regained
//
// Inbound redirection control flow:
//
// Start in `ProcessInboundSharedStorageInterceptorOnReceivedRedirect`
// - Execute `SharedStorageRequestHelper::ProcessIncomingResponse`
// - If the request has received the `kSharedStorageWriteHeader` response
// header and if it is currently eligible for shared storage (i.e., in
// particular, the `kSecSharedStorageWritableHeader` has not been removed on a
// redirect), the helper will parse the header value into a vector of Shared
// Storage operations to call
// - If the request has not received the `kSharedStorageWriteHeader` response
// header, or if parsing fails to produce any valid operations, then
// immediately call `ContinueOnReceiveRedirect`
// - Otherwise, `ContinueOnReceiveRedirect` will be run asynchronously after
// forwarding the operations to `URLLoaderNetworkServiceObserver` to queue via
// Mojo
//
// Inbound control flow:
//
// Start in `ProcessInboundSharedStorageInterceptorOnResponseStarted`
// - Execute `SharedStorageRequestHelper::ProcessIncomingResponse`
// - If the request has received the `kSharedStorageWriteHeader` response
// header and if it is currently eligible for shared storage (i.e., in
// particular, the `kSecSharedStorageWritableHeader` has not been removed on a
// redirect), the helper will parse the header value into a vector of Shared
// Storage operations to call
// - If the request has not received the `kSharedStorageWriteHeader` response
// header, or if parsing fails to produce any valid operations, then
// immediately call `ContinueOnResponseStarted`
// - Otherwise, `ContinueOnResponseStarted` will be run asynchronously after
// forwarding the operations to `URLLoaderNetworkServiceObserver` to queue via
// Mojo
void ProcessOutboundSharedStorageInterceptor();
void ProcessInboundSharedStorageInterceptorOnReceivedRedirect(
const net::RedirectInfo& redirect_info,
mojom::URLResponseHeadPtr response);
void ProcessInboundSharedStorageInterceptorOnResponseStarted();
// Continuation of `OnReceivedRedirect` after possibly asynchronously
// concluding the request's Shared Storage operations.
void ContinueOnReceiveRedirect(const net::RedirectInfo& redirect_info,
mojom::URLResponseHeadPtr response);
// If Trust Tokens parameters are present, delegates Trust Token handling
// to `trust_token_interceptor_`.
// The interceptor manages the asynchronous Begin (outbound, adding headers)
// and Finalize (inbound, processing headers) steps. URLLoader receives
// results via the OnDone... callbacks.
// On error during either step, the request is failed via NotifyCompleted.
void ProcessOutboundTrustTokenInterceptor(const ResourceRequest& request);
// Callback receiving result (headers or error) of the interceptor's Begin
// step.
void OnDoneBeginningTrustTokenOperation(
base::expected<net::HttpRequestHeaders, net::Error> result);
// Callback receiving result (net::OK or error) of the interceptor's Finalize
// step.
void OnDoneFinalizingTrustTokenOperation(net::Error error);
// Continuation of `OnResponseStarted` after possibly asynchronously
// concluding the request's Trust Tokens, Attribution, and/or Shared Storage
// operations.
void ContinueOnResponseStarted();
void ScheduleStart();
void ReadMore();
void ReadMoreAsync();
void DidRead(int num_bytes,
bool completed_synchronously,
bool into_slop_bucket);
void NotifyCompleted(int error_code);
void OnMojoDisconnect();
void OnResponseBodyStreamConsumerClosed(MojoResult result);
void OnResponseBodyStreamReady(MojoResult result);
void DeleteSelf();
void SendResponseToClient();
void CompletePendingWrite(bool success);
void SetRawResponseHeaders(scoped_refptr<const net::HttpResponseHeaders>);
void NotifyEarlyResponse(scoped_refptr<const net::HttpResponseHeaders>);
void MaybeNotifyEarlyResponseToDevtools(const net::HttpResponseHeaders&);
void SetRawRequestHeadersAndNotify(net::HttpRawRequestHeaders);
bool IsSharedDictionaryReadAllowed();
void DispatchOnRawRequest(
std::vector<network::mojom::HttpRawHeaderPairPtr> headers);
void DispatchOnRawResponse();
void SendUploadProgress(const net::UploadProgress& progress);
void OnUploadProgressACK();
void OnSSLCertificateErrorResponse(const net::SSLInfo& ssl_info,
int net_error);
bool HasDataPipe() const;
void RecordBodyReadFromNetBeforePausedIfNeeded();
void ResumeStart();
void OnBeforeSendHeadersComplete(
net::NetworkDelegate::OnBeforeStartTransactionCallback callback,
int result,
const std::optional<net::HttpRequestHeaders>& headers);
void OnHeadersReceivedComplete(
net::CompletionOnceCallback callback,
scoped_refptr<net::HttpResponseHeaders>* out_headers,
std::optional<GURL>* out_preserve_fragment_on_redirect_url,
int result,
const std::optional<std::string>& headers,
const std::optional<GURL>& preserve_fragment_on_redirect_url);
void CompleteBlockedResponse(
int error_code,
bool should_report_orb_blocking,
std::optional<mojom::BlockedByResponseReason> reason = std::nullopt);
enum BlockResponseForOrbResult {
// Returned when caller of BlockResponseForOrb doesn't need to continue,
// because the request will be cancelled soon.
kWillCancelRequest,
// Returned when the caller of BlockResponseForOrb should continue
// processing the request (e.g. by calling ReadMore as necessary).
kContinueRequest,
};
// Block the response because of ORB.
BlockResponseForOrbResult BlockResponseForOrb();
// Decide whether to call block a response via BlockResponseForOrb.
// Returns true if the request should be cancelled.
bool MaybeBlockResponseForOrb(orb::ResponseAnalyzer::Decision);
void ReportFlaggedResponseCookies(bool call_cookie_observer);
void StartReading();
// Whether `force_ignore_site_for_cookies` should be set on net::URLRequest.
bool ShouldForceIgnoreSiteForCookies(const ResourceRequest& request);
mojom::DevToolsObserver* GetDevToolsObserver() const;
mojom::CookieAccessObserver* GetCookieAccessObserver() const;
// Builds a response struct based on the data received so far.
// Never returns nullptr.
mojom::URLResponseHeadPtr BuildResponseHead() const;
// Returns whether TransferSizeUpdated IPC should be sent.
bool ShouldSendTransferSizeUpdated() const;
// Returns true if the corresponding `URLResponseHead`'s
// `load_with_storage_access` field should be set.
bool ShouldSetLoadWithStorageAccess() const;
// Reads more decoded data from the PartialDecoder.
void ReadDecodedDataFromPartialDecoder();
// Callback function to asynchronously receive the result from the
// PartialDecoder.
void OnReadDecodedDataFromPartialDecoder(int result);
// Checks the result from the PartialDecoder, performs MIME and ORB sniffing
// on the decoded data, and determines if more sniffing is needed.
// If no further decoding is needed, `partial_decoder_` is reset, and
// `partial_decoder_result_` is set unless an error occurred during decoding.
void CheckPartialDecoderResult(int result);
// Gets the client security state that should apply to the request. May be the
// value from the request (if present), the URLLoaderFactoryParams, or null.
const mojom::ClientSecurityState* GetClientSecurityState();
// Resets raw headers retrieved from underlying net::URLRequest before
// starting another network transaction (such as following a redirect).
void ResetRawHeadersForRedirect();
// If Devtools Durable Message collection is enabled, copies the response
// chunks into `devtools_durable_message_`. If `num_bytes` <= 0, marks the
// message as complete.
void MaybeCollectDurableMessage(size_t new_data_offset, int num_bytes);
const raw_ptr<net::URLRequestContext> url_request_context_;
const raw_ptr<mojom::NetworkContextClient> network_context_client_;
DeleteCallback delete_callback_;
const int resource_type_;
const bool is_load_timing_enabled_;
bool has_received_response_ = false;
// URLLoaderFactory is guaranteed to outlive URLLoader, so it is safe to
// store a raw pointer to mojom::URLLoaderFactoryParams.
const raw_ref<const mojom::URLLoaderFactoryParams> factory_params_;
// The following also belong to URLLoaderFactory and outlives this loader.
const raw_ptr<mojom::CrossOriginEmbedderPolicyReporter> coep_reporter_;
const raw_ptr<mojom::DocumentIsolationPolicyReporter> dip_reporter_;
const int32_t request_id_;
const int keepalive_request_size_;
const bool keepalive_;
// ClientSecurityState from ResourceRequest::trusted_params, if present.
// Otherwise, null. Use GetClientSecurityState() to access, which falls back
// to the value from the URLLoaderFactory.
const mojom::ClientSecurityStatePtr client_security_state_;
const bool do_not_prompt_for_login_;
std::unique_ptr<net::URLRequest> url_request_;
mojo::Receiver<mojom::URLLoader> receiver_;
mojo::Receiver<mojom::AuthChallengeResponder>
auth_challenge_responder_receiver_{this};
mojo::Receiver<mojom::ClientCertificateResponder>
client_cert_responder_receiver_{this};
MaybeSyncURLLoaderClient url_loader_client_;
int64_t total_written_bytes_ = 0;
mojo::ScopedDataPipeProducerHandle response_body_stream_;
scoped_refptr<NetToMojoPendingBuffer> pending_write_;
uint32_t pending_write_buffer_size_ = 0;
uint32_t pending_write_buffer_offset_ = 0;
mojo::SimpleWatcher writable_handle_watcher_;
mojo::SimpleWatcher peer_closed_handle_watcher_;
scoped_refptr<net::IOBufferWithSize> discard_buffer_;
// State checker between URLRequest::Read() and `response_body_stream_`.
enum class URLReadState {
// While waiting for `response_body_stream_` to be writable.
// TODO(yoichio): Since ReadMore() is called both when mojo pipe is ready
// to read and we want to write to the pipe.
// Consider spliting this into kNotReading and kWaitMojoPipeWritable.
kWaitMojoPipeWritable,
// While async URLRequest::ReadMore() task is posted.
kReadMoreTaskPosted,
// While there's a URLRequest::Read() call in progress.
kURLReadInProgress
};
URLReadState url_read_state_ = URLReadState::kWaitMojoPipeWritable;
// Stores any CORS error encountered while processing |url_request_|.
std::optional<CorsErrorStatus> cors_error_status_;
// Used when deferring sending the data to the client until mime sniffing is
// finished.
mojom::URLResponseHeadPtr response_;
mojo::ScopedDataPipeConsumerHandle consumer_handle_;
// Sniffing state and ORB state.
bool is_more_orb_sniffing_needed_ = false;
bool is_more_mime_sniffing_needed_ = false;
std::optional<std::string> mime_type_before_sniffing_;
const raw_ref<orb::PerFactoryState> per_factory_orb_state_;
// `orb_analyzer_` must be destructed before `per_factory_orb_state_`.
std::unique_ptr<orb::ResponseAnalyzer> orb_analyzer_;
std::unique_ptr<ResourceScheduler::ScheduledResourceRequest>
resource_scheduler_request_handle_;
scoped_refptr<const net::HttpResponseHeaders> raw_response_headers_;
std::unique_ptr<UploadProgressTracker> upload_progress_tracker_;
// Holds the URL of a redirect if it's currently deferred.
std::unique_ptr<GURL> deferred_redirect_url_;
// If |new_url| is given to FollowRedirect() it's saved here, so that it can
// be later referred to from NetworkContext::OnBeforeURLRequestInternal, which
// is called from NetworkDelegate::NotifyBeforeURLRequest.
std::optional<GURL> new_redirect_url_;
// The ID that DevTools uses to track network requests. It is generated in the
// renderer process and is only present when DevTools is enabled in the
// renderer.
const std::optional<std::string> devtools_request_id_;
const int32_t options_;
// This is used to compute the delta since last time received
// encoded body size was reported to the client.
int64_t reported_total_encoded_bytes_ = 0;
const mojom::RequestMode request_mode_;
const mojom::CredentialsMode request_credentials_mode_;
const bool has_user_activation_ = false;
const mojom::RequestDestination request_destination_ =
mojom::RequestDestination::kEmpty;
const std::vector<std::vector<uint8_t>> expected_public_keys_;
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder_;
bool first_auth_attempt_ = true;
std::unique_ptr<ScopedThrottlingToken> throttling_token_;
// Indicates the originating frame of the request, see
// network::ResourceRequest::fetch_window_id for details.
const std::optional<base::UnguessableToken> fetch_window_id_;
// Must be below `client_security_state_`.
PrivateNetworkAccessUrlLoaderInterceptor private_network_access_interceptor_;
mojo::Remote<mojom::TrustedHeaderClient> header_client_;
// Handles asynchronously opening files for upload. Holds a reference to the
// request's URL (from `url_request_`), so `url_request_` must outlive this.
std::unique_ptr<FileOpenerForUpload> file_opener_for_upload_;
// If the request is configured for Trust Tokens
// (https://github.com/WICG/trust-token-api) protocol operations, annotates
// the request with the pertinent request headers and, on receiving the
// corresponding response, processes and strips Trust Tokens response headers.
std::unique_ptr<TrustTokenUrlLoaderInterceptor> trust_token_interceptor_;
// This is used to determine whether it is allowed to use a dictionary when
// there is a matching shared dictionary for the request.
std::unique_ptr<SharedDictionaryAccessChecker> shared_dictionary_checker_;
// Outlives `this`.
const raw_ref<const cors::OriginAccessList> origin_access_list_;
// Observer instances relevant to this URLLoader.
// Each ObserverWrapper encapsulates either a Mojo Remote for an observer
// specific to this request (usually passed via TrustedParams) or a fallback
// pointer (usually pointing to a shared observer implementation held by the
// URLLoaderFactory/URLLoaderContext).
ObserverWrapper<mojom::CookieAccessObserver> cookie_observer_;
ObserverWrapper<mojom::TrustTokenAccessObserver> trust_token_observer_;
ObserverWrapper<mojom::URLLoaderNetworkServiceObserver>
url_loader_network_observer_;
ObserverWrapper<mojom::DevToolsObserver> devtools_observer_;
ObserverWrapper<mojom::DeviceBoundSessionAccessObserver>
device_bound_session_observer_;
const scoped_refptr<RefCountedDeviceBoundSessionAccessObserverRemote>
device_bound_session_observer_shared_remote_;
// Request helper responsible for processing Shared Storage headers
// (https://github.com/WICG/shared-storage#from-response-headers).
std::unique_ptr<SharedStorageRequestHelper> shared_storage_request_helper_;
// Request helper responsible for processing Ad Auction record event
// headers.
// (https://github.com/WICG/turtledove/pull/1279)
AdAuctionEventRecordRequestHelper ad_auction_event_record_request_helper_;
// Indicates |url_request_| is fetch upload request and that has streaming
// body.
const bool has_fetch_streaming_upload_body_;
// Whether DevToolsObserver::OnRaw{Request,Response} should be emitted
// (i.e. the request being loaded is monitored by DevTools).
bool enable_reporting_raw_headers_ = false;
// Whether DevToolsObserver::OnRaw{Request,Response} have been emitted for
// the current redirect hop. This assures we report raw request/response
// not more than once per redirect and that we only either report both
// or neither request and response.
bool emitted_devtools_raw_request_ = false;
bool emitted_devtools_raw_response_ = false;
// Used for metrics.
size_t raw_request_line_size_ = 0;
size_t raw_request_headers_size_ = 0;
// Handles processing of the ACCEPT_CH frame during connection, if enabled
// and an observer exists. May be nullptr.
std::unique_ptr<AcceptCHFrameInterceptor> accept_ch_frame_interceptor_;
// Stores cookies passed from the browser process to later add them to the
// request. This prevents the network stack from overriding them.
const bool allow_cookies_from_browser_ = false;
std::string cookies_from_browser_;
// Specifies that the response head should include request cookies.
const bool include_request_cookies_with_response_ = false;
net::cookie_util::ParsedRequestCookies request_cookies_;
// Specifies that the response head should include load timing internal info.
const bool include_load_timing_internal_info_with_response_;
std::vector<network::mojom::CookieAccessDetailsPtr> cookie_access_details_;
const bool provide_data_use_updates_;
// A SlopBucket is used as temporary storage for response body data from
// high-priority requests that cannot yet be written to the mojo data pipe
// because it is full.
std::unique_ptr<SlopBucket> slop_bucket_;
// Internal counters to record UMA for SlopBucket.
int mojo_begin_write_count_for_uma_ = 0;
int mojo_blocked_write_count_for_uma_ = 0;
bool was_slop_bucket_enabled_ = false;
// For decoding a small part of the response body to check its type (for ORB
// and MIME sniffing) when the response might be compressed and client-side
// content decoding is enabled.
std::unique_ptr<PartialDecoder> partial_decoder_;
// Keeps the original, compressed data from `partial_decoder_`.
std::optional<PartialDecoderResult> partial_decoder_result_;
// How much decoded data `partial_decoder_` should hold for the type check.
int partial_decoder_decoding_buffer_size_;
// Keeps the result of IsSharedDictionaryReadAllowed(). Used only for metrics.
bool shared_dictionary_allowed_check_passed_ = false;
// Permissions policy of the request.
const std::optional<network::PermissionsPolicy> permissions_policy_;
// DevTools Durable Message instance, if enabled.
base::WeakPtr<DevtoolsDurableMessage> devtools_durable_message_;
// Keeps track of raw body sizes transmitted to DevTools.
int64_t devtools_durable_message_raw_size_ = 0;
base::WeakPtrFactory<URLLoader> weak_ptr_factory_{this};
};
} // namespace network
#endif // SERVICES_NETWORK_URL_LOADER_H_