Bug 1615335 - Use SimpleHttpChannel to fetch TRR data r=valentin

Differential Revision: https://phabricator.services.mozilla.com/D63646

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Kershaw Chang 2020-03-04 16:11:16 +00:00
Родитель e2b5968015
Коммит 6fce0d130b
7 изменённых файлов: 202 добавлений и 37 удалений

Просмотреть файл

@ -7366,25 +7366,25 @@
# Single TRR request timeout, in milliseconds # Single TRR request timeout, in milliseconds
- name: network.trr.request_timeout_ms - name: network.trr.request_timeout_ms
type: uint32_t type: RelaxedAtomicUint32
value: 1500 value: 1500
mirror: always mirror: always
# Single TRR request timeout, in milliseconds for mode 3 # Single TRR request timeout, in milliseconds for mode 3
- name: network.trr.request_timeout_mode_trronly_ms - name: network.trr.request_timeout_mode_trronly_ms
type: uint32_t type: RelaxedAtomicUint32
value: 30000 value: 30000
mirror: always mirror: always
# Whether to send the Accept-Language header for TRR requests # Whether to send the Accept-Language header for TRR requests
- name: network.trr.send_accept-language_headers - name: network.trr.send_accept-language_headers
type: bool type: RelaxedAtomicBool
value: false value: false
mirror: always mirror: always
# Whether to send the User-Agent header for TRR requests # Whether to send the User-Agent header for TRR requests
- name: network.trr.send_user-agent_headers - name: network.trr.send_user-agent_headers
type: bool type: RelaxedAtomicBool
value: false value: false
mirror: always mirror: always
@ -7408,6 +7408,12 @@
value: false value: false
mirror: always mirror: always
# This pref controls whether to use SimpleHttpChannel off main thread.
- name: network.trr.fetch_off_main_thread
type: RelaxedAtomicBool
value: false
mirror: always
# Allow the network changed event to get sent when a network topology or setup # Allow the network changed event to get sent when a network topology or setup
# change is noticed while running. # change is noticed while running.
- name: network.notify.changed - name: network.notify.changed

Просмотреть файл

@ -8,6 +8,7 @@
#include "nsCharSeparatedTokenizer.h" #include "nsCharSeparatedTokenizer.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsHostResolver.h" #include "nsHostResolver.h"
#include "nsHttpHandler.h"
#include "nsIHttpChannel.h" #include "nsIHttpChannel.h"
#include "nsIHttpChannelInternal.h" #include "nsIHttpChannelInternal.h"
#include "nsIIOService.h" #include "nsIIOService.h"
@ -28,6 +29,7 @@
#include "mozilla/Logging.h" #include "mozilla/Logging.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_network.h" #include "mozilla/StaticPrefs_network.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/Telemetry.h" #include "mozilla/Telemetry.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "mozilla/Tokenizer.h" #include "mozilla/Tokenizer.h"
@ -156,7 +158,12 @@ nsresult TRR::DohEncode(nsCString& aBody, bool aDisableECS) {
NS_IMETHODIMP NS_IMETHODIMP
TRR::Run() { TRR::Run() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT_IF(gTRRService && StaticPrefs::network_trr_fetch_off_main_thread(),
gTRRService->IsOnTRRThread());
MOZ_ASSERT_IF(
gTRRService && !StaticPrefs::network_trr_fetch_off_main_thread(),
NS_IsMainThread());
if ((gTRRService == nullptr) || NS_FAILED(SendHTTPRequest())) { if ((gTRRService == nullptr) || NS_FAILED(SendHTTPRequest())) {
FailData(NS_ERROR_FAILURE); FailData(NS_ERROR_FAILURE);
// The dtor will now be run // The dtor will now be run
@ -164,9 +171,63 @@ TRR::Run() {
return NS_OK; return NS_OK;
} }
static void InitHttpHandler() {
nsresult rv;
nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
if (NS_FAILED(rv)) {
return;
}
nsCOMPtr<nsIProtocolHandler> handler;
rv = ios->GetProtocolHandler("http", getter_AddRefs(handler));
if (NS_FAILED(rv)) {
return;
}
}
nsresult TRR::CreateChannelHelper(nsIURI* aUri, nsIChannel** aResult) {
*aResult = nullptr;
if (NS_IsMainThread()) {
nsresult rv;
nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
NS_ENSURE_SUCCESS(rv, rv);
return NS_NewChannel(aResult, aUri, nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_OTHER,
nullptr, // nsICookieJarSettings
nullptr, // PerformanceStorage
nullptr, // aLoadGroup
nullptr, // aCallbacks
nsIRequest::LOAD_NORMAL, ios);
}
// Unfortunately, we can only initialize gHttpHandler on main thread.
if (!gHttpHandler) {
nsCOMPtr<nsIEventTarget> main = GetMainThreadEventTarget();
if (main) {
// Forward to the main thread synchronously.
SyncRunnable::DispatchToThread(
main, new SyncRunnable(NS_NewRunnableFunction(
"InitHttpHandler", []() { InitHttpHandler(); })));
}
}
if (!gHttpHandler) {
return NS_ERROR_UNEXPECTED;
}
return gHttpHandler->CreateSimpleHttpChannel(aUri,
nullptr, // givenProxyInfo
0, // proxyResolveFlags
nullptr, // proxyURI
nullptr, // aLoadInfo
aResult);
}
nsresult TRR::SendHTTPRequest() { nsresult TRR::SendHTTPRequest() {
// This is essentially the "run" method - created from nsHostResolver // This is essentially the "run" method - created from nsHostResolver
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
if ((mType != TRRTYPE_A) && (mType != TRRTYPE_AAAA) && if ((mType != TRRTYPE_A) && (mType != TRRTYPE_AAAA) &&
(mType != TRRTYPE_NS) && (mType != TRRTYPE_TXT)) { (mType != TRRTYPE_NS) && (mType != TRRTYPE_TXT)) {
@ -196,14 +257,11 @@ nsresult TRR::SendHTTPRequest() {
} }
} }
nsresult rv;
nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
NS_ENSURE_SUCCESS(rv, rv);
bool useGet = gTRRService->UseGET(); bool useGet = gTRRService->UseGET();
nsAutoCString body; nsAutoCString body;
nsCOMPtr<nsIURI> dnsURI; nsCOMPtr<nsIURI> dnsURI;
bool disableECS = gTRRService->DisableECS(); bool disableECS = gTRRService->DisableECS();
nsresult rv;
LOG(("TRR::SendHTTPRequest resolve %s type %u\n", mHost.get(), mType)); LOG(("TRR::SendHTTPRequest resolve %s type %u\n", mHost.get(), mType));
@ -246,23 +304,20 @@ nsresult TRR::SendHTTPRequest() {
return rv; return rv;
} }
rv = NS_NewChannel(getter_AddRefs(mChannel), dnsURI, rv = CreateChannelHelper(dnsURI, getter_AddRefs(mChannel));
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
nsIContentPolicy::TYPE_OTHER,
nullptr, // nsICookieJarSettings
nullptr, // PerformanceStorage
nullptr, // aLoadGroup
this,
nsIRequest::LOAD_ANONYMOUS | nsIRequest::INHIBIT_CACHING |
nsIRequest::LOAD_BYPASS_CACHE |
nsIChannel::LOAD_BYPASS_URL_CLASSIFIER,
ios);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
LOG(("TRR:SendHTTPRequest: NewChannel failed!\n")); LOG(("TRR:SendHTTPRequest: NewChannel failed!\n"));
return rv; return rv;
} }
mChannel->SetLoadFlags(
nsIRequest::LOAD_ANONYMOUS | nsIRequest::INHIBIT_CACHING |
nsIRequest::LOAD_BYPASS_CACHE | nsIChannel::LOAD_BYPASS_URL_CLASSIFIER);
NS_ENSURE_SUCCESS(rv, rv);
rv = mChannel->SetNotificationCallbacks(this);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel); nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
if (!httpChannel) { if (!httpChannel) {
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
@ -1019,7 +1074,10 @@ nsresult TRR::On200Response(nsIChannel* aChannel) {
mCname.get(), mCnameLoop)); mCname.get(), mCnameLoop));
RefPtr<TRR> trr = RefPtr<TRR> trr =
new TRR(mHostResolver, mRec, mCname, mType, mCnameLoop, mPB); new TRR(mHostResolver, mRec, mCname, mType, mCnameLoop, mPB);
rv = NS_DispatchToMainThread(trr); if (!gTRRService) {
return NS_ERROR_FAILURE;
}
rv = gTRRService->DispatchTRRRequest(trr);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
return rv; return rv;
} }
@ -1188,10 +1246,22 @@ class ProxyCancel : public Runnable {
}; };
void TRR::Cancel() { void TRR::Cancel() {
if (!NS_IsMainThread()) { if (StaticPrefs::network_trr_fetch_off_main_thread()) {
NS_DispatchToMainThread(new ProxyCancel(this)); if (gTRRService) {
return; nsCOMPtr<nsIThread> thread = gTRRService->TRRThread();
if (thread && !thread->IsOnCurrentThread()) {
nsCOMPtr<nsIRunnable> r = new ProxyCancel(this);
thread->Dispatch(r.forget());
return;
}
}
} else {
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(new ProxyCancel(this));
return;
}
} }
if (mChannel) { if (mChannel) {
LOG(("TRR: %p canceling Channel %p %s %d\n", this, mChannel.get(), LOG(("TRR: %p canceling Channel %p %s %d\n", this, mChannel.get(),
mHost.get(), mType)); mHost.get(), mType));

Просмотреть файл

@ -165,6 +165,8 @@ class TRR : public Runnable,
bool UseDefaultServer(); bool UseDefaultServer();
nsresult CreateChannelHelper(nsIURI* aUri, nsIChannel** aResult);
nsCOMPtr<nsIChannel> mChannel; nsCOMPtr<nsIChannel> mChannel;
enum TrrType mType; enum TrrType mType;
TimeStamp mStartTime; TimeStamp mStartTime;

Просмотреть файл

@ -34,6 +34,7 @@ extern mozilla::LazyLogModule gHostResolverLog;
#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args) #define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args)
TRRService* gTRRService = nullptr; TRRService* gTRRService = nullptr;
StaticRefPtr<nsIThread> sTRRBackgroundThread;
NS_IMPL_ISUPPORTS(TRRService, nsIObserver, nsISupportsWeakReference) NS_IMPL_ISUPPORTS(TRRService, nsIObserver, nsISupportsWeakReference)
@ -75,6 +76,7 @@ nsresult TRRService::Init() {
observerService->AddObserver(this, kPurge, true); observerService->AddObserver(this, kPurge, true);
observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true); observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true);
observerService->AddObserver(this, NS_DNS_SUFFIX_LIST_UPDATED_TOPIC, true); observerService->AddObserver(this, NS_DNS_SUFFIX_LIST_UPDATED_TOPIC, true);
observerService->AddObserver(this, "xpcom-shutdown-threads", true);
} }
nsCOMPtr<nsIPrefBranch> prefBranch; nsCOMPtr<nsIPrefBranch> prefBranch;
GetPrefBranch(getter_AddRefs(prefBranch)); GetPrefBranch(getter_AddRefs(prefBranch));
@ -106,6 +108,18 @@ nsresult TRRService::Init() {
nsCOMPtr<nsINetworkLinkService> nls = nsCOMPtr<nsINetworkLinkService> nls =
do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID); do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID);
RebuildSuffixList(nls); RebuildSuffixList(nls);
if (StaticPrefs::network_trr_fetch_off_main_thread()) {
nsCOMPtr<nsIThread> thread;
if (NS_FAILED(
NS_NewNamedThread("TRR Background", getter_AddRefs(thread)))) {
NS_WARNING("NS_NewNamedThread failed!");
return NS_ERROR_FAILURE;
}
sTRRBackgroundThread = thread;
}
LOG(("Initialized TRRService\n")); LOG(("Initialized TRRService\n"));
return NS_OK; return NS_OK;
} }
@ -397,6 +411,49 @@ TRRService::~TRRService() {
gTRRService = nullptr; gTRRService = nullptr;
} }
nsresult TRRService::DispatchTRRRequest(TRR* aTrrRequest) {
return DispatchTRRRequestInternal(aTrrRequest, true);
}
nsresult TRRService::DispatchTRRRequestInternal(TRR* aTrrRequest,
bool aWithLock) {
NS_ENSURE_ARG_POINTER(aTrrRequest);
if (!StaticPrefs::network_trr_fetch_off_main_thread()) {
return NS_DispatchToMainThread(aTrrRequest);
}
RefPtr<TRR> trr = aTrrRequest;
nsCOMPtr<nsIThread> thread = aWithLock ? TRRThread() : TRRThread_locked();
if (!thread) {
return NS_ERROR_FAILURE;
}
return thread->Dispatch(trr.forget());
}
already_AddRefed<nsIThread> TRRService::TRRThread() {
MutexAutoLock lock(mLock);
return TRRThread_locked();
}
already_AddRefed<nsIThread> TRRService::TRRThread_locked() {
RefPtr<nsIThread> thread = sTRRBackgroundThread;
return thread.forget();
}
bool TRRService::IsOnTRRThread() {
nsCOMPtr<nsIThread> thread;
{
MutexAutoLock lock(mLock);
thread = sTRRBackgroundThread;
}
if (!thread) {
return false;
}
return thread->IsOnCurrentThread();
}
NS_IMETHODIMP NS_IMETHODIMP
TRRService::Observe(nsISupports* aSubject, const char* aTopic, TRRService::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) { const char16_t* aData) {
@ -462,6 +519,16 @@ TRRService::Observe(nsISupports* aSubject, const char* aTopic,
nsCOMPtr<nsINetworkLinkService> link = do_QueryInterface(aSubject); nsCOMPtr<nsINetworkLinkService> link = do_QueryInterface(aSubject);
RebuildSuffixList(link); RebuildSuffixList(link);
CheckPlatformDNSStatus(link); CheckPlatformDNSStatus(link);
} else if (!strcmp(aTopic, "xpcom-shutdown-threads")) {
if (sTRRBackgroundThread) {
nsCOMPtr<nsIThread> thread;
{
MutexAutoLock lock(mLock);
thread = sTRRBackgroundThread.get();
sTRRBackgroundThread = nullptr;
}
MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
}
} }
return NS_OK; return NS_OK;
} }
@ -526,7 +593,7 @@ void TRRService::MaybeConfirm_locked() {
mConfirmationNS.get())); mConfirmationNS.get()));
mConfirmer = mConfirmer =
new TRR(this, mConfirmationNS, TRRTYPE_NS, EmptyCString(), false); new TRR(this, mConfirmationNS, TRRTYPE_NS, EmptyCString(), false);
NS_DispatchToMainThread(mConfirmer); DispatchTRRRequestInternal(mConfirmer, false);
} }
} }
@ -563,9 +630,6 @@ bool TRRService::MaybeBootstrap(const nsACString& aPossible,
bool TRRService::IsDomainBlacklisted(const nsACString& aHost, bool TRRService::IsDomainBlacklisted(const nsACString& aHost,
const nsACString& aOriginSuffix, const nsACString& aOriginSuffix,
bool aPrivateBrowsing) { bool aPrivateBrowsing) {
// Only use the Storage API on the main thread
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(), "wrong thread");
if (!Enabled(nsIRequest::TRR_DEFAULT_MODE)) { if (!Enabled(nsIRequest::TRR_DEFAULT_MODE)) {
return true; return true;
} }
@ -576,8 +640,15 @@ bool TRRService::IsDomainBlacklisted(const nsACString& aHost,
// Calling the locking version of this method would cause us to grab // Calling the locking version of this method would cause us to grab
// the mutex for every label of the hostname, which would be very // the mutex for every label of the hostname, which would be very
// inefficient. // inefficient.
if (IsExcludedFromTRR_unlocked(aHost)) { if (NS_IsMainThread()) {
return true; if (IsExcludedFromTRR_unlocked(aHost)) {
return true;
}
} else {
MOZ_ASSERT(IsOnTRRThread());
if (IsExcludedFromTRR(aHost)) {
return true;
}
} }
if (!mTRRBLStorage) { if (!mTRRBLStorage) {
@ -770,7 +841,7 @@ void TRRService::TRRBlacklist(const nsACString& aHost,
// check if there's an NS entry for this name // check if there's an NS entry for this name
RefPtr<TRR> trr = RefPtr<TRR> trr =
new TRR(this, check, TRRTYPE_NS, aOriginSuffix, privateBrowsing); new TRR(this, check, TRRTYPE_NS, aOriginSuffix, privateBrowsing);
NS_DispatchToMainThread(trr); DispatchTRRRequest(trr);
} }
} }
} }
@ -792,7 +863,11 @@ TRRService::Notify(nsITimer* aTimer) {
} }
void TRRService::TRRIsOkay(enum TrrOkay aReason) { void TRRService::TRRIsOkay(enum TrrOkay aReason) {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT_IF(StaticPrefs::network_trr_fetch_off_main_thread(),
IsOnTRRThread());
MOZ_ASSERT_IF(!StaticPrefs::network_trr_fetch_off_main_thread(),
NS_IsMainThread());
Telemetry::AccumulateCategorical( Telemetry::AccumulateCategorical(
aReason == OKAY_NORMAL ? Telemetry::LABELS_DNS_TRR_SUCCESS::Fine aReason == OKAY_NORMAL ? Telemetry::LABELS_DNS_TRR_SUCCESS::Fine
: (aReason == OKAY_TIMEOUT : (aReason == OKAY_TIMEOUT
@ -819,7 +894,10 @@ AHostResolver::LookupStatus TRRService::CompleteLookup(
const nsACString& aOriginSuffix) { const nsACString& aOriginSuffix) {
// this is an NS check for the TRR blacklist or confirmationNS check // this is an NS check for the TRR blacklist or confirmationNS check
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT_IF(StaticPrefs::network_trr_fetch_off_main_thread(),
IsOnTRRThread());
MOZ_ASSERT_IF(!StaticPrefs::network_trr_fetch_off_main_thread(),
NS_IsMainThread());
MOZ_ASSERT(!rec); MOZ_ASSERT(!rec);
RefPtr<AddrInfo> newRRSet(aNewRRSet); RefPtr<AddrInfo> newRRSet(aNewRRSet);

Просмотреть файл

@ -67,6 +67,10 @@ class TRRService : public nsIObserver,
void TRRIsOkay(enum TrrOkay aReason); void TRRIsOkay(enum TrrOkay aReason);
bool ParentalControlEnabled() const { return mParentalControlEnabled; } bool ParentalControlEnabled() const { return mParentalControlEnabled; }
nsresult DispatchTRRRequest(TRR* aTrrRequest);
already_AddRefed<nsIThread> TRRThread();
bool IsOnTRRThread();
private: private:
virtual ~TRRService(); virtual ~TRRService();
nsresult ReadPrefs(const char* name); nsresult ReadPrefs(const char* name);
@ -84,6 +88,9 @@ class TRRService : public nsIObserver,
void RebuildSuffixList(nsINetworkLinkService* aLinkService); void RebuildSuffixList(nsINetworkLinkService* aLinkService);
void CheckPlatformDNSStatus(nsINetworkLinkService* aLinkService); void CheckPlatformDNSStatus(nsINetworkLinkService* aLinkService);
nsresult DispatchTRRRequestInternal(TRR* aTrrRequest, bool aWithLock);
already_AddRefed<nsIThread> TRRThread_locked();
bool mInitialized; bool mInitialized;
Atomic<uint32_t, Relaxed> mMode; Atomic<uint32_t, Relaxed> mMode;
Atomic<uint32_t, Relaxed> mTRRBlacklistExpireTime; Atomic<uint32_t, Relaxed> mTRRBlacklistExpireTime;

Просмотреть файл

@ -82,6 +82,7 @@ GeneratedFile('etld_data.inc', script='prepare_tlds.py',
# need to include etld_data.inc # need to include etld_data.inc
LOCAL_INCLUDES += [ LOCAL_INCLUDES += [
'/netwerk/base', '/netwerk/base',
'/netwerk/protocol/http',
] ]
USE_LIBS += ['icu'] USE_LIBS += ['icu']

Просмотреть файл

@ -1272,7 +1272,7 @@ nsresult nsHostResolver::TrrLookup(nsHostRecord* aRec, TRR* pushedTRR) {
RefPtr<TRR> trr; RefPtr<TRR> trr;
MutexAutoLock trrlock(addrRec->mTrrLock); MutexAutoLock trrlock(addrRec->mTrrLock);
trr = pushedTRR ? pushedTRR : new TRR(this, rec, rectype); trr = pushedTRR ? pushedTRR : new TRR(this, rec, rectype);
if (pushedTRR || NS_SUCCEEDED(NS_DispatchToMainThread(trr))) { if (pushedTRR || NS_SUCCEEDED(gTRRService->DispatchTRRRequest(trr))) {
addrRec->mResolving++; addrRec->mResolving++;
if (rectype == TRRTYPE_A) { if (rectype == TRRTYPE_A) {
MOZ_ASSERT(!addrRec->mTrrA); MOZ_ASSERT(!addrRec->mTrrA);
@ -1305,7 +1305,8 @@ nsresult nsHostResolver::TrrLookup(nsHostRecord* aRec, TRR* pushedTRR) {
RefPtr<TRR> trr; RefPtr<TRR> trr;
MutexAutoLock trrlock(typeRec->mTrrLock); MutexAutoLock trrlock(typeRec->mTrrLock);
trr = pushedTRR ? pushedTRR : new TRR(this, rec, rectype); trr = pushedTRR ? pushedTRR : new TRR(this, rec, rectype);
if (pushedTRR || NS_SUCCEEDED(NS_DispatchToMainThread(trr))) { RefPtr<TRR> trrRequest = trr;
if (pushedTRR || NS_SUCCEEDED(gTRRService->DispatchTRRRequest(trr))) {
typeRec->mResolving++; typeRec->mResolving++;
MOZ_ASSERT(!typeRec->mTrr); MOZ_ASSERT(!typeRec->mTrr);
typeRec->mTrr = trr; typeRec->mTrr = trr;