Bug 1652655 - P3: Dispatch the transaction based on HTTPSSVC record, r=dragana

Differential Revision: https://phabricator.services.mozilla.com/D85123
This commit is contained in:
Kershaw Chang 2020-08-21 18:59:15 +00:00
Родитель a841171067
Коммит 10d957aaa7
12 изменённых файлов: 197 добавлений и 2 удалений

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

@ -8316,6 +8316,12 @@
value: false
mirror: always
# Whether to use HTTPS RR as AltSvc
- name: network.dns.use_https_rr_as_altsvc
type: RelaxedAtomicBool
value: false
mirror: always
#---------------------------------------------------------------------------
# Prefs starting with "nglayout."
#---------------------------------------------------------------------------

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

@ -746,5 +746,9 @@ NS_IMETHODIMP ClassifierDummyChannel::GetResponseEmbedderPolicy(
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP ClassifierDummyChannel::SetWaitForHTTPSSVCRecord() {
return NS_ERROR_NOT_IMPLEMENTED;
}
} // namespace net
} // namespace mozilla

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

@ -4840,5 +4840,10 @@ void HttpBaseChannel::MaybeFlushConsoleReports() {
void HttpBaseChannel::DoDiagnosticAssertWhenOnStopNotCalledOnDestroy() {}
NS_IMETHODIMP HttpBaseChannel::SetWaitForHTTPSSVCRecord() {
mCaps |= NS_HTTP_WAIT_HTTPSSVC_RESULT;
return NS_OK;
}
} // namespace net
} // namespace mozilla

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

@ -340,6 +340,8 @@ class HttpBaseChannel : public nsHashPropertyBag,
nsIHttpUpgradeListener* aListener) override;
void DoDiagnosticAssertWhenOnStopNotCalledOnDestroy() override;
NS_IMETHOD SetWaitForHTTPSSVCRecord() override;
// nsISupportsPriority
NS_IMETHOD GetPriority(int32_t* value) override;
NS_IMETHOD AdjustPriority(int32_t delta) override;

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

@ -120,6 +120,10 @@ extern const nsCString kHttp3Versions[];
// such as HTTP upgrade which are not supported by HTTP3.
#define NS_HTTP_DISALLOW_HTTP3 (1 << 22)
// Force a transaction to stay in pending queue until the HTTPSSVC record is
// available.
#define NS_HTTP_WAIT_HTTPSSVC_RESULT (1 << 23)
#define NS_HTTP_TRR_FLAGS_FROM_MODE(x) ((static_cast<uint32_t>(x) & 3) << 19)
#define NS_HTTP_TRR_MODE_FROM_FLAGS(x) \

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

@ -26,7 +26,10 @@
#include "nsHttpConnectionMgr.h"
#include "nsHttpHandler.h"
#include "nsIClassOfService.h"
#include "nsIDNSByTypeRecord.h"
#include "nsIDNSRecord.h"
#include "nsIDNSListener.h"
#include "nsIDNSService.h"
#include "nsIHttpChannelInternal.h"
#include "nsIRequestContext.h"
#include "nsISocketTransport.h"
@ -1716,6 +1719,12 @@ nsresult nsHttpConnectionMgr::TryDispatchTransaction(
// consider pipelining scripts and revalidations
// h1 pipelining has been removed
// Don't dispatch if this transaction is waiting for HTTPS RR.
// Note that this is only used in test currently.
if (caps & NS_HTTP_WAIT_HTTPSSVC_RESULT) {
return NS_ERROR_NOT_AVAILABLE;
}
// step 4
if (!onlyReusedConnection) {
nsresult rv = MakeNewConnection(ent, pendingTransInfo);
@ -5762,6 +5771,62 @@ void nsHttpConnectionMgr::MoveToWildCardConnEntry(
}
}
bool nsHttpConnectionMgr::MoveTransToHTTPSSVCConnEntry(
nsHttpTransaction* aTrans, nsHttpConnectionInfo* aNewCI) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG(("nsHttpConnectionMgr::MoveTransToHTTPSSVCConnEntry: trans=%p aNewCI=%s",
aTrans, aNewCI->HashKey().get()));
bool prohibitWildCard = !!aTrans->TunnelProvider();
bool noHttp3 = aTrans->Caps() & NS_HTTP_DISALLOW_HTTP3;
// Step 1: Check if the new entry is the same as the old one.
nsConnectionEntry* oldEntry = GetOrCreateConnectionEntry(
aTrans->ConnectionInfo(), prohibitWildCard, noHttp3);
nsConnectionEntry* newEntry =
GetOrCreateConnectionEntry(aNewCI, prohibitWildCard, noHttp3);
if (oldEntry == newEntry) {
return true;
}
// Step 2: Try to find the undispatched transaction.
int32_t transIndex;
// We will abandon all half-open sockets belonging to the given
// transaction.
nsTArray<RefPtr<PendingTransactionInfo>>* infoArray =
GetTransactionPendingQHelper(oldEntry, aTrans);
RefPtr<PendingTransactionInfo> pendingTransInfo;
transIndex =
infoArray ? infoArray->IndexOf(aTrans, 0, PendingComparator()) : -1;
if (transIndex >= 0) {
pendingTransInfo = (*infoArray)[transIndex];
infoArray->RemoveElementAt(transIndex);
}
// It's fine we can't find the transaction. The transaction may not be added.
if (!pendingTransInfo) {
return false;
}
MOZ_ASSERT(pendingTransInfo->mTransaction == aTrans);
// Abandon all half-open sockets belonging to the given transaction.
RefPtr<nsHalfOpenSocket> half = do_QueryReferent(pendingTransInfo->mHalfOpen);
if (half) {
half->Abandon();
}
pendingTransInfo->mHalfOpen = nullptr;
pendingTransInfo->mActiveConn = nullptr;
// Step 3: Add the transaction to the new entry.
aTrans->UpdateConnectionInfo(aNewCI);
Unused << ProcessNewTransaction(aTrans);
return true;
}
nsHttpConnectionMgr* nsHttpConnectionMgr::AsHttpConnectionMgr() { return this; }
HttpConnectionMgrParent* nsHttpConnectionMgr::AsHttpConnectionMgrParent() {

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

@ -94,6 +94,12 @@ class nsHttpConnectionMgr final : public HttpConnectionMgrShell,
nsHttpConnectionInfo* wildcardCI,
HttpConnectionBase* conn);
// Move a transaction from the pendingQ of it's connection entry to another
// one. Returns true if the transaction is moved successfully, otherwise
// returns false.
bool MoveTransToHTTPSSVCConnEntry(nsHttpTransaction* aTrans,
nsHttpConnectionInfo* aNewCI);
[[nodiscard]] bool ProcessPendingQForEntry(nsHttpConnectionInfo*);
// This is used to force an idle connection to be closed and removed from

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

@ -2964,4 +2964,8 @@ void nsHttpHandler::MaybeAddAltSvcForTesting(
}
}
bool nsHttpHandler::UseHTTPSRRAsAltSvcEnabled() const {
return StaticPrefs::network_dns_use_https_rr_as_altsvc();
}
} // namespace mozilla::net

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

@ -502,6 +502,8 @@ class nsHttpHandler final : public nsIHttpProtocolHandler,
nsIInterfaceRequestor* aCallbacks,
const OriginAttributes& aOriginAttributes);
bool UseHTTPSRRAsAltSvcEnabled() const;
private:
nsHttpHandler();

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

@ -28,6 +28,9 @@
#include "nsHttpResponseHead.h"
#include "nsICancelable.h"
#include "nsIClassOfService.h"
#include "nsIDNSByTypeRecord.h"
#include "nsIDNSRecord.h"
#include "nsIDNSService.h"
#include "nsIEventTarget.h"
#include "nsIHttpActivityObserver.h"
#include "nsIHttpAuthenticator.h"
@ -424,6 +427,27 @@ nsresult nsHttpTransaction::Init(
MOZ_ASSERT(trans);
mPushedStream = trans->TakePushedStreamById(aPushedStreamId);
}
if (gHttpHandler->UseHTTPSRRAsAltSvcEnabled()) {
nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
nsCOMPtr<nsIEventTarget> target;
Unused << gHttpHandler->GetSocketThreadTarget(getter_AddRefs(target));
if (dns && target) {
uint32_t flags =
nsIDNSService::GetFlagsFromTRRMode(mConnInfo->GetTRRMode());
if (mCaps & NS_HTTP_REFRESH_DNS) {
flags |= nsIDNSService::RESOLVE_BYPASS_CACHE;
}
rv = dns->AsyncResolveNative(
mConnInfo->GetOrigin(), nsIDNSService::RESOLVE_TYPE_HTTPSSVC, flags,
nullptr, this, target, mConnInfo->GetOriginAttributes(),
getter_AddRefs(mDNSRequest));
if (NS_FAILED(rv) && (mCaps & NS_HTTP_WAIT_HTTPSSVC_RESULT)) {
return rv;
}
}
}
return NS_OK;
}
@ -522,6 +546,11 @@ void nsHttpTransaction::OnActivated() {
return;
}
if (mDNSRequest) {
mDNSRequest->Cancel(NS_ERROR_ABORT);
mDNSRequest = nullptr;
}
if (mTrafficCategory != HttpTrafficCategory::eInvalid) {
HttpTrafficAnalyzer* hta = gHttpHandler->GetHttpTrafficAnalyzer();
if (hta) {
@ -2364,7 +2393,7 @@ nsHttpTransaction::Release() {
}
NS_IMPL_QUERY_INTERFACE(nsHttpTransaction, nsIInputStreamCallback,
nsIOutputStreamCallback)
nsIOutputStreamCallback, nsIDNSListener)
//-----------------------------------------------------------------------------
// nsHttpTransaction::nsIInputStreamCallback
@ -2627,5 +2656,58 @@ void nsHttpTransaction::NotifyTransactionObserver(nsresult reason) {
obs(std::move(result));
}
void nsHttpTransaction::UpdateConnectionInfo(nsHttpConnectionInfo* aConnInfo) {
MOZ_ASSERT(aConnInfo);
if (mActivated) {
MOZ_ASSERT(false, "Should not update conn info after activated");
return;
}
// TODO: maybe backup the old connection info.
mConnInfo = aConnInfo;
}
NS_IMETHODIMP nsHttpTransaction::OnLookupComplete(nsICancelable* aRequest,
nsIDNSRecord* aRecord,
nsresult aStatus) {
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
LOG(("nsHttpTransaction::OnLookupComplete [this=%p] mActivated=%d", this,
mActivated));
mDNSRequest = nullptr;
MakeDontWaitHTTPSSVC();
if (mActivated) {
return NS_OK;
}
nsCOMPtr<nsIDNSHTTPSSVCRecord> record = do_QueryInterface(aRecord);
if (!record || NS_FAILED(aStatus)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsISVCBRecord> svcbRecord;
if (NS_FAILED(record->GetServiceModeRecord(mCaps & NS_HTTP_DISALLOW_SPDY,
mCaps & NS_HTTP_DISALLOW_HTTP3,
getter_AddRefs(svcbRecord)))) {
return NS_ERROR_FAILURE;
}
RefPtr<nsHttpConnectionInfo> newInfo =
mConnInfo->CloneAndAdoptHTTPSSVCRecord(svcbRecord);
if (!gHttpHandler->ConnMgr()->MoveTransToHTTPSSVCConnEntry(this, newInfo)) {
// MoveTransToHTTPSSVCConnEntry() returning fail means this transaction is
// not in the connection entry's pending queue. This could happen if
// OnLookupComplete() is called before this transaction is added in the
// queue. We still need to update the connection info, so this transaction
// can be added to the right connection entry.
UpdateConnectionInfo(newInfo);
}
return NS_OK;
}
} // namespace net
} // namespace mozilla

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

@ -13,6 +13,7 @@
#include "EventTokenBucket.h"
#include "nsCOMPtr.h"
#include "nsThreadUtils.h"
#include "nsIDNSListener.h"
#include "nsIInterfaceRequestor.h"
#include "TimingStruct.h"
#include "Http2Push.h"
@ -48,13 +49,15 @@ class nsHttpTransaction final : public nsAHttpTransaction,
public ATokenBucketEvent,
public nsIInputStreamCallback,
public nsIOutputStreamCallback,
public ARefBase {
public ARefBase,
public nsIDNSListener {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSAHTTPTRANSACTION
NS_DECL_HTTPTRANSACTIONSHELL
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_NSIOUTPUTSTREAMCALLBACK
NS_DECL_NSIDNSLISTENER
nsHttpTransaction();
@ -74,6 +77,8 @@ class nsHttpTransaction final : public nsAHttpTransaction,
void MakeSticky() { mCaps |= NS_HTTP_STICKY_CONNECTION; }
void MakeNonSticky() override { mCaps &= ~NS_HTTP_STICKY_CONNECTION; }
void MakeDontWaitHTTPSSVC() { mCaps &= ~NS_HTTP_WAIT_HTTPSSVC_RESULT; }
// SetPriority() may only be used by the connection manager.
void SetPriority(int32_t priority) { mPriority = priority; }
int32_t Priority() { return mPriority; }
@ -144,6 +149,8 @@ class nsHttpTransaction final : public nsAHttpTransaction,
// transaction.
void OnPush(Http2PushedStreamWrapper* aStream);
void UpdateConnectionInfo(nsHttpConnectionInfo* aConnInfo);
private:
friend class DeleteHttpTransaction;
virtual ~nsHttpTransaction();
@ -431,6 +438,8 @@ class nsHttpTransaction final : public nsAHttpTransaction,
OnPushCallback mOnPushCallback;
nsDataHashtable<nsUint32HashKey, RefPtr<Http2PushedStreamWrapper>>
mIDToStreamMap;
nsCOMPtr<nsICancelable> mDNSRequest;
};
} // namespace net

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

@ -415,4 +415,10 @@ interface nsIHttpChannelInternal : nsISupports
[noscript, notxpcom, nostdcall]
void DoDiagnosticAssertWhenOnStopNotCalledOnDestroy();
/**
* If this is called, this channel's transaction will not be dispatched
* until the HTTPSSVC record is available.
*/
[must_use] void setWaitForHTTPSSVCRecord();
};