296 lines
11 KiB
C++
296 lines
11 KiB
C++
/* Copyright (c) 2019 The Brave Authors. All rights reserved.
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "brave/browser/net/brave_request_handler.h"
|
|
|
|
#include <algorithm>
|
|
#include <utility>
|
|
|
|
#include "base/containers/contains.h"
|
|
#include "base/feature_list.h"
|
|
#include "base/task/post_task.h"
|
|
#include "brave/browser/net/brave_ad_block_csp_network_delegate_helper.h"
|
|
#include "brave/browser/net/brave_ad_block_tp_network_delegate_helper.h"
|
|
#include "brave/browser/net/brave_common_static_redirect_network_delegate_helper.h"
|
|
#include "brave/browser/net/brave_httpse_network_delegate_helper.h"
|
|
#include "brave/browser/net/brave_service_key_network_delegate_helper.h"
|
|
#include "brave/browser/net/brave_site_hacks_network_delegate_helper.h"
|
|
#include "brave/browser/net/brave_stp_util.h"
|
|
#include "brave/browser/net/global_privacy_control_network_delegate_helper.h"
|
|
#include "brave/browser/net/url_context.h"
|
|
#include "brave/common/pref_names.h"
|
|
#include "brave/components/brave_referrals/buildflags/buildflags.h"
|
|
#include "brave/components/brave_rewards/browser/net/network_delegate_helper.h"
|
|
#include "brave/components/brave_shields/common/features.h"
|
|
#include "brave/components/brave_webtorrent/browser/buildflags/buildflags.h"
|
|
#include "brave/components/decentralized_dns/buildflags/buildflags.h"
|
|
#include "brave/components/ipfs/buildflags/buildflags.h"
|
|
#include "chrome/browser/browser_process.h"
|
|
#include "content/public/browser/browser_task_traits.h"
|
|
#include "content/public/browser/browser_thread.h"
|
|
#include "content/public/common/url_constants.h"
|
|
#include "extensions/common/constants.h"
|
|
#include "net/base/net_errors.h"
|
|
|
|
#if BUILDFLAG(ENABLE_BRAVE_REFERRALS)
|
|
#include "brave/browser/net/brave_referrals_network_delegate_helper.h"
|
|
#endif
|
|
|
|
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
|
|
#include "brave/browser/net/brave_torrent_redirect_network_delegate_helper.h"
|
|
#endif
|
|
|
|
#if BUILDFLAG(ENABLE_IPFS)
|
|
#include "brave/browser/net/ipfs_redirect_network_delegate_helper.h"
|
|
#include "brave/components/ipfs/features.h"
|
|
#endif
|
|
|
|
#if BUILDFLAG(DECENTRALIZED_DNS_ENABLED)
|
|
#include "brave/browser/net/decentralized_dns_network_delegate_helper.h"
|
|
#endif
|
|
|
|
static bool IsInternalScheme(std::shared_ptr<brave::BraveRequestInfo> ctx) {
|
|
DCHECK(ctx);
|
|
return ctx->request_url.SchemeIs(extensions::kExtensionScheme) ||
|
|
ctx->request_url.SchemeIs(content::kChromeUIScheme);
|
|
}
|
|
|
|
BraveRequestHandler::BraveRequestHandler() {
|
|
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
|
SetupCallbacks();
|
|
}
|
|
|
|
BraveRequestHandler::~BraveRequestHandler() = default;
|
|
|
|
void BraveRequestHandler::SetupCallbacks() {
|
|
brave::OnBeforeURLRequestCallback callback =
|
|
base::BindRepeating(brave::OnBeforeURLRequest_SiteHacksWork);
|
|
before_url_request_callbacks_.push_back(callback);
|
|
|
|
callback = base::BindRepeating(brave::OnBeforeURLRequest_AdBlockTPPreWork);
|
|
before_url_request_callbacks_.push_back(callback);
|
|
|
|
callback = base::BindRepeating(brave::OnBeforeURLRequest_HttpsePreFileWork);
|
|
before_url_request_callbacks_.push_back(callback);
|
|
|
|
callback =
|
|
base::BindRepeating(brave::OnBeforeURLRequest_CommonStaticRedirectWork);
|
|
before_url_request_callbacks_.push_back(callback);
|
|
|
|
#if BUILDFLAG(DECENTRALIZED_DNS_ENABLED)
|
|
callback = base::BindRepeating(
|
|
decentralized_dns::OnBeforeURLRequest_DecentralizedDnsPreRedirectWork);
|
|
before_url_request_callbacks_.push_back(callback);
|
|
#endif
|
|
|
|
callback = base::BindRepeating(brave_rewards::OnBeforeURLRequest);
|
|
before_url_request_callbacks_.push_back(callback);
|
|
|
|
#if BUILDFLAG(ENABLE_IPFS)
|
|
if (base::FeatureList::IsEnabled(ipfs::features::kIpfsFeature)) {
|
|
callback = base::BindRepeating(ipfs::OnBeforeURLRequest_IPFSRedirectWork);
|
|
before_url_request_callbacks_.push_back(callback);
|
|
brave::OnHeadersReceivedCallback ipfs_headers_received_callback =
|
|
base::BindRepeating(ipfs::OnHeadersReceived_IPFSRedirectWork);
|
|
headers_received_callbacks_.push_back(ipfs_headers_received_callback);
|
|
}
|
|
#endif
|
|
|
|
brave::OnBeforeStartTransactionCallback start_transaction_callback =
|
|
base::BindRepeating(brave::OnBeforeStartTransaction_SiteHacksWork);
|
|
before_start_transaction_callbacks_.push_back(start_transaction_callback);
|
|
|
|
start_transaction_callback = base::BindRepeating(
|
|
brave::OnBeforeStartTransaction_GlobalPrivacyControlWork);
|
|
before_start_transaction_callbacks_.push_back(start_transaction_callback);
|
|
|
|
start_transaction_callback =
|
|
base::BindRepeating(brave::OnBeforeStartTransaction_BraveServiceKey);
|
|
before_start_transaction_callbacks_.push_back(start_transaction_callback);
|
|
|
|
#if BUILDFLAG(ENABLE_BRAVE_REFERRALS)
|
|
start_transaction_callback =
|
|
base::BindRepeating(brave::OnBeforeStartTransaction_ReferralsWork);
|
|
before_start_transaction_callbacks_.push_back(start_transaction_callback);
|
|
#endif
|
|
|
|
#if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT)
|
|
brave::OnHeadersReceivedCallback headers_received_callback =
|
|
base::BindRepeating(webtorrent::OnHeadersReceived_TorrentRedirectWork);
|
|
headers_received_callbacks_.push_back(headers_received_callback);
|
|
#endif
|
|
|
|
if (base::FeatureList::IsEnabled(
|
|
::brave_shields::features::kBraveAdblockCspRules)) {
|
|
brave::OnHeadersReceivedCallback headers_received_callback2 =
|
|
base::BindRepeating(brave::OnHeadersReceived_AdBlockCspWork);
|
|
headers_received_callbacks_.push_back(headers_received_callback2);
|
|
}
|
|
}
|
|
|
|
bool BraveRequestHandler::IsRequestIdentifierValid(
|
|
uint64_t request_identifier) {
|
|
return base::Contains(callbacks_, request_identifier);
|
|
}
|
|
|
|
int BraveRequestHandler::OnBeforeURLRequest(
|
|
std::shared_ptr<brave::BraveRequestInfo> ctx,
|
|
net::CompletionOnceCallback callback,
|
|
GURL* new_url) {
|
|
if (before_url_request_callbacks_.empty() || IsInternalScheme(ctx)) {
|
|
return net::OK;
|
|
}
|
|
ctx->new_url = new_url;
|
|
ctx->event_type = brave::kOnBeforeRequest;
|
|
callbacks_[ctx->request_identifier] = std::move(callback);
|
|
RunNextCallback(ctx);
|
|
return net::ERR_IO_PENDING;
|
|
}
|
|
|
|
int BraveRequestHandler::OnBeforeStartTransaction(
|
|
std::shared_ptr<brave::BraveRequestInfo> ctx,
|
|
net::CompletionOnceCallback callback,
|
|
net::HttpRequestHeaders* headers) {
|
|
if (before_start_transaction_callbacks_.empty() || IsInternalScheme(ctx)) {
|
|
return net::OK;
|
|
}
|
|
ctx->event_type = brave::kOnBeforeStartTransaction;
|
|
ctx->headers = headers;
|
|
callbacks_[ctx->request_identifier] = std::move(callback);
|
|
RunNextCallback(ctx);
|
|
return net::ERR_IO_PENDING;
|
|
}
|
|
|
|
int BraveRequestHandler::OnHeadersReceived(
|
|
std::shared_ptr<brave::BraveRequestInfo> ctx,
|
|
net::CompletionOnceCallback callback,
|
|
const net::HttpResponseHeaders* original_response_headers,
|
|
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
|
|
GURL* allowed_unsafe_redirect_url) {
|
|
if (!ctx->tab_origin.is_empty()) {
|
|
brave::RemoveTrackableSecurityHeadersForThirdParty(
|
|
ctx->request_url, url::Origin::Create(ctx->tab_origin),
|
|
original_response_headers, override_response_headers);
|
|
}
|
|
|
|
if (headers_received_callbacks_.empty() &&
|
|
!ctx->request_url.SchemeIs(content::kChromeUIScheme)) {
|
|
// Extension scheme not excluded since brave_webtorrent needs it.
|
|
return net::OK;
|
|
}
|
|
|
|
callbacks_[ctx->request_identifier] = std::move(callback);
|
|
ctx->event_type = brave::kOnHeadersReceived;
|
|
ctx->original_response_headers = original_response_headers;
|
|
ctx->override_response_headers = override_response_headers;
|
|
ctx->allowed_unsafe_redirect_url = allowed_unsafe_redirect_url;
|
|
|
|
RunNextCallback(ctx);
|
|
return net::ERR_IO_PENDING;
|
|
}
|
|
|
|
void BraveRequestHandler::OnURLRequestDestroyed(
|
|
std::shared_ptr<brave::BraveRequestInfo> ctx) {
|
|
if (base::Contains(callbacks_, ctx->request_identifier)) {
|
|
callbacks_.erase(ctx->request_identifier);
|
|
}
|
|
}
|
|
|
|
void BraveRequestHandler::RunCallbackForRequestIdentifier(
|
|
uint64_t request_identifier,
|
|
int rv) {
|
|
std::map<uint64_t, net::CompletionOnceCallback>::iterator it =
|
|
callbacks_.find(request_identifier);
|
|
// We intentionally do the async call to maintain the proper flow
|
|
// of URLLoader callbacks.
|
|
base::PostTask(FROM_HERE, {content::BrowserThread::UI},
|
|
base::BindOnce(std::move(it->second), rv));
|
|
}
|
|
|
|
// TODO(iefremov): Merge all callback containers into one and run only one loop
|
|
// instead of many (issues/5574).
|
|
void BraveRequestHandler::RunNextCallback(
|
|
std::shared_ptr<brave::BraveRequestInfo> ctx) {
|
|
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
|
|
|
if (!base::Contains(callbacks_, ctx->request_identifier)) {
|
|
return;
|
|
}
|
|
|
|
// Continue processing callbacks until we hit one that returns PENDING
|
|
int rv = net::OK;
|
|
|
|
if (ctx->event_type == brave::kOnBeforeRequest) {
|
|
while (before_url_request_callbacks_.size() !=
|
|
ctx->next_url_request_index) {
|
|
brave::OnBeforeURLRequestCallback callback =
|
|
before_url_request_callbacks_[ctx->next_url_request_index++];
|
|
brave::ResponseCallback next_callback =
|
|
base::BindRepeating(&BraveRequestHandler::RunNextCallback,
|
|
weak_factory_.GetWeakPtr(), ctx);
|
|
rv = callback.Run(next_callback, ctx);
|
|
if (rv == net::ERR_IO_PENDING) {
|
|
return;
|
|
}
|
|
if (rv != net::OK) {
|
|
break;
|
|
}
|
|
}
|
|
} else if (ctx->event_type == brave::kOnBeforeStartTransaction) {
|
|
while (before_start_transaction_callbacks_.size() !=
|
|
ctx->next_url_request_index) {
|
|
brave::OnBeforeStartTransactionCallback callback =
|
|
before_start_transaction_callbacks_[ctx->next_url_request_index++];
|
|
brave::ResponseCallback next_callback =
|
|
base::BindRepeating(&BraveRequestHandler::RunNextCallback,
|
|
weak_factory_.GetWeakPtr(), ctx);
|
|
rv = callback.Run(ctx->headers, next_callback, ctx);
|
|
if (rv == net::ERR_IO_PENDING) {
|
|
return;
|
|
}
|
|
if (rv != net::OK) {
|
|
break;
|
|
}
|
|
}
|
|
} else if (ctx->event_type == brave::kOnHeadersReceived) {
|
|
while (headers_received_callbacks_.size() != ctx->next_url_request_index) {
|
|
brave::OnHeadersReceivedCallback callback =
|
|
headers_received_callbacks_[ctx->next_url_request_index++];
|
|
brave::ResponseCallback next_callback =
|
|
base::BindRepeating(&BraveRequestHandler::RunNextCallback,
|
|
weak_factory_.GetWeakPtr(), ctx);
|
|
rv = callback.Run(ctx->original_response_headers,
|
|
ctx->override_response_headers,
|
|
ctx->allowed_unsafe_redirect_url, next_callback, ctx);
|
|
if (rv == net::ERR_IO_PENDING) {
|
|
return;
|
|
}
|
|
if (rv != net::OK) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rv != net::OK) {
|
|
RunCallbackForRequestIdentifier(ctx->request_identifier, rv);
|
|
return;
|
|
}
|
|
|
|
if (ctx->event_type == brave::kOnBeforeRequest) {
|
|
if (!ctx->new_url_spec.empty() &&
|
|
(ctx->new_url_spec != ctx->request_url.spec()) &&
|
|
IsRequestIdentifierValid(ctx->request_identifier)) {
|
|
*ctx->new_url = GURL(ctx->new_url_spec);
|
|
}
|
|
|
|
if (ctx->ShouldBlockRequest()) {
|
|
RunCallbackForRequestIdentifier(ctx->request_identifier,
|
|
net::ERR_BLOCKED_BY_CLIENT);
|
|
return;
|
|
}
|
|
}
|
|
RunCallbackForRequestIdentifier(ctx->request_identifier, rv);
|
|
}
|