#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "content/browser/devtools/devtools_url_loader_interceptor.h"
#include <memory>
#include <optional>
#include <string_view>
#include "base/barrier_closure.h"
#include "base/base64.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/no_destructor.h"
#include "base/strings/pattern.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/unguessable_token.h"
#include "content/browser/devtools/protocol/network.h"
#include "content/browser/devtools/protocol/network_handler.h"
#include "content/browser/devtools/request_body_collector.h"
#include "content/browser/loader/download_utils_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_client.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/system/data_pipe_drainer.h"
#include "net/base/load_flags.h"
#include "net/base/mime_sniffer.h"
#include "net/cookies/cookie_access_result.h"
#include "net/cookies/cookie_util.h"
#include "net/http/http_util.h"
#include "net/url_request/redirect_info.h"
#include "net/url_request/redirect_util.h"
#include "net/url_request/referrer_policy.h"
#include "services/network/public/cpp/cors/cors.h"
#include "services/network/public/cpp/header_util.h"
#include "services/network/public/cpp/record_ontransfersizeupdate_utils.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/resource_request_body.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
#include "services/network/public/mojom/early_hints.mojom.h"
#include "services/network/public/mojom/encoded_body_length.mojom-forward.h"
#include "services/network/public/mojom/encoded_body_length.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "third_party/blink/public/platform/resource_request_blocked_reason.h"
namespace content {
InterceptedRequestInfo::InterceptedRequestInfo() = default;
InterceptedRequestInfo::~InterceptedRequestInfo() = default;
DevToolsURLLoaderInterceptor::AuthChallengeResponse::AuthChallengeResponse(
ResponseType response_type)
: … { … }
DevToolsURLLoaderInterceptor::AuthChallengeResponse::AuthChallengeResponse(
const std::u16string& username,
const std::u16string& password)
: … { … }
DevToolsURLLoaderInterceptor::FilterEntry::FilterEntry(
const base::UnguessableToken& target_id,
std::vector<Pattern> patterns,
RequestInterceptedCallback callback)
: … { … }
DevToolsURLLoaderInterceptor::FilterEntry::FilterEntry(FilterEntry&&) = default;
DevToolsURLLoaderInterceptor::FilterEntry::~FilterEntry() = default;
DevToolsURLLoaderInterceptor::Modifications::Modifications() = default;
DevToolsURLLoaderInterceptor::Modifications::Modifications(
net::Error error_reason)
: … { … }
DevToolsURLLoaderInterceptor::Modifications::Modifications(
scoped_refptr<net::HttpResponseHeaders> response_headers,
scoped_refptr<base::RefCountedMemory> response_body)
: … { … }
DevToolsURLLoaderInterceptor::Modifications::Modifications(
std::unique_ptr<AuthChallengeResponse> auth_challenge_response)
: … { … }
DevToolsURLLoaderInterceptor::Modifications::Modifications(
protocol::Maybe<std::string> modified_url,
protocol::Maybe<std::string> modified_method,
protocol::Maybe<protocol::Binary> modified_post_data,
std::unique_ptr<HeadersVector> modified_headers,
protocol::Maybe<bool> intercept_response)
: … { … }
DevToolsURLLoaderInterceptor::Modifications::Modifications(
std::optional<net::Error> error_reason,
scoped_refptr<net::HttpResponseHeaders> response_headers,
scoped_refptr<base::RefCountedMemory> response_body,
size_t body_offset,
protocol::Maybe<std::string> modified_url,
protocol::Maybe<std::string> modified_method,
protocol::Maybe<protocol::Binary> modified_post_data,
std::unique_ptr<HeadersVector> modified_headers,
std::unique_ptr<AuthChallengeResponse> auth_challenge_response)
: … { … }
DevToolsURLLoaderInterceptor::Modifications::~Modifications() = default;
DevToolsURLLoaderInterceptor::Pattern::~Pattern() = default;
DevToolsURLLoaderInterceptor::Pattern::Pattern(const Pattern& other) = default;
DevToolsURLLoaderInterceptor::Pattern::Pattern(
const std::string& url_pattern,
base::flat_set<blink::mojom::ResourceType> resource_types,
InterceptionStage interception_stage)
: … { … }
bool DevToolsURLLoaderInterceptor::Pattern::Matches(
const std::string& url,
blink::mojom::ResourceType resource_type) const { … }
struct CreateLoaderParameters { … };
namespace {
RequestInterceptedCallback;
ContinueInterceptedRequestCallback;
GetResponseBodyCallback;
TakeResponseBodyPipeCallback;
Modifications;
InterceptionStage;
Response;
CredentialsMode;
FetchResponseType;
class BodyReader : public mojo::DataPipeDrainer::Client { … };
void BodyReader::StartReading(mojo::ScopedDataPipeConsumerHandle body) { … }
void BodyReader::OnDataComplete() { … }
struct ResponseMetadata { … };
void RemoveUnsafeRequestHeadersOnRedirect(net::HttpRequestHeaders& headers) { … }
class HeadersOverride { … };
}
class InterceptionJob : public network::mojom::URLLoaderClient,
public network::mojom::URLLoader { … };
void DevToolsURLLoaderInterceptor::CreateJob(
const base::UnguessableToken& frame_token,
int32_t process_id,
bool is_download,
const std::optional<std::string>& renderer_request_id,
std::unique_ptr<CreateLoaderParameters> create_params,
mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory,
mojo::PendingRemote<network::mojom::CookieManager> cookie_manager) { … }
DevToolsURLLoaderInterceptor::InterceptionStages
DevToolsURLLoaderInterceptor::GetInterceptionStages(
const GURL& url,
blink::mojom::ResourceType resource_type) const { … }
class DevToolsURLLoaderFactoryProxy : public network::mojom::URLLoaderFactory { … };
DevToolsURLLoaderFactoryProxy::DevToolsURLLoaderFactoryProxy(
const base::UnguessableToken& frame_token,
int32_t process_id,
bool is_download,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_remote,
mojo::PendingRemote<network::mojom::CookieManager> cookie_manager,
base::WeakPtr<DevToolsURLLoaderInterceptor> interceptor)
: … { … }
DevToolsURLLoaderFactoryProxy::~DevToolsURLLoaderFactoryProxy() = default;
void DevToolsURLLoaderFactoryProxy::CreateLoaderAndStart(
mojo::PendingReceiver<network::mojom::URLLoader> loader,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& request,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) { … }
void DevToolsURLLoaderFactoryProxy::Clone(
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) { … }
void DevToolsURLLoaderFactoryProxy::OnTargetFactoryError() { … }
void DevToolsURLLoaderFactoryProxy::OnProxyBindingError() { … }
void DevToolsURLLoaderInterceptor::HandleAuthRequest(
GlobalRequestID req_id,
const net::AuthChallengeInfo& auth_info,
HandleAuthRequestCallback callback) { … }
DevToolsURLLoaderInterceptor::DevToolsURLLoaderInterceptor(
RequestInterceptedCallback callback)
: … { … }
DevToolsURLLoaderInterceptor::~DevToolsURLLoaderInterceptor() { … }
void DevToolsURLLoaderInterceptor::SetPatterns(
std::vector<DevToolsURLLoaderInterceptor::Pattern> patterns,
bool handle_auth) { … }
void DevToolsURLLoaderInterceptor::GetResponseBody(
const std::string& interception_id,
std::unique_ptr<GetResponseBodyCallback> callback) { … }
void DevToolsURLLoaderInterceptor::TakeResponseBodyPipe(
const std::string& interception_id,
DevToolsURLLoaderInterceptor::TakeResponseBodyPipeCallback callback) { … }
void DevToolsURLLoaderInterceptor::ContinueInterceptedRequest(
const std::string& interception_id,
std::unique_ptr<Modifications> modifications,
std::unique_ptr<ContinueInterceptedRequestCallback> callback) { … }
bool DevToolsURLLoaderInterceptor::CreateProxyForInterception(
int process_id,
StoragePartition* storage_partition,
const base::UnguessableToken& frame_token,
bool is_navigation,
bool is_download,
network::mojom::URLLoaderFactoryOverride* intercepting_factory) { … }
InterceptionJob::InterceptionJob(
DevToolsURLLoaderInterceptor* interceptor,
const std::string& id,
const base::UnguessableToken& frame_token,
int process_id,
const std::optional<std::string>& renderer_request_id,
std::unique_ptr<CreateLoaderParameters> create_loader_params,
bool is_download,
mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory,
mojo::PendingRemote<network::mojom::CookieManager> cookie_manager)
: … { … }
bool InterceptionJob::StartJobAndMaybeNotify() { … }
network::mojom::FetchResponseType InterceptionJob::CalculateResponseTainting() { … }
network::ResourceRequest InterceptionJob::GetResourceRequestForCookies() { … }
void InterceptionJob::UpdateCORSFlag() { … }
bool InterceptionJob::CanGetResponseBody(std::string* error_reason) { … }
void InterceptionJob::GetResponseBody(
std::unique_ptr<GetResponseBodyCallback> callback) { … }
void InterceptionJob::TakeResponseBodyPipe(
TakeResponseBodyPipeCallback callback) { … }
void InterceptionJob::ContinueInterceptedRequest(
std::unique_ptr<Modifications> modifications,
std::unique_ptr<ContinueInterceptedRequestCallback> callback) { … }
void InterceptionJob::Detach() { … }
Response InterceptionJob::InnerContinueRequest(
std::unique_ptr<Modifications> modifications) { … }
void InterceptionJob::ProcessFollowRedirect(
const net::HttpRequestHeaders& modified_cors_exempt_headers) { … }
void InterceptionJob::ApplyModificationsToRequest(
std::unique_ptr<Modifications> modifications) { … }
void InterceptionJob::ProcessAuthResponse(
const DevToolsURLLoaderInterceptor::AuthChallengeResponse& response) { … }
Response InterceptionJob::ProcessResponseOverride(
scoped_refptr<net::HttpResponseHeaders> headers,
scoped_refptr<base::RefCountedMemory> body,
size_t response_body_offset) { … }
void InterceptionJob::ProcessSetCookies(const net::HttpResponseHeaders& headers,
base::OnceClosure callback) { … }
void InterceptionJob::ProcessRedirectByClient(const GURL& redirect_url) { … }
void InterceptionJob::SendResponse(scoped_refptr<base::RefCountedMemory> body,
size_t offset) { … }
void InterceptionJob::ResponseBodyComplete() { … }
void InterceptionJob::StartRequest() { … }
void InterceptionJob::CancelRequest() { … }
std::unique_ptr<InterceptedRequestInfo> InterceptionJob::BuildRequestInfo(
const network::mojom::URLResponseHeadPtr& head) { … }
void InterceptionJob::FetchCookies(base::OnceClosure callback) { … }
void InterceptionJob::NotifyClient(
std::unique_ptr<InterceptedRequestInfo> request_info) { … }
void InterceptionJob::OnGotCookies(
base::OnceClosure callback,
const net::CookieAccessResultList& cookies_with_access_result,
const net::CookieAccessResultList& excluded_cookies) { … }
void InterceptionJob::OnGotRequestBodies(
base::OnceClosure callback,
std::vector<RequestBodyCollector::BodyEntry> bodies) { … }
void InterceptionJob::CompleteNotifyingClient(
std::unique_ptr<InterceptedRequestInfo> request_info) { … }
void InterceptionJob::CompleteRequest(
const network::URLLoaderCompletionStatus& status) { … }
void InterceptionJob::Shutdown() { … }
void InterceptionJob::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) { … }
void InterceptionJob::SetPriority(net::RequestPriority priority,
int32_t intra_priority_value) { … }
void InterceptionJob::PauseReadingBodyFromNet() { … }
void InterceptionJob::ResumeReadingBodyFromNet() { … }
void InterceptionJob::OnReceiveEarlyHints(
network::mojom::EarlyHintsPtr early_hints) { … }
void InterceptionJob::OnReceiveResponse(
network::mojom::URLResponseHeadPtr head,
mojo::ScopedDataPipeConsumerHandle body,
std::optional<mojo_base::BigBuffer> cached_metadata) { … }
void InterceptionJob::OnReceiveRedirect(
const net::RedirectInfo& redirect_info,
network::mojom::URLResponseHeadPtr head) { … }
void InterceptionJob::OnUploadProgress(int64_t current_position,
int64_t total_size,
OnUploadProgressCallback callback) { … }
void InterceptionJob::OnTransferSizeUpdated(int32_t transfer_size_diff) { … }
void InterceptionJob::StartLoadingResponseBody(
mojo::ScopedDataPipeConsumerHandle body) { … }
void InterceptionJob::OnComplete(
const network::URLLoaderCompletionStatus& status) { … }
void InterceptionJob::OnAuthRequest(
const net::AuthChallengeInfo& auth_info,
DevToolsURLLoaderInterceptor::HandleAuthRequestCallback callback) { … }
}