зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1815741 - implement DNS-over-Oblivious-HTTP r=valentin,necko-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D169218
This commit is contained in:
Родитель
47428da2d3
Коммит
66f11ff04c
|
@ -11967,6 +11967,24 @@
|
|||
value: "canary"
|
||||
mirror: never
|
||||
|
||||
# Use Oblivious HTTP when making TRR requests.
|
||||
- name: network.trr.use_ohttp
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
# Oblivious HTTP relay URI for TRR requests.
|
||||
- name: network.trr.ohttp.relay_uri
|
||||
type: String
|
||||
value: ""
|
||||
mirror: never
|
||||
|
||||
# URI from which to fetch the configuration for the Oblivious HTTP gateway for TRR requests.
|
||||
- name: network.trr.ohttp.config_uri
|
||||
type: String
|
||||
value: ""
|
||||
mirror: never
|
||||
|
||||
# Allow the network changed event to get sent when a network topology or setup
|
||||
# change is noticed while running.
|
||||
- name: network.notify.changed
|
||||
|
|
|
@ -269,7 +269,7 @@ nsresult ODoHService::UpdateODoHConfigFromURI() {
|
|||
return rv;
|
||||
}
|
||||
|
||||
channel->SetLoadFlags(
|
||||
rv = channel->SetLoadFlags(
|
||||
nsIRequest::LOAD_ANONYMOUS | nsIRequest::INHIBIT_CACHING |
|
||||
nsIRequest::LOAD_BYPASS_CACHE | nsIChannel::LOAD_BYPASS_URL_CLASSIFIER);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIObliviousHttp.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsITimedChannel.h"
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "nsURLHelper.h"
|
||||
#include "ODoH.h"
|
||||
#include "ObliviousHttpChannel.h"
|
||||
#include "TRR.h"
|
||||
#include "TRRService.h"
|
||||
#include "TRRServiceChannel.h"
|
||||
|
@ -261,7 +263,27 @@ nsresult TRR::SendHTTPRequest() {
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = DNSUtils::CreateChannelHelper(dnsURI, getter_AddRefs(channel));
|
||||
bool useOHTTP = StaticPrefs::network_trr_use_ohttp();
|
||||
if (useOHTTP) {
|
||||
nsCOMPtr<nsIObliviousHttpService> ohttpService(
|
||||
do_GetService("@mozilla.org/network/oblivious-http-service;1"));
|
||||
if (!ohttpService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsIURI> relayURI;
|
||||
nsTArray<uint8_t> encodedConfig;
|
||||
rv = ohttpService->GetTRRSettings(getter_AddRefs(relayURI), encodedConfig);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
if (!relayURI) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = ohttpService->NewChannel(relayURI, dnsURI, encodedConfig,
|
||||
getter_AddRefs(channel));
|
||||
} else {
|
||||
rv = DNSUtils::CreateChannelHelper(dnsURI, getter_AddRefs(channel));
|
||||
}
|
||||
if (NS_FAILED(rv) || !channel) {
|
||||
LOG(("TRR:SendHTTPRequest: NewChannel failed!\n"));
|
||||
return rv;
|
||||
|
@ -1040,8 +1062,17 @@ TRR::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aInputStream,
|
|||
}
|
||||
|
||||
void TRR::Cancel(nsresult aStatus) {
|
||||
RefPtr<TRRServiceChannel> trrServiceChannel = do_QueryObject(mChannel);
|
||||
if (trrServiceChannel && !XRE_IsSocketProcess()) {
|
||||
bool isTRRServiceChannel = false;
|
||||
nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(
|
||||
do_QueryInterface(mChannel));
|
||||
if (httpChannelInternal) {
|
||||
nsresult rv =
|
||||
httpChannelInternal->GetIsTRRServiceChannel(&isTRRServiceChannel);
|
||||
if (NS_FAILED(rv)) {
|
||||
isTRRServiceChannel = false;
|
||||
}
|
||||
}
|
||||
if (isTRRServiceChannel && !XRE_IsSocketProcess()) {
|
||||
if (TRRService::Get()) {
|
||||
nsCOMPtr<nsIThread> thread = TRRService::Get()->TRRThread();
|
||||
if (thread && !thread->IsOnCurrentThread()) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "nsDNSPrefetch.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIProtocolProxyService.h"
|
||||
#include "nsIObliviousHttp.h"
|
||||
#include "prsystem.h"
|
||||
#include "prnetdb.h"
|
||||
#include "prmon.h"
|
||||
|
@ -879,6 +880,9 @@ nsDNSService::Init() {
|
|||
|
||||
RegisterWeakMemoryReporter(this);
|
||||
|
||||
nsCOMPtr<nsIObliviousHttpService> ohttpService(
|
||||
do_GetService("@mozilla.org/network/oblivious-http-service;1"));
|
||||
|
||||
mTrrService = new TRRService();
|
||||
if (NS_FAILED(mTrrService->Init())) {
|
||||
mTrrService = nullptr;
|
||||
|
|
|
@ -16,18 +16,23 @@
|
|||
|
||||
namespace mozilla::net {
|
||||
|
||||
NS_IMPL_ISUPPORTS(ObliviousHttpChannel, nsIHttpChannel, nsIIdentChannel,
|
||||
nsIChannel, nsIRequest, nsIRequestObserver, nsIStreamListener,
|
||||
nsIUploadChannel2)
|
||||
NS_IMPL_ISUPPORTS(ObliviousHttpChannel, nsIChannel, nsIHttpChannel,
|
||||
nsIHttpChannelInternal, nsIIdentChannel, nsIRequest,
|
||||
nsIRequestObserver, nsIStreamListener, nsIUploadChannel2,
|
||||
nsITimedChannel)
|
||||
|
||||
ObliviousHttpChannel::ObliviousHttpChannel(
|
||||
nsIURI* targetURI, const nsTArray<uint8_t>& encodedConfig,
|
||||
nsIHttpChannel* innerChannel)
|
||||
: mTargetURI(targetURI),
|
||||
mEncodedConfig(encodedConfig.Clone()),
|
||||
mInnerChannel(innerChannel) {
|
||||
mInnerChannel(innerChannel),
|
||||
mInnerChannelInternal(do_QueryInterface(innerChannel)),
|
||||
mInnerChannelTimed(do_QueryInterface(innerChannel)) {
|
||||
LOG(("ObliviousHttpChannel ctor [this=%p]", this));
|
||||
MOZ_ASSERT(mInnerChannel);
|
||||
MOZ_ASSERT(mInnerChannelInternal);
|
||||
MOZ_ASSERT(mInnerChannelTimed);
|
||||
}
|
||||
|
||||
ObliviousHttpChannel::~ObliviousHttpChannel() {
|
||||
|
@ -60,17 +65,17 @@ ObliviousHttpChannel::SetTopBrowsingContextId(uint64_t aId) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::GetTransferSize(uint64_t* aTransferSize) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
return mInnerChannel->GetTransferSize(aTransferSize);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::GetRequestSize(uint64_t* aRequestSize) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
return mInnerChannel->GetRequestSize(aRequestSize);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::GetDecodedBodySize(uint64_t* aDecodedBodySize) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
return mInnerChannel->GetDecodedBodySize(aDecodedBodySize);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -198,6 +203,8 @@ ObliviousHttpChannel::GetResponseStatus(uint32_t* aResponseStatus) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::GetResponseStatusText(nsACString& aResponseStatusText) {
|
||||
LOG(("ObliviousHttpChannel::GetResponseStatusText NOT IMPLEMENTED [this=%p]",
|
||||
this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
@ -252,6 +259,8 @@ ObliviousHttpChannel::GetResponseHeader(const nsACString& header,
|
|||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::SetResponseHeader(const nsACString& header,
|
||||
const nsACString& value, bool merge) {
|
||||
LOG(("ObliviousHttpChannel::SetResponseHeader NOT IMPLEMENTED [this=%p]",
|
||||
this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
@ -290,37 +299,56 @@ ObliviousHttpChannel::GetOriginalResponseHeader(
|
|||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::VisitOriginalResponseHeaders(
|
||||
nsIHttpHeaderVisitor* aVisitor) {
|
||||
LOG(
|
||||
("ObliviousHttpChannel::VisitOriginalResponseHeaders NOT IMPLEMENTED "
|
||||
"[this=%p]",
|
||||
this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::ShouldStripRequestBodyHeader(const nsACString& aMethod,
|
||||
bool* aResult) {
|
||||
LOG(
|
||||
("ObliviousHttpChannel::ShouldStripRequestBodyHeader NOT IMPLEMENTED "
|
||||
"[this=%p]",
|
||||
this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::IsNoStoreResponse(bool* _retval) {
|
||||
LOG(("ObliviousHttpChannel::IsNoStoreResponse NOT IMPLEMENTED [this=%p]",
|
||||
this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::IsNoCacheResponse(bool* _retval) {
|
||||
LOG(("ObliviousHttpChannel::IsNoCacheResponse NOT IMPLEMENTED [this=%p]",
|
||||
this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::IsPrivateResponse(bool* _retval) {
|
||||
LOG(("ObliviousHttpChannel::IsPrivateResponse NOT IMPLEMENTED [this=%p]",
|
||||
this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::RedirectTo(nsIURI* aNewURI) {
|
||||
LOG(("ObliviousHttpChannel::RedirectTo NOT IMPLEMENTED [this=%p]", this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::UpgradeToSecure() { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
ObliviousHttpChannel::UpgradeToSecure() {
|
||||
LOG(("ObliviousHttpChannel::UpgradeToSecure NOT IMPLEMENTED [this=%p]",
|
||||
this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::GetRequestContextID(uint64_t* _retval) {
|
||||
|
@ -339,6 +367,8 @@ ObliviousHttpChannel::GetProtocolVersion(nsACString& aProtocolVersion) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::GetEncodedBodySize(uint64_t* aEncodedBodySize) {
|
||||
LOG(("ObliviousHttpChannel::GetEncodedBodySize NOT IMPLEMENTED [this=%p]",
|
||||
this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
@ -358,9 +388,55 @@ ObliviousHttpChannel::LogMimeTypeMismatch(const nsACString& aMessageName,
|
|||
|
||||
void ObliviousHttpChannel::SetSource(
|
||||
mozilla::UniquePtr<mozilla::ProfileChunkedBuffer> aSource) {
|
||||
LOG(("ObliviousHttpChannel::SetSource NOT IMPLEMENTED [this=%p]", this));
|
||||
// NS_ERROR_NOT_IMPLEMENTED
|
||||
}
|
||||
|
||||
void ObliviousHttpChannel::SetConnectionInfo(nsHttpConnectionInfo* aCi) {
|
||||
if (mInnerChannelInternal) {
|
||||
mInnerChannelInternal->SetConnectionInfo(aCi);
|
||||
}
|
||||
}
|
||||
|
||||
void ObliviousHttpChannel::DoDiagnosticAssertWhenOnStopNotCalledOnDestroy() {
|
||||
if (mInnerChannelInternal) {
|
||||
mInnerChannelInternal->DoDiagnosticAssertWhenOnStopNotCalledOnDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
void ObliviousHttpChannel::SetIPv6Disabled() {
|
||||
if (mInnerChannelInternal) {
|
||||
mInnerChannelInternal->SetIPv6Disabled();
|
||||
}
|
||||
}
|
||||
|
||||
void ObliviousHttpChannel::SetIPv4Disabled() {
|
||||
if (mInnerChannelInternal) {
|
||||
mInnerChannelInternal->SetIPv4Disabled();
|
||||
}
|
||||
}
|
||||
|
||||
void ObliviousHttpChannel::DisableAltDataCache() {
|
||||
if (mInnerChannelInternal) {
|
||||
mInnerChannelInternal->DisableAltDataCache();
|
||||
}
|
||||
}
|
||||
|
||||
void ObliviousHttpChannel::SetAltDataForChild(bool aIsForChild) {
|
||||
if (mInnerChannelInternal) {
|
||||
mInnerChannelInternal->SetAltDataForChild(aIsForChild);
|
||||
}
|
||||
}
|
||||
|
||||
void ObliviousHttpChannel::SetCorsPreflightParameters(
|
||||
nsTArray<nsTString<char>> const& aUnsafeHeaders,
|
||||
bool aShouldStripRequestBodyHeader) {
|
||||
if (mInnerChannelInternal) {
|
||||
mInnerChannelInternal->SetCorsPreflightParameters(
|
||||
aUnsafeHeaders, aShouldStripRequestBodyHeader);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ObliviousHttpChannel::nsIChannel
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -411,7 +487,7 @@ ObliviousHttpChannel::GetSecurityInfo(
|
|||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::GetContentType(nsACString& aContentType) {
|
||||
return mInnerChannel->GetContentType(aContentType);
|
||||
return GetResponseHeader("content-type"_ns, aContentType);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -441,6 +517,7 @@ ObliviousHttpChannel::SetContentLength(int64_t aContentLength) {
|
|||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::Open(nsIInputStream** aStream) {
|
||||
LOG(("ObliviousHttpChannel::Open NOT IMPLEMENTED [this=%p]", this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
@ -459,6 +536,9 @@ ObliviousHttpChannel::AsyncOpen(nsIStreamListener* aListener) {
|
|||
return rv;
|
||||
}
|
||||
nsAutoCString scheme;
|
||||
if (!mTargetURI) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
rv = mTargetURI->GetScheme(scheme);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
|
@ -615,15 +695,13 @@ NS_IMETHODIMP
|
|||
ObliviousHttpChannel::OnStartRequest(nsIRequest* aRequest) {
|
||||
LOG(("ObliviousHttpChannel::OnStartRequest [this=%p, request=%p]", this,
|
||||
aRequest));
|
||||
return mStreamListener->OnStartRequest(aRequest);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::OnStopRequest(nsIRequest* aRequest,
|
||||
nsresult aStatusCode) {
|
||||
LOG(("ObliviousHttpChannel::OnStopRequest [this=%p, request=%p, status=%u]",
|
||||
this, aRequest, (uint32_t)aStatusCode));
|
||||
|
||||
nsresult ObliviousHttpChannel::ProcessOnStopRequest() {
|
||||
if (mRawResponse.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsCOMPtr<nsIObliviousHttp> obliviousHttp(
|
||||
do_GetService("@mozilla.org/network/oblivious-http;1"));
|
||||
if (!obliviousHttp) {
|
||||
|
@ -644,39 +722,57 @@ ObliviousHttpChannel::OnStopRequest(nsIRequest* aRequest,
|
|||
if (!bhttp) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = bhttp->DecodeResponse(decapsulated, getter_AddRefs(mBinaryHttpResponse));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
return bhttp->DecodeResponse(decapsulated,
|
||||
getter_AddRefs(mBinaryHttpResponse));
|
||||
}
|
||||
|
||||
void ObliviousHttpChannel::EmitOnDataAvailable() {
|
||||
if (!mBinaryHttpResponse) {
|
||||
return;
|
||||
}
|
||||
nsTArray<uint8_t> content;
|
||||
rv = mBinaryHttpResponse->GetContent(content);
|
||||
nsresult rv = mBinaryHttpResponse->GetContent(content);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
return;
|
||||
}
|
||||
if (content.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (content.Length() > std::numeric_limits<uint32_t>::max()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return;
|
||||
}
|
||||
uint32_t contentLength = (uint32_t)content.Length();
|
||||
if (contentLength > 0) {
|
||||
nsCOMPtr<nsIInputStream> contentStream;
|
||||
rv = NS_NewByteInputStream(getter_AddRefs(contentStream),
|
||||
std::move(content));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = mStreamListener->OnDataAvailable(aRequest, contentStream, 0,
|
||||
contentLength);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
rv = mStreamListener->OnStopRequest(aRequest, aStatusCode);
|
||||
nsCOMPtr<nsIInputStream> contentStream;
|
||||
rv = NS_NewByteInputStream(getter_AddRefs(contentStream), std::move(content));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
return;
|
||||
}
|
||||
mInnerChannel = nullptr;
|
||||
mEncapsulatedRequest = nullptr;
|
||||
mStreamListener = nullptr;
|
||||
rv = mStreamListener->OnDataAvailable(this, contentStream, 0, contentLength);
|
||||
Unused << rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpChannel::OnStopRequest(nsIRequest* aRequest,
|
||||
nsresult aStatusCode) {
|
||||
LOG(("ObliviousHttpChannel::OnStopRequest [this=%p, request=%p, status=%u]",
|
||||
this, aRequest, (uint32_t)aStatusCode));
|
||||
|
||||
auto releaseStreamListener = MakeScopeExit(
|
||||
[self = RefPtr{this}]() mutable { self->mStreamListener = nullptr; });
|
||||
|
||||
if (NS_SUCCEEDED(aStatusCode)) {
|
||||
bool requestSucceeded;
|
||||
nsresult rv = mInnerChannel->GetRequestSucceeded(&requestSucceeded);
|
||||
if (NS_SUCCEEDED(rv) && requestSucceeded) {
|
||||
aStatusCode = ProcessOnStopRequest();
|
||||
}
|
||||
}
|
||||
Unused << mStreamListener->OnStartRequest(this);
|
||||
if (NS_SUCCEEDED(aStatusCode)) {
|
||||
EmitOnDataAvailable();
|
||||
}
|
||||
Unused << mStreamListener->OnStopRequest(this, aStatusCode);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -687,6 +783,10 @@ ObliviousHttpChannel::OnStopRequest(nsIRequest* aRequest,
|
|||
NS_IMETHODIMP ObliviousHttpChannel::ExplicitSetUploadStream(
|
||||
nsIInputStream* aStream, const nsACString& aContentType,
|
||||
int64_t aContentLength, const nsACString& aMethod, bool aStreamHasHeaders) {
|
||||
// This function should only be called before AsyncOpen.
|
||||
if (mStreamListener) {
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
}
|
||||
if (aMethod != "POST"_ns || aStreamHasHeaders) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
@ -726,6 +826,8 @@ NS_IMETHODIMP ObliviousHttpChannel::GetUploadStreamHasHeaders(
|
|||
|
||||
NS_IMETHODIMP ObliviousHttpChannel::CloneUploadStream(
|
||||
int64_t* aContentLength, nsIInputStream** _retval) {
|
||||
LOG(("ObliviousHttpChannel::CloneUploadStream NOT IMPLEMENTED [this=%p]",
|
||||
this));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,16 +10,20 @@
|
|||
|
||||
#include "nsIBinaryHttp.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIObliviousHttp.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsITimedChannel.h"
|
||||
#include "nsIUploadChannel2.h"
|
||||
#include "nsTHashMap.h"
|
||||
|
||||
namespace mozilla::net {
|
||||
|
||||
class ObliviousHttpChannel final : public nsIHttpChannel,
|
||||
public nsIHttpChannelInternal,
|
||||
public nsIStreamListener,
|
||||
public nsIUploadChannel2 {
|
||||
public nsIUploadChannel2,
|
||||
public nsITimedChannel {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSICHANNEL
|
||||
|
@ -32,12 +36,17 @@ class ObliviousHttpChannel final : public nsIHttpChannel,
|
|||
const nsTArray<uint8_t>& encodedConfig,
|
||||
nsIHttpChannel* innerChannel);
|
||||
|
||||
NS_FORWARD_NSIREQUEST(mInnerChannel->)
|
||||
NS_FORWARD_NSIIDENTCHANNEL(mInnerChannel->)
|
||||
NS_FORWARD_SAFE_NSIREQUEST(mInnerChannel)
|
||||
NS_FORWARD_SAFE_NSIIDENTCHANNEL(mInnerChannel)
|
||||
NS_FORWARD_SAFE_NSIHTTPCHANNELINTERNAL(mInnerChannelInternal)
|
||||
NS_FORWARD_SAFE_NSITIMEDCHANNEL(mInnerChannelTimed)
|
||||
|
||||
protected:
|
||||
~ObliviousHttpChannel();
|
||||
|
||||
nsresult ProcessOnStopRequest();
|
||||
void EmitOnDataAvailable();
|
||||
|
||||
nsCOMPtr<nsIURI> mTargetURI;
|
||||
nsTArray<uint8_t> mEncodedConfig;
|
||||
|
||||
|
@ -46,6 +55,8 @@ class ObliviousHttpChannel final : public nsIHttpChannel,
|
|||
nsTArray<uint8_t> mContent;
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> mInnerChannel;
|
||||
nsCOMPtr<nsIHttpChannelInternal> mInnerChannelInternal;
|
||||
nsCOMPtr<nsITimedChannel> mInnerChannelTimed;
|
||||
nsCOMPtr<nsIObliviousHttpClientRequest> mEncapsulatedRequest;
|
||||
nsTArray<uint8_t> mRawResponse;
|
||||
nsCOMPtr<nsIBinaryHttpResponse> mBinaryHttpResponse;
|
||||
|
|
|
@ -9,10 +9,91 @@
|
|||
|
||||
#include "DNSUtils.h"
|
||||
#include "ObliviousHttpChannel.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
namespace mozilla::net {
|
||||
|
||||
NS_IMPL_ISUPPORTS(ObliviousHttpService, nsIObliviousHttpService)
|
||||
NS_IMPL_ISUPPORTS(ObliviousHttpService, nsIObliviousHttpService, nsIObserver,
|
||||
nsIStreamLoaderObserver)
|
||||
|
||||
ObliviousHttpService::ObliviousHttpService()
|
||||
: mTRRConfig(ObliviousHttpConfig(), "ObliviousHttpService::mTRRConfig") {
|
||||
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||||
if (prefBranch) {
|
||||
prefBranch->AddObserver("network.trr.ohttp", this, false);
|
||||
}
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReadPrefs("*"_ns);
|
||||
}
|
||||
|
||||
void ObliviousHttpService::ReadPrefs(const nsACString& whichPref) {
|
||||
nsAutoCString relayURIPref("network.trr.ohttp.relay_uri");
|
||||
if (whichPref.Equals(relayURIPref) || whichPref.EqualsLiteral("*")) {
|
||||
nsAutoCString relayURIString;
|
||||
nsresult rv = Preferences::GetCString(relayURIPref.get(), relayURIString);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIURI> relayURI;
|
||||
rv = NS_NewURI(getter_AddRefs(relayURI), relayURIString);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
auto trrConfig = mTRRConfig.Lock();
|
||||
trrConfig->mRelayURI = relayURI;
|
||||
}
|
||||
|
||||
nsAutoCString configURIPref("network.trr.ohttp.config_uri");
|
||||
if (whichPref.Equals(configURIPref) || whichPref.EqualsLiteral("*")) {
|
||||
nsAutoCString configURIString;
|
||||
nsresult rv = Preferences::GetCString(configURIPref.get(), configURIString);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIURI> configURI;
|
||||
rv = NS_NewURI(getter_AddRefs(configURI), configURIString);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = DNSUtils::CreateChannelHelper(configURI, getter_AddRefs(channel));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
rv = channel->SetLoadFlags(
|
||||
nsIRequest::LOAD_ANONYMOUS | nsIRequest::INHIBIT_CACHING |
|
||||
nsIRequest::LOAD_BYPASS_CACHE | nsIChannel::LOAD_BYPASS_URL_CLASSIFIER);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
|
||||
if (!httpChannel) {
|
||||
return;
|
||||
}
|
||||
// This connection should not use TRR
|
||||
rv = httpChannel->SetTRRMode(nsIRequest::TRR_DISABLED_MODE);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIStreamLoader> loader;
|
||||
rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
rv = httpChannel->AsyncOpen(loader);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
auto trrConfig = mTRRConfig.Lock();
|
||||
trrConfig->mEncodedConfig.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// nsIObliviousHttpService
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpService::NewChannel(nsIURI* relayURI, nsIURI* targetURI,
|
||||
|
@ -34,4 +115,51 @@ ObliviousHttpService::NewChannel(nsIURI* relayURI, nsIURI* targetURI,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpService::GetTRRSettings(nsIURI** relayURI,
|
||||
nsTArray<uint8_t>& encodedConfig) {
|
||||
auto trrConfig = mTRRConfig.Lock();
|
||||
*relayURI = do_AddRef(trrConfig->mRelayURI).take();
|
||||
encodedConfig.Assign(trrConfig->mEncodedConfig.Clone());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIObserver
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpService::Observe(nsISupports* subject, const char* topic,
|
||||
const char16_t* data) {
|
||||
if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
|
||||
ReadPrefs(NS_ConvertUTF16toUTF8(data));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIStreamLoaderObserver
|
||||
|
||||
NS_IMETHODIMP
|
||||
ObliviousHttpService::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
nsISupports* aContext, nsresult aStatus,
|
||||
uint32_t aLength,
|
||||
const uint8_t* aContent) {
|
||||
if (NS_SUCCEEDED(aStatus)) {
|
||||
auto trrConfig = mTRRConfig.Lock();
|
||||
trrConfig->mEncodedConfig.Clear();
|
||||
trrConfig->mEncodedConfig.AppendElements(aContent, aLength);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService(
|
||||
mozilla::services::GetObserverService());
|
||||
if (!observerService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv = observerService->NotifyObservers(
|
||||
nullptr, "ohttp-service-config-loaded", nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
||||
|
|
|
@ -8,17 +8,36 @@
|
|||
#ifndef mozilla_net_ObliviousHttpService_h
|
||||
#define mozilla_net_ObliviousHttpService_h
|
||||
|
||||
#include "mozilla/DataMutex.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIObliviousHttp.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIStreamLoader.h"
|
||||
|
||||
namespace mozilla::net {
|
||||
|
||||
class ObliviousHttpService final : public nsIObliviousHttpService {
|
||||
class ObliviousHttpConfig {
|
||||
public:
|
||||
nsCOMPtr<nsIURI> mRelayURI;
|
||||
nsTArray<uint8_t> mEncodedConfig;
|
||||
};
|
||||
|
||||
class ObliviousHttpService final : public nsIObliviousHttpService,
|
||||
nsIObserver,
|
||||
nsIStreamLoaderObserver {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOBLIVIOUSHTTPSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSISTREAMLOADEROBSERVER
|
||||
|
||||
ObliviousHttpService();
|
||||
|
||||
private:
|
||||
~ObliviousHttpService() = default;
|
||||
void ReadPrefs(const nsACString& whichPref);
|
||||
|
||||
DataMutex<ObliviousHttpConfig> mTRRConfig;
|
||||
};
|
||||
|
||||
} // namespace mozilla::net
|
||||
|
|
|
@ -83,6 +83,7 @@ NS_INTERFACE_MAP_BEGIN(TRRServiceChannel)
|
|||
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDNSListener)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
|
||||
NS_INTERFACE_MAP_ENTRY_CONCRETE(TRRServiceChannel)
|
||||
NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
|
||||
|
||||
|
|
|
@ -70,4 +70,6 @@ interface nsIObliviousHttp : nsISupports
|
|||
interface nsIObliviousHttpService : nsISupports
|
||||
{
|
||||
nsIChannel newChannel(in nsIURI relayURI, in nsIURI targetURI, in Array<octet> encodedConfig);
|
||||
|
||||
void getTRRSettings(out nsIURI relayURI, out Array<octet> encodedConfig);
|
||||
};
|
||||
|
|
|
@ -473,6 +473,10 @@ BinaryHttpResponse.prototype = {
|
|||
QueryInterface: ChromeUtils.generateQI(["nsIBinaryHttpResponse"]),
|
||||
};
|
||||
|
||||
function bytesToString(bytes) {
|
||||
return String.fromCharCode.apply(null, bytes);
|
||||
}
|
||||
|
||||
function check_http_info(request, expected_httpVersion, expected_proxy) {
|
||||
let httpVersion = "";
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from trr_common.js */
|
||||
|
||||
Cu.importGlobalProperties(["fetch"]);
|
||||
|
||||
const { setTimeout } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/Timer.sys.mjs"
|
||||
);
|
||||
|
||||
let httpServer;
|
||||
let ohttpServer;
|
||||
let ohttpEncodedConfig = "not a valid config";
|
||||
|
||||
// Decapsulate the request, send it to the actual TRR, receive the response,
|
||||
// encapsulate it, and send it back through `response`.
|
||||
async function forwardToTRR(request, response) {
|
||||
let inputStream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
|
||||
Ci.nsIScriptableInputStream
|
||||
);
|
||||
inputStream.init(request.bodyInputStream);
|
||||
let requestBody = inputStream.readBytes(inputStream.available());
|
||||
let ohttpResponse = ohttpServer.decapsulate(stringToBytes(requestBody));
|
||||
let bhttp = Cc["@mozilla.org/network/binary-http;1"].getService(
|
||||
Ci.nsIBinaryHttp
|
||||
);
|
||||
let decodedRequest = bhttp.decodeRequest(ohttpResponse.request);
|
||||
let headers = {};
|
||||
for (
|
||||
let i = 0;
|
||||
i < decodedRequest.headerNames.length && decodedRequest.headerValues.length;
|
||||
i++
|
||||
) {
|
||||
headers[decodedRequest.headerNames[i]] = decodedRequest.headerValues[i];
|
||||
}
|
||||
let uri = `${decodedRequest.scheme}://${decodedRequest.authority}${decodedRequest.path}`;
|
||||
let body = new Uint8Array(decodedRequest.content.length);
|
||||
for (let i = 0; i < decodedRequest.content.length; i++) {
|
||||
body[i] = decodedRequest.content[i];
|
||||
}
|
||||
try {
|
||||
// Timeout after 10 seconds.
|
||||
let fetchInProgress = true;
|
||||
let controller = new AbortController();
|
||||
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||
setTimeout(() => {
|
||||
if (fetchInProgress) {
|
||||
controller.abort();
|
||||
}
|
||||
}, 10000);
|
||||
let trrResponse = await fetch(uri, {
|
||||
method: decodedRequest.method,
|
||||
headers,
|
||||
body: decodedRequest.method == "POST" ? body : undefined,
|
||||
credentials: "omit",
|
||||
signal: controller.signal,
|
||||
});
|
||||
fetchInProgress = false;
|
||||
let data = new Uint8Array(await trrResponse.arrayBuffer());
|
||||
let trrResponseContent = [];
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
trrResponseContent.push(data[i]);
|
||||
}
|
||||
let trrResponseHeaderNames = [];
|
||||
let trrResponseHeaderValues = [];
|
||||
for (let header of trrResponse.headers) {
|
||||
trrResponseHeaderNames.push(header[0]);
|
||||
trrResponseHeaderValues.push(header[1]);
|
||||
}
|
||||
let binaryResponse = new BinaryHttpResponse(
|
||||
trrResponse.status,
|
||||
trrResponseHeaderNames,
|
||||
trrResponseHeaderValues,
|
||||
trrResponseContent
|
||||
);
|
||||
let responseBytes = bhttp.encodeResponse(binaryResponse);
|
||||
let encResponse = ohttpResponse.encapsulate(responseBytes);
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "message/ohttp-res", false);
|
||||
response.write(bytesToString(encResponse));
|
||||
} catch (e) {
|
||||
// Some tests involve the responder either timing out or closing the
|
||||
// connection unexpectedly.
|
||||
}
|
||||
}
|
||||
|
||||
add_setup(async function setup() {
|
||||
h2Port = trr_test_setup();
|
||||
|
||||
if (mozinfo.socketprocess_networking) {
|
||||
Services.dns; // Needed to trigger socket process.
|
||||
await TestUtils.waitForCondition(() => Services.io.socketProcessLaunched);
|
||||
}
|
||||
|
||||
Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRONLY);
|
||||
|
||||
let ohttp = Cc["@mozilla.org/network/oblivious-http;1"].getService(
|
||||
Ci.nsIObliviousHttp
|
||||
);
|
||||
ohttpServer = ohttp.server();
|
||||
|
||||
httpServer = new HttpServer();
|
||||
httpServer.registerPathHandler("/relay", function(request, response) {
|
||||
response.processAsync();
|
||||
forwardToTRR(request, response).then(() => {
|
||||
response.finish();
|
||||
});
|
||||
});
|
||||
httpServer.registerPathHandler("/config", function(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.setHeader("Content-Type", "application/ohttp-keys", false);
|
||||
response.write(ohttpEncodedConfig);
|
||||
});
|
||||
httpServer.start(-1);
|
||||
|
||||
Services.prefs.setBoolPref("network.trr.use_ohttp", true);
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
trr_clear_prefs();
|
||||
Services.prefs.clearUserPref("network.trr.use_ohttp");
|
||||
Services.prefs.clearUserPref("network.trr.ohttp.config_uri");
|
||||
Services.prefs.clearUserPref("network.trr.ohttp.relay_uri");
|
||||
await new Promise((resolve, reject) => {
|
||||
httpServer.stop(resolve);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Test that if DNS-over-OHTTP isn't configured, the implementation falls back
|
||||
// to platform resolution.
|
||||
add_task(async function test_ohttp_not_configured() {
|
||||
Services.dns.clearCache(true);
|
||||
setModeAndURI(2, "doh?responseIP=2.2.2.2");
|
||||
await new TRRDNSListener("example.com", "127.0.0.1");
|
||||
});
|
||||
|
||||
add_task(async function set_ohttp_invalid_prefs() {
|
||||
Services.prefs.setCharPref(
|
||||
"network.trr.ohttp.relay_uri",
|
||||
"http://nonexistent.test"
|
||||
);
|
||||
Services.prefs.setCharPref(
|
||||
"network.trr.ohttp.config_uri",
|
||||
"http://nonexistent.test"
|
||||
);
|
||||
|
||||
Cc["@mozilla.org/network/oblivious-http-service;1"].getService(
|
||||
Ci.nsIObliviousHttpService
|
||||
);
|
||||
await TestUtils.topicObserved("ohttp-service-config-loaded");
|
||||
});
|
||||
|
||||
// Test that if DNS-over-OHTTP has an invalid configuration, the implementation
|
||||
// falls back to platform resolution.
|
||||
add_task(async function test_ohttp_invalid_prefs_fallback() {
|
||||
Services.dns.clearCache(true);
|
||||
setModeAndURI(2, "doh?responseIP=2.2.2.2");
|
||||
await new TRRDNSListener("example.com", "127.0.0.1");
|
||||
});
|
||||
|
||||
add_task(async function set_ohttp_prefs_500_error() {
|
||||
Services.prefs.setCharPref(
|
||||
"network.trr.ohttp.relay_uri",
|
||||
`http://localhost:${httpServer.identity.primaryPort}/relay`
|
||||
);
|
||||
Services.prefs.setCharPref(
|
||||
"network.trr.ohttp.config_uri",
|
||||
`http://localhost:${httpServer.identity.primaryPort}/500error`
|
||||
);
|
||||
await TestUtils.topicObserved("ohttp-service-config-loaded");
|
||||
});
|
||||
|
||||
// Test that if DNS-over-OHTTP has an invalid configuration, the implementation
|
||||
// falls back to platform resolution.
|
||||
add_task(async function test_ohttp_500_error_fallback() {
|
||||
Services.dns.clearCache(true);
|
||||
setModeAndURI(2, "doh?responseIP=2.2.2.2");
|
||||
await new TRRDNSListener("example.com", "127.0.0.1");
|
||||
});
|
||||
|
||||
add_task(async function set_ohttp_prefs_valid() {
|
||||
ohttpEncodedConfig = bytesToString(ohttpServer.encodedConfig);
|
||||
Services.prefs.setCharPref(
|
||||
"network.trr.ohttp.config_uri",
|
||||
`http://localhost:${httpServer.identity.primaryPort}/config`
|
||||
);
|
||||
await TestUtils.topicObserved("ohttp-service-config-loaded");
|
||||
});
|
||||
|
||||
add_task(test_A_record);
|
||||
|
||||
add_task(test_AAAA_records);
|
||||
|
||||
add_task(test_RFC1918);
|
||||
|
||||
add_task(test_GET_ECS);
|
||||
|
||||
add_task(test_timeout_mode3);
|
||||
|
||||
add_task(test_strict_native_fallback);
|
||||
|
||||
add_task(test_no_answers_fallback);
|
||||
|
||||
add_task(test_404_fallback);
|
||||
|
||||
add_task(test_mode_1_and_4);
|
||||
|
||||
add_task(test_CNAME);
|
||||
|
||||
add_task(test_name_mismatch);
|
||||
|
||||
add_task(test_mode_2);
|
||||
|
||||
add_task(test_excluded_domains);
|
||||
|
||||
add_task(test_captiveportal_canonicalURL);
|
||||
|
||||
add_task(test_parentalcontrols);
|
||||
|
||||
// TRR-first check that DNS result is used if domain is part of the builtin-excluded-domains pref
|
||||
add_task(test_builtin_excluded_domains);
|
||||
|
||||
add_task(test_excluded_domains_mode3);
|
||||
|
||||
add_task(test25e);
|
||||
|
||||
add_task(test_parentalcontrols_mode3);
|
||||
|
||||
add_task(test_builtin_excluded_domains_mode3);
|
||||
|
||||
add_task(count_cookies);
|
||||
|
||||
// This test doesn't work with having a JS httpd server as a relay.
|
||||
// add_task(test_connection_closed);
|
||||
|
||||
add_task(test_fetch_time);
|
||||
|
||||
add_task(test_fqdn);
|
||||
|
||||
add_task(test_ipv6_trr_fallback);
|
||||
|
||||
add_task(test_ipv4_trr_fallback);
|
||||
|
||||
add_task(test_no_retry_without_doh);
|
|
@ -5,10 +5,6 @@
|
|||
|
||||
const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
|
||||
function bytesToString(bytes) {
|
||||
return String.fromCharCode.apply(null, bytes);
|
||||
}
|
||||
|
||||
class ObliviousHttpTestRequest {
|
||||
constructor(method, uri, headers, content) {
|
||||
this.method = method;
|
||||
|
|
|
@ -178,6 +178,10 @@ skip-if = bits != 32
|
|||
[test_udpsocket.js]
|
||||
[test_udpsocket_offline.js]
|
||||
[test_doomentry.js]
|
||||
[test_dooh.js]
|
||||
head = head_channels.js head_cache.js head_cookies.js head_trr.js head_http3.js trr_common.js
|
||||
run-sequentially = node server exceptions dont replay well
|
||||
skip-if = socketprocess_networking
|
||||
[test_cacheflags.js]
|
||||
skip-if =
|
||||
os == "win" && os_version == "6.1" # Skip on Azure - frequent failure
|
||||
|
|
Загрузка…
Ссылка в новой задаче