diff options
Diffstat (limited to 'netwerk/protocol/http')
25 files changed, 275 insertions, 127 deletions
diff --git a/netwerk/protocol/http/ConnectionEntry.cpp b/netwerk/protocol/http/ConnectionEntry.cpp index 7b59011cd3..dc0dfd103c 100644 --- a/netwerk/protocol/http/ConnectionEntry.cpp +++ b/netwerk/protocol/http/ConnectionEntry.cpp @@ -124,6 +124,7 @@ void ConnectionEntry::DisallowHttp2() { // Can't coalesce if we're not using spdy mCoalescingKeys.Clear(); + mAddresses.Clear(); } void ConnectionEntry::DontReuseHttp3Conn() { @@ -137,6 +138,7 @@ void ConnectionEntry::DontReuseHttp3Conn() { // Can't coalesce if we're not using http3 mCoalescingKeys.Clear(); + mAddresses.Clear(); } void ConnectionEntry::RecordIPFamilyPreference(uint16_t family) { @@ -447,6 +449,7 @@ void ConnectionEntry::ClosePersistentConnections() { } mCoalescingKeys.Clear(); + mAddresses.Clear(); } uint32_t ConnectionEntry::PruneDeadConnections() { @@ -969,18 +972,16 @@ bool ConnectionEntry::MaybeProcessCoalescingKeys(nsIDNSAddrRecord* dnsRecord, return false; } - nsTArray<NetAddr> addressSet; - nsresult rv = dnsRecord->GetAddresses(addressSet); - - if (NS_FAILED(rv) || addressSet.IsEmpty()) { + nsresult rv = dnsRecord->GetAddresses(mAddresses); + if (NS_FAILED(rv) || mAddresses.IsEmpty()) { return false; } - for (uint32_t i = 0; i < addressSet.Length(); ++i) { - if ((addressSet[i].raw.family == AF_INET && addressSet[i].inet.ip == 0) || - (addressSet[i].raw.family == AF_INET6 && - addressSet[i].inet6.ip.u64[0] == 0 && - addressSet[i].inet6.ip.u64[1] == 0)) { + for (uint32_t i = 0; i < mAddresses.Length(); ++i) { + if ((mAddresses[i].raw.family == AF_INET && mAddresses[i].inet.ip == 0) || + (mAddresses[i].raw.family == AF_INET6 && + mAddresses[i].inet6.ip.u64[0] == 0 && + mAddresses[i].inet6.ip.u64[1] == 0)) { // Bug 1680249 - Don't create the coalescing key if the ip address is // `0.0.0.0` or `::`. LOG( @@ -991,7 +992,7 @@ bool ConnectionEntry::MaybeProcessCoalescingKeys(nsIDNSAddrRecord* dnsRecord, } nsCString* newKey = mCoalescingKeys.AppendElement(nsCString()); newKey->SetLength(kIPv6CStrBufSize + 26); - addressSet[i].ToStringBuffer(newKey->BeginWriting(), kIPv6CStrBufSize); + mAddresses[i].ToStringBuffer(newKey->BeginWriting(), kIPv6CStrBufSize); newKey->SetLength(strlen(newKey->BeginReading())); if (mConnInfo->GetAnonymous()) { newKey->AppendLiteral("~A:"); diff --git a/netwerk/protocol/http/ConnectionEntry.h b/netwerk/protocol/http/ConnectionEntry.h index 8ccc126503..6a265e58fc 100644 --- a/netwerk/protocol/http/ConnectionEntry.h +++ b/netwerk/protocol/http/ConnectionEntry.h @@ -121,8 +121,14 @@ class ConnectionEntry { // combined with the Anonymous flag and OA from the connection information // to build the hash key for hosts in the same ip pool. // + nsTArray<nsCString> mCoalescingKeys; + // This is a list of addresses matching the coalescing keys. + // This is necessary to check if the origin's DNS entries + // contain the IP address of the active connection. + nsTArray<NetAddr> mAddresses; + // To have the UsingSpdy flag means some host with the same connection // entry has done NPN=spdy/* at some point. It does not mean every // connection is currently using spdy. diff --git a/netwerk/protocol/http/EarlyHintPreloader.cpp b/netwerk/protocol/http/EarlyHintPreloader.cpp index 920fea7fcd..3c8fd5a882 100644 --- a/netwerk/protocol/http/EarlyHintPreloader.cpp +++ b/netwerk/protocol/http/EarlyHintPreloader.cpp @@ -330,7 +330,7 @@ void EarlyHintPreloader::MaybeCreateAndInsertPreload( // directives to it nsCOMPtr<nsIContentSecurityPolicy> csp = new nsCSPContext(); nsresult rv = csp->SetRequestContextWithPrincipal( - aPrincipal, aBaseURI, u""_ns, 0 /* aInnerWindowId */); + aPrincipal, aBaseURI, ""_ns, 0 /* aInnerWindowId */); NS_ENSURE_SUCCESS_VOID(rv); rv = CSP_AppendCSPFromHeader(csp, NS_ConvertUTF8toUTF16(aCSPHeader), false /* report only */); diff --git a/netwerk/protocol/http/Http3Stream.cpp b/netwerk/protocol/http/Http3Stream.cpp index 4f33ca07e2..4bb6b30925 100644 --- a/netwerk/protocol/http/Http3Stream.cpp +++ b/netwerk/protocol/http/Http3Stream.cpp @@ -42,7 +42,7 @@ Http3Stream::Http3Stream(nsAHttpTransaction* httpTransaction, mTransactionBrowserId = trans->BrowserId(); } - SetPriority(cos.Flags()); + mPriorityUrgency = nsHttpHandler::UrgencyFromCoSFlags(cos.Flags()); SetIncremental(cos.Incremental()); } @@ -80,31 +80,6 @@ bool Http3Stream::GetHeadersString(const char* buf, uint32_t avail, return true; } -void Http3Stream::SetPriority(uint32_t aCos) { - if (aCos & nsIClassOfService::UrgentStart) { - // coming from an user interaction => response should be the highest - // priority - mPriorityUrgency = 1; - } else if (aCos & nsIClassOfService::Leader) { - // main html document normal priority - mPriorityUrgency = 2; - } else if (aCos & nsIClassOfService::Unblocked) { - mPriorityUrgency = 3; - } else if (aCos & nsIClassOfService::Follower) { - mPriorityUrgency = 4; - } else if (aCos & nsIClassOfService::Speculative) { - mPriorityUrgency = 6; - } else if (aCos & nsIClassOfService::Background) { - // background tasks can be deprioritzed to the lowest priority - mPriorityUrgency = 6; - } else if (aCos & nsIClassOfService::Tail) { - mPriorityUrgency = 6; - } else { - // all others get a lower priority than the main html document - mPriorityUrgency = 4; - } -} - void Http3Stream::SetIncremental(bool incremental) { mPriorityIncremental = incremental; } diff --git a/netwerk/protocol/http/Http3Stream.h b/netwerk/protocol/http/Http3Stream.h index 1048b20ef5..fbfd567cbf 100644 --- a/netwerk/protocol/http/Http3Stream.h +++ b/netwerk/protocol/http/Http3Stream.h @@ -67,7 +67,6 @@ class Http3Stream final : public nsAHttpSegmentReader, bool GetHeadersString(const char* buf, uint32_t avail, uint32_t* countUsed); nsresult StartRequest(); - void SetPriority(uint32_t aCos); void SetIncremental(bool incremental); /** diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 9008d758fc..ff88b02753 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -1402,7 +1402,7 @@ nsresult HttpBaseChannel::DoApplyContentConversions( // channels cannot effectively be used in two contexts (specifically this one // and a peek context for sniffing) // -class InterceptFailedOnStop : public nsIStreamListener { +class InterceptFailedOnStop : public nsIThreadRetargetableStreamListener { virtual ~InterceptFailedOnStop() = default; nsCOMPtr<nsIStreamListener> mNext; HttpBaseChannel* mChannel; @@ -1411,6 +1411,7 @@ class InterceptFailedOnStop : public nsIStreamListener { InterceptFailedOnStop(nsIStreamListener* arg, HttpBaseChannel* chan) : mNext(arg), mChannel(chan) {} NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER NS_IMETHOD OnStartRequest(nsIRequest* aRequest) override { return mNext->OnStartRequest(aRequest); @@ -1432,7 +1433,37 @@ class InterceptFailedOnStop : public nsIStreamListener { } }; -NS_IMPL_ISUPPORTS(InterceptFailedOnStop, nsIStreamListener, nsIRequestObserver) +NS_IMPL_ADDREF(InterceptFailedOnStop) +NS_IMPL_RELEASE(InterceptFailedOnStop) + +NS_INTERFACE_MAP_BEGIN(InterceptFailedOnStop) + NS_INTERFACE_MAP_ENTRY(nsIStreamListener) + NS_INTERFACE_MAP_ENTRY(nsIRequestObserver) + NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableStreamListener) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRequestObserver) +NS_INTERFACE_MAP_END + +NS_IMETHODIMP +InterceptFailedOnStop::CheckListenerChain() { + nsCOMPtr<nsIThreadRetargetableStreamListener> listener = + do_QueryInterface(mNext); + if (!listener) { + return NS_ERROR_NO_INTERFACE; + } + + return listener->CheckListenerChain(); +} + +NS_IMETHODIMP +InterceptFailedOnStop::OnDataFinished(nsresult aStatus) { + nsCOMPtr<nsIThreadRetargetableStreamListener> listener = + do_QueryInterface(mNext); + if (listener) { + return listener->OnDataFinished(aStatus); + } + + return NS_OK; +} NS_IMETHODIMP HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener, @@ -1508,6 +1539,8 @@ HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener, mode = 2; } else if (from.EqualsLiteral("br")) { mode = 3; + } else if (from.EqualsLiteral("zstd")) { + mode = 4; } Telemetry::Accumulate(Telemetry::HTTP_CONTENT_ENCODING, mode); } @@ -1612,6 +1645,14 @@ HttpBaseChannel::nsContentEncodings::GetNext(nsACString& aNextEncoding) { } } + if (!haveType) { + encoding.BeginReading(start); + if (CaseInsensitiveFindInReadable("zstd"_ns, start, end)) { + aNextEncoding.AssignLiteral(APPLICATION_ZSTD); + haveType = true; + } + } + // Prepare to fetch the next encoding mCurEnd = mCurStart; mReady = false; @@ -2392,7 +2433,6 @@ HttpBaseChannel::GetDocumentURI(nsIURI** aDocumentURI) { NS_IMETHODIMP HttpBaseChannel::SetDocumentURI(nsIURI* aDocumentURI) { ENSURE_CALLED_BEFORE_CONNECT(); - mDocumentURI = aDocumentURI; return NS_OK; } @@ -4973,7 +5013,7 @@ nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI* newURI, httpInternal->SetLastRedirectFlags(redirectFlags); if (LoadRequireCORSPreflight()) { - httpInternal->SetCorsPreflightParameters(mUnsafeHeaders, false); + httpInternal->SetCorsPreflightParameters(mUnsafeHeaders, false, false); } } @@ -5847,17 +5887,20 @@ void HttpBaseChannel::EnsureBrowserId() { void HttpBaseChannel::SetCorsPreflightParameters( const nsTArray<nsCString>& aUnsafeHeaders, - bool aShouldStripRequestBodyHeader) { + bool aShouldStripRequestBodyHeader, bool aShouldStripAuthHeader) { MOZ_RELEASE_ASSERT(!LoadRequestObserversCalled()); StoreRequireCORSPreflight(true); mUnsafeHeaders = aUnsafeHeaders.Clone(); - if (aShouldStripRequestBodyHeader) { + if (aShouldStripRequestBodyHeader || aShouldStripAuthHeader) { mUnsafeHeaders.RemoveElementsBy([&](const nsCString& aHeader) { - return aHeader.LowerCaseEqualsASCII("content-type") || - aHeader.LowerCaseEqualsASCII("content-encoding") || - aHeader.LowerCaseEqualsASCII("content-language") || - aHeader.LowerCaseEqualsASCII("content-location"); + return (aShouldStripRequestBodyHeader && + (aHeader.LowerCaseEqualsASCII("content-type") || + aHeader.LowerCaseEqualsASCII("content-encoding") || + aHeader.LowerCaseEqualsASCII("content-language") || + aHeader.LowerCaseEqualsASCII("content-location"))) || + (aShouldStripAuthHeader && + aHeader.LowerCaseEqualsASCII("authorization")); }); } } diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index f3678bb0c9..d6d693212b 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -319,7 +319,7 @@ class HttpBaseChannel : public nsHashPropertyBag, NS_IMETHOD GetProxyURI(nsIURI** proxyURI) override; virtual void SetCorsPreflightParameters( const nsTArray<nsCString>& unsafeHeaders, - bool aShouldStripRequestBodyHeader) override; + bool aShouldStripRequestBodyHeader, bool aShouldStripAuthHeader) override; virtual void SetAltDataForChild(bool aIsForChild) override; virtual void DisableAltDataCache() override { StoreDisableAltDataCache(true); diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index c7009f34d3..8b581b070e 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -8,7 +8,7 @@ // HttpLog.h should generally be included first #include "HttpLog.h" -#include "mozilla/net/PBackgroundDataBridge.h" +#include "nsError.h" #include "nsHttp.h" #include "nsICacheEntry.h" #include "mozilla/BasePrincipal.h" @@ -23,6 +23,7 @@ #include "mozilla/ipc/IPCStreamUtils.h" #include "mozilla/net/NeckoChild.h" #include "mozilla/net/HttpChannelChild.h" +#include "mozilla/net/PBackgroundDataBridge.h" #include "mozilla/net/UrlClassifierCommon.h" #include "mozilla/net/UrlClassifierFeatureFactory.h" @@ -34,6 +35,7 @@ #include "nsContentPolicyUtils.h" #include "nsDOMNavigationTiming.h" #include "nsIThreadRetargetableStreamListener.h" +#include "nsIStreamTransportService.h" #include "nsStringStream.h" #include "nsHttpChannel.h" #include "nsHttpHandler.h" @@ -598,6 +600,17 @@ void HttpChannelChild::DoOnStartRequest(nsIRequest* aRequest) { } else if (listener) { mListener = listener; mCompressListener = listener; + + // We call MaybeRetarget here to allow the stream converter + // the option to request data on another thread, even if the + // final listener might not support it + if (nsCOMPtr<nsIStreamConverter> conv = + do_QueryInterface((mCompressListener))) { + rv = conv->MaybeRetarget(this); + if (NS_SUCCEEDED(rv)) { + mOMTResult = LABELS_HTTP_CHILD_OMT_STATS_2::successOnlyDecomp; + } + } } } @@ -852,15 +865,10 @@ class RecordStopRequestDelta final { } TimeDuration delta = (mOnStopRequestTime - mOnDataFinishedTime); - if (delta.ToMilliseconds() < 0) { - // Because Telemetry can't handle negatives - delta = -delta; - glean::networking::http_content_ondatafinished_to_onstop_delay_negative - .AccumulateRawDuration(delta); - } else { - glean::networking::http_content_ondatafinished_to_onstop_delay - .AccumulateRawDuration(delta); - } + MOZ_ASSERT((delta.ToMilliseconds() >= 0), + "OnDataFinished after OnStopRequest"); + glean::networking::http_content_ondatafinished_to_onstop_delay + .AccumulateRawDuration(delta); } }; @@ -1157,7 +1165,7 @@ void HttpChannelChild::CollectOMTTelemetry() { NS_CP_ContentTypeName(mLoadInfo->InternalContentPolicyType())); Telemetry::AccumulateCategoricalKeyed( - key, static_cast<LABELS_HTTP_CHILD_OMT_STATS>(mOMTResult)); + key, static_cast<LABELS_HTTP_CHILD_OMT_STATS_2>(mOMTResult)); } // We want to inspect all upgradable mixed content loads @@ -3055,7 +3063,7 @@ HttpChannelChild::RetargetDeliveryTo(nsISerialEventTarget* aNewTarget) { NS_ENSURE_ARG(aNewTarget); if (aNewTarget->IsOnCurrentThread()) { NS_WARNING("Retargeting delivery to same thread"); - mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::successMainThread; + mOMTResult = LABELS_HTTP_CHILD_OMT_STATS_2::successMainThread; return NS_OK; } @@ -3063,7 +3071,7 @@ HttpChannelChild::RetargetDeliveryTo(nsISerialEventTarget* aNewTarget) { // TODO: Maybe add a new label for this? Maybe it doesn't // matter though, since we also blocked QI, so we shouldn't // ever get here. - mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::failListener; + mOMTResult = LABELS_HTTP_CHILD_OMT_STATS_2::failListener; return NS_ERROR_NO_INTERFACE; } @@ -3074,27 +3082,34 @@ HttpChannelChild::RetargetDeliveryTo(nsISerialEventTarget* aNewTarget) { do_QueryInterface(mListener, &rv); if (!retargetableListener || NS_FAILED(rv)) { NS_WARNING("Listener is not retargetable"); - mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::failListener; + mOMTResult = LABELS_HTTP_CHILD_OMT_STATS_2::failListener; return NS_ERROR_NO_INTERFACE; } rv = retargetableListener->CheckListenerChain(); if (NS_FAILED(rv)) { NS_WARNING("Subsequent listeners are not retargetable"); - mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::failListenerChain; + mOMTResult = LABELS_HTTP_CHILD_OMT_STATS_2::failListenerChain; return rv; } { MutexAutoLock lock(mEventTargetMutex); MOZ_ASSERT(!mODATarget); - mODATarget = aNewTarget; + RetargetDeliveryToImpl(aNewTarget, lock); } - mOMTResult = LABELS_HTTP_CHILD_OMT_STATS::success; + mOMTResult = LABELS_HTTP_CHILD_OMT_STATS_2::success; return NS_OK; } +void HttpChannelChild::RetargetDeliveryToImpl(nsISerialEventTarget* aNewTarget, + MutexAutoLock& aLockRef) { + aLockRef.AssertOwns(mEventTargetMutex); + + mODATarget = aNewTarget; +} + NS_IMETHODIMP HttpChannelChild::GetDeliveryTarget(nsISerialEventTarget** aEventTarget) { MutexAutoLock lock(mEventTargetMutex); diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index 38895a0555..8cfc820a23 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -33,7 +33,7 @@ #include "nsIThreadRetargetableRequest.h" #include "mozilla/net/DNS.h" -using mozilla::Telemetry::LABELS_HTTP_CHILD_OMT_STATS; +using mozilla::Telemetry::LABELS_HTTP_CHILD_OMT_STATS_2; class nsIEventTarget; class nsIInterceptedBodyCallback; @@ -271,6 +271,9 @@ class HttpChannelChild final : public PHttpChannelChild, nsresult MaybeLogCOEPError(nsresult aStatus); + void RetargetDeliveryToImpl(nsISerialEventTarget* aNewTarget, + MutexAutoLock& aLockRef); + private: // this section is for main-thread-only object // all the references need to be proxy released on main thread. @@ -312,8 +315,8 @@ class HttpChannelChild final : public PHttpChannelChild, // The result of RetargetDeliveryTo for this channel. // |notRequested| represents OMT is not requested by the channel owner. - Atomic<LABELS_HTTP_CHILD_OMT_STATS, mozilla::Relaxed> mOMTResult{ - LABELS_HTTP_CHILD_OMT_STATS::notRequested}; + Atomic<LABELS_HTTP_CHILD_OMT_STATS_2, mozilla::Relaxed> mOMTResult{ + LABELS_HTTP_CHILD_OMT_STATS_2::notRequested}; uint32_t mCacheKey{0}; int32_t mCacheFetchCount{0}; diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index e734d15a7d..b8634512ce 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -587,7 +587,7 @@ bool HttpChannelParent::DoAsyncOpen( if (aCorsPreflightArgs.isSome()) { const CorsPreflightArgs& args = aCorsPreflightArgs.ref(); - httpChannel->SetCorsPreflightParameters(args.unsafeHeaders(), false); + httpChannel->SetCorsPreflightParameters(args.unsafeHeaders(), false, false); } nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(uploadStream); @@ -896,7 +896,7 @@ mozilla::ipc::IPCResult HttpChannelParent::RecvRedirect2Verify( MOZ_RELEASE_ASSERT(newInternalChannel); const CorsPreflightArgs& args = aCorsPreflightArgs.ref(); newInternalChannel->SetCorsPreflightParameters(args.unsafeHeaders(), - false); + false, false); } if (aReferrerInfo) { @@ -1180,7 +1180,7 @@ HttpChannelParent::OnStartRequest(nsIRequest* aRequest) { PContentParent* pcp = Manager()->Manager(); MOZ_ASSERT(pcp, "We should have a manager if our IPC isn't closed"); DebugOnly<nsresult> rv = - static_cast<ContentParent*>(pcp)->AboutToLoadHttpFtpDocumentForChild( + static_cast<ContentParent*>(pcp)->AboutToLoadHttpDocumentForChild( chan, &args.shouldWaitForOnStartRequestSent()); MOZ_ASSERT(NS_SUCCEEDED(rv)); } diff --git a/netwerk/protocol/http/ObliviousHttpChannel.cpp b/netwerk/protocol/http/ObliviousHttpChannel.cpp index fafbf84b0b..1b4449f004 100644 --- a/netwerk/protocol/http/ObliviousHttpChannel.cpp +++ b/netwerk/protocol/http/ObliviousHttpChannel.cpp @@ -419,10 +419,10 @@ void ObliviousHttpChannel::SetAltDataForChild(bool aIsForChild) { void ObliviousHttpChannel::SetCorsPreflightParameters( nsTArray<nsTString<char>> const& aUnsafeHeaders, - bool aShouldStripRequestBodyHeader) { + bool aShouldStripRequestBodyHeader, bool aShouldStripAuthHeader) { if (mInnerChannelInternal) { mInnerChannelInternal->SetCorsPreflightParameters( - aUnsafeHeaders, aShouldStripRequestBodyHeader); + aUnsafeHeaders, aShouldStripRequestBodyHeader, aShouldStripAuthHeader); } } diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index 90ac6a4ddc..2846b852ca 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -441,7 +441,8 @@ nsresult nsCORSListenerProxy::Init(nsIChannel* aChannel, getter_AddRefs(mOuterNotificationCallbacks)); aChannel->SetNotificationCallbacks(this); - nsresult rv = UpdateChannel(aChannel, aAllowDataURI, UpdateType::Default); + nsresult rv = + UpdateChannel(aChannel, aAllowDataURI, UpdateType::Default, false); if (NS_FAILED(rv)) { { MutexAutoLock lock(mMutex); @@ -765,7 +766,7 @@ nsCORSListenerProxy::AsyncOnChannelRedirect( // data URIs should have been blocked before we got to the internal // redirect. rv = UpdateChannel(aNewChannel, DataURIHandling::Allow, - UpdateType::InternalOrHSTSRedirect); + UpdateType::InternalOrHSTSRedirect, false); if (NS_FAILED(rv)) { NS_WARNING( "nsCORSListenerProxy::AsyncOnChannelRedirect: " @@ -835,6 +836,13 @@ nsCORSListenerProxy::AsyncOnChannelRedirect( } bool rewriteToGET = false; + // We need to strip auth header from preflight request for + // cross-origin redirects. + // See Bug 1874132 + bool stripAuthHeader = + StaticPrefs::network_fetch_redirect_stripAuthHeader() && + NS_ShouldRemoveAuthHeaderOnRedirect(aOldChannel, aNewChannel, aFlags); + nsCOMPtr<nsIHttpChannel> oldHttpChannel = do_QueryInterface(aOldChannel); if (oldHttpChannel) { nsAutoCString method; @@ -843,9 +851,10 @@ nsCORSListenerProxy::AsyncOnChannelRedirect( &rewriteToGET); } - rv = UpdateChannel(aNewChannel, DataURIHandling::Disallow, - rewriteToGET ? UpdateType::StripRequestBodyHeader - : UpdateType::Default); + rv = UpdateChannel( + aNewChannel, DataURIHandling::Disallow, + rewriteToGET ? UpdateType::StripRequestBodyHeader : UpdateType::Default, + stripAuthHeader); if (NS_FAILED(rv)) { NS_WARNING( "nsCORSListenerProxy::AsyncOnChannelRedirect: " @@ -930,7 +939,10 @@ bool CheckInsecureUpgradePreventsCORS(nsIPrincipal* aRequestingPrincipal, nsresult nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, DataURIHandling aAllowDataURI, - UpdateType aUpdateType) { + UpdateType aUpdateType, + bool aStripAuthHeader) { + MOZ_ASSERT_IF(aUpdateType == UpdateType::InternalOrHSTSRedirect, + !aStripAuthHeader); nsCOMPtr<nsIURI> uri, originalURI; nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, rv); @@ -1020,7 +1032,7 @@ nsresult nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, // Check if we need to do a preflight, and if so set one up. This must be // called once we know that the request is going, or has gone, cross-origin. - rv = CheckPreflightNeeded(aChannel, aUpdateType); + rv = CheckPreflightNeeded(aChannel, aUpdateType, aStripAuthHeader); NS_ENSURE_SUCCESS(rv, rv); // It's a cross site load @@ -1087,7 +1099,8 @@ nsresult nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, } nsresult nsCORSListenerProxy::CheckPreflightNeeded(nsIChannel* aChannel, - UpdateType aUpdateType) { + UpdateType aUpdateType, + bool aStripAuthHeader) { // If this caller isn't using AsyncOpen, or if this *is* a preflight channel, // then we shouldn't initiate preflight for this channel. nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo(); @@ -1154,7 +1167,7 @@ nsresult nsCORSListenerProxy::CheckPreflightNeeded(nsIChannel* aChannel, internal->SetCorsPreflightParameters( headers.IsEmpty() ? loadInfoHeaders : headers, - aUpdateType == UpdateType::StripRequestBodyHeader); + aUpdateType == UpdateType::StripRequestBodyHeader, aStripAuthHeader); return NS_OK; } diff --git a/netwerk/protocol/http/nsCORSListenerProxy.h b/netwerk/protocol/http/nsCORSListenerProxy.h index e96b0a8aca..cdc3272fe0 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.h +++ b/netwerk/protocol/http/nsCORSListenerProxy.h @@ -92,10 +92,12 @@ class nsCORSListenerProxy final : public nsIInterfaceRequestor, [[nodiscard]] nsresult UpdateChannel(nsIChannel* aChannel, DataURIHandling aAllowDataURI, - UpdateType aUpdateType); + UpdateType aUpdateType, + bool aStripAuthHeader); [[nodiscard]] nsresult CheckRequestApproved(nsIRequest* aRequest); [[nodiscard]] nsresult CheckPreflightNeeded(nsIChannel* aChannel, - UpdateType aUpdateType); + UpdateType aUpdateType, + bool aStripAuthHeader); nsCOMPtr<nsIStreamListener> mOuterListener; // The principal that originally kicked off the request diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 96e61e4fb8..4428b72426 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -15,11 +15,13 @@ #include "mozilla/glean/GleanMetrics.h" #include "mozilla/StoragePrincipalHelper.h" +#include "nsCOMPtr.h" #include "nsContentSecurityUtils.h" #include "nsHttp.h" #include "nsHttpChannel.h" #include "nsHttpChannelAuthProvider.h" #include "nsHttpHandler.h" +#include "nsIStreamConverter.h" #include "nsString.h" #include "nsICacheStorageService.h" #include "nsICacheStorage.h" @@ -483,6 +485,25 @@ void nsHttpChannel::HandleContinueCancellingByURLClassifier( ContinueCancellingByURLClassifier(aErrorCode); } +void nsHttpChannel::SetPriorityHeader() { + uint8_t urgency = nsHttpHandler::UrgencyFromCoSFlags(mClassOfService.Flags()); + bool incremental = mClassOfService.Incremental(); + + nsPrintfCString value( + "%s", urgency != 3 ? nsPrintfCString("u=%d", urgency).get() : ""); + + if (incremental) { + if (!value.IsEmpty()) { + value.Append(", "); + } + value.Append("i"); + } + + if (!value.IsEmpty()) { + SetRequestHeader("Priority"_ns, value, false); + } +} + nsresult nsHttpChannel::OnBeforeConnect() { nsresult rv = NS_OK; @@ -1202,6 +1223,10 @@ nsresult nsHttpChannel::SetupTransaction() { mozilla::MutexAutoLock lock(mRCWNLock); + if (StaticPrefs::network_http_priority_header_enabled()) { + SetPriorityHeader(); + } + // If we're racing cache with network, conditional or byte range header // could be added in OnCacheEntryCheck. We cannot send conditional request // without having the entry, so we need to remove the headers here and @@ -1810,6 +1835,7 @@ nsresult nsHttpChannel::CallOnStartRequest() { "converter in this case."); mListener = listener; mCompressListener = listener; + StoreHasAppliedConversion(true); } } @@ -7664,6 +7690,7 @@ static nsLiteralCString ContentTypeToTelemetryLabel(nsHttpChannel* aChannel) { return "proxy"_ns; } if (contentType.EqualsLiteral(APPLICATION_BROTLI) || + contentType.EqualsLiteral(APPLICATION_ZSTD) || contentType.Find("zip") != kNotFound || contentType.Find("compress") != kNotFound) { return "compressed"_ns; diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index dede167f87..e2fb5abde9 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -566,6 +566,8 @@ class nsHttpChannel final : public HttpBaseChannel, // This method can only be called on the main thread. void PerformBackgroundCacheRevalidationNow(); + void SetPriorityHeader(); + private: nsCOMPtr<nsICancelable> mProxyRequest; diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index c7c385a42a..dbbd8fe0ca 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -817,10 +817,35 @@ HttpConnectionBase* nsHttpConnectionMgr::FindCoalescableConnection( for (uint32_t i = 0; i < keyLen; ++i) { conn = FindCoalescableConnectionByHashKey(ent, ent->mCoalescingKeys[i], justKidding, aNoHttp2, aNoHttp3); + + auto usableEntry = [&](HttpConnectionBase* conn) { + // This is allowed by the spec, but other browsers don't coalesce + // so agressively, which surprises developers. See bug 1420777. + if (StaticPrefs::network_http_http2_aggressive_coalescing()) { + return true; + } + + // Make sure that the connection's IP address is one that is in + // the set of IP addresses in the entry's DNS response. + NetAddr addr; + nsresult rv = conn->GetPeerAddr(&addr); + if (NS_FAILED(rv)) { + // Err on the side of not coalescing + return false; + } + // We don't care about remote port when matching entries. + addr.inet.port = 0; + return ent->mAddresses.Contains(addr); + }; + if (conn) { - LOG(("FindCoalescableConnection(%s) match conn %p on dns key %s\n", - ci->HashKey().get(), conn, ent->mCoalescingKeys[i].get())); - return conn; + LOG(("Found connection with matching hash")); + if (usableEntry(conn)) { + LOG(("> coalescing")); + return conn; + } else { + LOG(("> not coalescing as remote address not present in DNS records")); + } } } diff --git a/netwerk/protocol/http/nsHttpDigestAuth.cpp b/netwerk/protocol/http/nsHttpDigestAuth.cpp index 2a98301942..809cf7993b 100644 --- a/netwerk/protocol/http/nsHttpDigestAuth.cpp +++ b/netwerk/protocol/http/nsHttpDigestAuth.cpp @@ -9,6 +9,7 @@ #include "mozilla/ClearOnShutdown.h" #include "mozilla/Sprintf.h" +#include "mozilla/StaticPrefs_network.h" #include "mozilla/Unused.h" #include "nsHttp.h" @@ -22,6 +23,7 @@ #include "nsCRT.h" #include "nsICryptoHash.h" #include "nsComponentManagerUtils.h" +#include "pk11pub.h" constexpr uint16_t DigestLength(uint16_t aAlgorithm) { if (aAlgorithm & (ALGO_SHA256 | ALGO_SHA256_SESS)) { @@ -321,9 +323,13 @@ nsHttpDigestAuth::GenerateCredentials( // returned Authentication-Info header). also used for session info. // nsAutoCString cnonce; - static const char hexChar[] = "0123456789abcdef"; - for (int i = 0; i < 16; ++i) { - cnonce.Append(hexChar[(int)(15.0 * rand() / (RAND_MAX + 1.0))]); + nsTArray<uint8_t> cnonceBuf; + cnonceBuf.SetLength(StaticPrefs::network_http_digest_auth_cnonce_length() / + 2); + PK11_GenerateRandom(reinterpret_cast<unsigned char*>(cnonceBuf.Elements()), + cnonceBuf.Length()); + for (auto byte : cnonceBuf) { + cnonce.AppendPrintf("%02x", byte); } LOG((" cnonce=%s\n", cnonce.get())); diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index 4861b45466..b6440c88b5 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -714,6 +714,34 @@ nsresult nsHttpHandler::GenerateHostPort(const nsCString& host, int32_t port, return NS_GenerateHostPort(host, port, hostLine); } +// static +uint8_t nsHttpHandler::UrgencyFromCoSFlags(uint32_t cos) { + uint8_t urgency; + if (cos & nsIClassOfService::UrgentStart) { + // coming from an user interaction => response should be the highest + // priority + urgency = 1; + } else if (cos & nsIClassOfService::Leader) { + // main html document normal priority + urgency = 2; + } else if (cos & nsIClassOfService::Unblocked) { + urgency = 3; + } else if (cos & nsIClassOfService::Follower) { + urgency = 4; + } else if (cos & nsIClassOfService::Speculative) { + urgency = 6; + } else if (cos & nsIClassOfService::Background) { + // background tasks can be deprioritzed to the lowest priority + urgency = 6; + } else if (cos & nsIClassOfService::Tail) { + urgency = 6; + } else { + // all others get a lower priority than the main html document + urgency = 4; + } + return urgency; +} + //----------------------------------------------------------------------------- // nsHttpHandler <private> //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/nsHttpHandler.h b/netwerk/protocol/http/nsHttpHandler.h index 2562d0c833..65ce5d6d12 100644 --- a/netwerk/protocol/http/nsHttpHandler.h +++ b/netwerk/protocol/http/nsHttpHandler.h @@ -429,6 +429,8 @@ class nsHttpHandler final : public nsIHttpProtocolHandler, int32_t port, nsACString& hostLine); + static uint8_t UrgencyFromCoSFlags(uint32_t cos); + SpdyInformation* SpdyInfo() { return &mSpdyInfo; } bool IsH2MandatorySuiteEnabled() { return mH2MandatorySuiteEnabled; } diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index 558de8e6ea..24ef50fb85 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -1684,16 +1684,16 @@ void nsHttpTransaction::Close(nsresult reason) { switch (mHttpVersion) { case HttpVersion::v1_0: case HttpVersion::v1_1: - glean::networking::http_1_download_throughput.AccumulateSamples( - {mpbs}); + glean::networking::http_1_download_throughput.AccumulateSingleSample( + mpbs); break; case HttpVersion::v2_0: - glean::networking::http_2_download_throughput.AccumulateSamples( - {mpbs}); + glean::networking::http_2_download_throughput.AccumulateSingleSample( + mpbs); break; case HttpVersion::v3_0: - glean::networking::http_3_download_throughput.AccumulateSamples( - {mpbs}); + glean::networking::http_3_download_throughput.AccumulateSingleSample( + mpbs); break; default: break; @@ -3574,42 +3574,42 @@ void nsHttpTransaction::CollectTelemetryForUploads() { switch (mHttpVersion) { case HttpVersion::v1_0: case HttpVersion::v1_1: - glean::networking::http_1_upload_throughput.AccumulateSamples({mpbs}); + glean::networking::http_1_upload_throughput.AccumulateSingleSample(mpbs); if (mRequestSize <= TELEMETRY_REQUEST_SIZE_50M) { - glean::networking::http_1_upload_throughput_10_50.AccumulateSamples( - {mpbs}); + glean::networking::http_1_upload_throughput_10_50 + .AccumulateSingleSample(mpbs); } else if (mRequestSize <= TELEMETRY_REQUEST_SIZE_100M) { - glean::networking::http_1_upload_throughput_50_100.AccumulateSamples( - {mpbs}); + glean::networking::http_1_upload_throughput_50_100 + .AccumulateSingleSample(mpbs); } else { - glean::networking::http_1_upload_throughput_100.AccumulateSamples( - {mpbs}); + glean::networking::http_1_upload_throughput_100.AccumulateSingleSample( + mpbs); } break; case HttpVersion::v2_0: - glean::networking::http_2_upload_throughput.AccumulateSamples({mpbs}); + glean::networking::http_2_upload_throughput.AccumulateSingleSample(mpbs); if (mRequestSize <= TELEMETRY_REQUEST_SIZE_50M) { - glean::networking::http_2_upload_throughput_10_50.AccumulateSamples( - {mpbs}); + glean::networking::http_2_upload_throughput_10_50 + .AccumulateSingleSample(mpbs); } else if (mRequestSize <= TELEMETRY_REQUEST_SIZE_100M) { - glean::networking::http_2_upload_throughput_50_100.AccumulateSamples( - {mpbs}); + glean::networking::http_2_upload_throughput_50_100 + .AccumulateSingleSample(mpbs); } else { - glean::networking::http_2_upload_throughput_100.AccumulateSamples( - {mpbs}); + glean::networking::http_2_upload_throughput_100.AccumulateSingleSample( + mpbs); } break; case HttpVersion::v3_0: - glean::networking::http_3_upload_throughput.AccumulateSamples({mpbs}); + glean::networking::http_3_upload_throughput.AccumulateSingleSample(mpbs); if (mRequestSize <= TELEMETRY_REQUEST_SIZE_50M) { - glean::networking::http_3_upload_throughput_10_50.AccumulateSamples( - {mpbs}); + glean::networking::http_3_upload_throughput_10_50 + .AccumulateSingleSample(mpbs); } else if (mRequestSize <= TELEMETRY_REQUEST_SIZE_100M) { - glean::networking::http_3_upload_throughput_50_100.AccumulateSamples( - {mpbs}); + glean::networking::http_3_upload_throughput_50_100 + .AccumulateSingleSample(mpbs); } else { - glean::networking::http_3_upload_throughput_100.AccumulateSamples( - {mpbs}); + glean::networking::http_3_upload_throughput_100.AccumulateSingleSample( + mpbs); } break; default: diff --git a/netwerk/protocol/http/nsIHttpActivityObserver.idl b/netwerk/protocol/http/nsIHttpActivityObserver.idl index 533e6af135..1a2cea84ba 100644 --- a/netwerk/protocol/http/nsIHttpActivityObserver.idl +++ b/netwerk/protocol/http/nsIHttpActivityObserver.idl @@ -196,9 +196,9 @@ interface nsIHttpActivityDistributor : nsIHttpActivityObserver /** * C++ friendly getter */ - [noscript, notxpcom] bool Activated(); - [noscript, notxpcom] bool ObserveProxyResponseEnabled(); - [noscript, notxpcom] bool ObserveConnectionEnabled(); + [noscript, notxpcom] boolean Activated(); + [noscript, notxpcom] boolean ObserveProxyResponseEnabled(); + [noscript, notxpcom] boolean ObserveConnectionEnabled(); /** * When true, the ACTIVITY_SUBTYPE_PROXY_RESPONSE_HEADER will be sent to diff --git a/netwerk/protocol/http/nsIHttpAuthManager.idl b/netwerk/protocol/http/nsIHttpAuthManager.idl index 5acd652942..cf39a03e34 100644 --- a/netwerk/protocol/http/nsIHttpAuthManager.idl +++ b/netwerk/protocol/http/nsIHttpAuthManager.idl @@ -63,7 +63,7 @@ interface nsIHttpAuthManager : nsISupports out AString aUserDomain, out AString aUserName, out AString aUserPassword, - [optional] in bool aIsPrivate, + [optional] in boolean aIsPrivate, [optional] in nsIPrincipal aPrincipal); /** diff --git a/netwerk/protocol/http/nsIHttpChannel.idl b/netwerk/protocol/http/nsIHttpChannel.idl index 7ed707eacf..1bd7aeba37 100644 --- a/netwerk/protocol/http/nsIHttpChannel.idl +++ b/netwerk/protocol/http/nsIHttpChannel.idl @@ -204,7 +204,7 @@ interface nsIHttpChannel : nsIIdentChannel * Call this method to see if we need to strip the request body headers * for the new http channel. This should be called during redirection. */ - [must_use] bool ShouldStripRequestBodyHeader(in ACString aMethod); + [must_use] boolean ShouldStripRequestBodyHeader(in ACString aMethod); /** * This attribute of the channel indicates whether or not diff --git a/netwerk/protocol/http/nsIHttpChannelInternal.idl b/netwerk/protocol/http/nsIHttpChannelInternal.idl index 1650b8f35c..64f41be28b 100644 --- a/netwerk/protocol/http/nsIHttpChannelInternal.idl +++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl @@ -105,7 +105,7 @@ interface nsIHttpChannelInternal : nsISupports * Returns true in case this channel is used for auth; * (the response header includes 'www-authenticate'). */ - [noscript, must_use] readonly attribute bool isAuthChannel; + [noscript, must_use] readonly attribute boolean isAuthChannel; /** * This flag is set to force relevant cookies to be sent with this load @@ -381,7 +381,8 @@ interface nsIHttpChannelInternal : nsISupports */ [noscript, notxpcom, nostdcall] void setCorsPreflightParameters(in CStringArrayRef unsafeHeaders, - in boolean shouldStripRequestBodyHeader); + in boolean shouldStripRequestBodyHeader, + in boolean shouldStripAuthHeader); [noscript, notxpcom, nostdcall] void setAltDataForChild(in boolean aIsForChild); @@ -457,7 +458,7 @@ interface nsIHttpChannelInternal : nsISupports in nsILoadInfo_CrossOriginOpenerPolicy aInitiatorPolicy); [noscript] - bool hasCrossOriginOpenerPolicyMismatch(); + boolean hasCrossOriginOpenerPolicyMismatch(); [noscript] nsILoadInfo_CrossOriginEmbedderPolicy getResponseEmbedderPolicy(in boolean aIsOriginTrialCoepCredentiallessEnabled); diff --git a/netwerk/protocol/http/nsIWellKnownOpportunisticUtils.idl b/netwerk/protocol/http/nsIWellKnownOpportunisticUtils.idl index fa90891172..366b17fdd4 100644 --- a/netwerk/protocol/http/nsIWellKnownOpportunisticUtils.idl +++ b/netwerk/protocol/http/nsIWellKnownOpportunisticUtils.idl @@ -19,5 +19,5 @@ interface nsIWellKnownOpportunisticUtils : nsISupports [must_use] void verify(in ACString aJSON, in ACString aOrigin); - [must_use] readonly attribute bool valid; + [must_use] readonly attribute boolean valid; }; |