From e56e5d6cb123858b7fe9b2613b690926c33a3bed Mon Sep 17 00:00:00 2001 From: Moonchild Date: Tue, 12 Aug 2025 16:18:38 +0200 Subject: [PATCH 1/6] Issue #2258 - Part 1: Support XCTO:nosniff when navigating. --- ipc/glue/BackgroundUtils.cpp | 4 ++- netwerk/base/LoadInfo.cpp | 18 +++++++++- netwerk/base/LoadInfo.h | 4 ++- netwerk/base/nsILoadInfo.idl | 9 +++++ netwerk/base/nsNetUtil.cpp | 10 ++++++ netwerk/ipc/NeckoChannelParams.ipdlh | 1 + netwerk/protocol/http/nsHttpChannel.cpp | 11 ++++++ .../converters/nsUnknownDecoder.cpp | 36 ++++++++++++++++++- parser/html/nsHtml5StreamParser.cpp | 10 +++++- parser/html/nsHtml5StreamParser.h | 5 +++ 10 files changed, 103 insertions(+), 5 deletions(-) diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp index 587b70faa5..036b38f985 100644 --- a/ipc/glue/BackgroundUtils.cpp +++ b/ipc/glue/BackgroundUtils.cpp @@ -295,6 +295,7 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo, aLoadInfo->GetForcePreflight(), aLoadInfo->GetIsPreflight(), aLoadInfo->GetLoadTriggeredFromExternal(), + aLoadInfo->GetSkipContentSniffing(), aLoadInfo->GetIsFromProcessingFrameAttributes() ); @@ -372,7 +373,8 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs, loadInfoArgs.corsUnsafeHeaders(), loadInfoArgs.forcePreflight(), loadInfoArgs.isPreflight(), - loadInfoArgs.loadTriggeredFromExternal() + loadInfoArgs.loadTriggeredFromExternal(), + loadInfoArgs.skipContentSniffing() ); if (loadInfoArgs.isFromProcessingFrameAttributes()) { diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index 54f59c8252..9b3532a8c5 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -66,6 +66,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, , mForcePreflight(false) , mIsPreflight(false) , mLoadTriggeredFromExternal(false) + , mSkipContentSniffing(false) , mIsFromProcessingFrameAttributes(false) { MOZ_ASSERT(mLoadingPrincipal); @@ -241,6 +242,7 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow, , mForcePreflight(false) , mIsPreflight(false) , mLoadTriggeredFromExternal(false) + , mSkipContentSniffing(false) , mIsFromProcessingFrameAttributes(false) { // Top-level loads are never third-party @@ -305,6 +307,7 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) , mForcePreflight(rhs.mForcePreflight) , mIsPreflight(rhs.mIsPreflight) , mLoadTriggeredFromExternal(rhs.mLoadTriggeredFromExternal) + , mSkipContentSniffing(rhs.mSkipContentSniffing) , mIsFromProcessingFrameAttributes(rhs.mIsFromProcessingFrameAttributes) { } @@ -333,7 +336,8 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, const nsTArray& aCorsUnsafeHeaders, bool aForcePreflight, bool aIsPreflight, - bool aLoadTriggeredFromExternal) + bool aLoadTriggeredFromExternal, + bool aSkipContentSniffing) : mLoadingPrincipal(aLoadingPrincipal) , mTriggeringPrincipal(aTriggeringPrincipal) , mPrincipalToInherit(aPrincipalToInherit) @@ -357,6 +361,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, , mForcePreflight(aForcePreflight) , mIsPreflight(aIsPreflight) , mLoadTriggeredFromExternal(aLoadTriggeredFromExternal) + , mSkipContentSniffing(aSkipContentSniffing) , mIsFromProcessingFrameAttributes(false) { // Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal @@ -965,6 +970,17 @@ LoadInfo::MaybeIncreaseTainting(uint32_t aTainting) return NS_OK; } +NS_IMETHODIMP +LoadInfo::GetSkipContentSniffing(bool* aSkipContentSniffing) { + *aSkipContentSniffing = mSkipContentSniffing; + return NS_OK; +} + +NS_IMETHODIMP +LoadInfo::SetSkipContentSniffing(bool aSkipContentSniffing) { + mSkipContentSniffing = aSkipContentSniffing; + return NS_OK; +} NS_IMETHODIMP LoadInfo::GetIsTopLevelLoad(bool *aResult) { diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index 24dc83a59d..7edfc044c4 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -111,7 +111,8 @@ private: const nsTArray& aUnsafeHeaders, bool aForcePreflight, bool aIsPreflight, - bool aLoadTriggeredFromExternal); + bool aLoadTriggeredFromExternal, + bool aSkipContentSniffing); LoadInfo(const LoadInfo& rhs); friend nsresult @@ -157,6 +158,7 @@ private: bool mForcePreflight; bool mIsPreflight; bool mLoadTriggeredFromExternal; + bool mSkipContentSniffing; // Is true if this load was triggered by processing the attributes of the // browsing context container. diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl index 4baa8a682c..41c2ac09bb 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -367,6 +367,15 @@ interface nsILoadInfo : nsISupports */ [infallible] readonly attribute unsigned long securityMode; + + /** + * This flag is used for any browsing context where we should not sniff + * the content type. E.g if an iframe has the XCTO nosniff header, then + * that flag is set to true so we skip content sniffing for that browsing + * context. + */ + [infallible] attribute boolean skipContentSniffing; + /** * True if this request is embedded in a context that can't be third-party * (i.e. an iframe embedded in a cross-origin parent window). If this is diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index ce62cfa8fc..d6db22098a 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -2129,6 +2129,16 @@ NS_SniffContent(const char *aSnifferType, nsIRequest *aRequest, const uint8_t *aData, uint32_t aLength, nsACString &aSniffedType) { + // In case XCTO nosniff was present, we could just skip sniffing here + nsCOMPtr channel = do_QueryInterface(aRequest); + if (channel) { + nsCOMPtr loadInfo = channel->GetLoadInfo(); + if (loadInfo->GetSkipContentSniffing()) { + aSniffedType.Truncate(); + return; + } + } + typedef nsCategoryCache ContentSnifferCache; extern ContentSnifferCache* gNetSniffers; extern ContentSnifferCache* gDataSniffers; diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh index 91265b8953..038382f94d 100644 --- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -55,6 +55,7 @@ struct LoadInfoArgs bool forcePreflight; bool isPreflight; bool loadTriggeredFromExternal; + bool skipContentSniffing; bool isFromProcessingFrameAttributes; }; diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index f83c2ef90b..c28606982e 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -14,6 +14,7 @@ #include "nsHttp.h" #include "nsHttpChannel.h" #include "nsHttpHandler.h" +#include "nsString.h" #include "nsIApplicationCacheService.h" #include "nsIApplicationCacheContainer.h" #include "nsICacheStorageService.h" @@ -1100,6 +1101,16 @@ ProcessXCTO(nsIURI* aURI, nsHttpResponseHead* aResponseHead, nsILoadInfo* aLoadI ReportTypeBlocking(aURI, aLoadInfo, "MimeTypeMismatch"); return NS_ERROR_CORRUPTED_CONTENT; } + auto policyType = aLoadInfo->GetExternalContentPolicyType(); + if (policyType == nsIContentPolicy::TYPE_DOCUMENT || + policyType == nsIContentPolicy::TYPE_SUBDOCUMENT) { + // If the header XCTO nosniff is set for any browsing context, then + // we set the skipContentSniffing flag on the Loadinfo. Within + // NS_SniffContent we then bail early and do not do any sniffing. + aLoadInfo->SetSkipContentSniffing(true); + return NS_OK; + } + return NS_OK; } diff --git a/netwerk/streamconv/converters/nsUnknownDecoder.cpp b/netwerk/streamconv/converters/nsUnknownDecoder.cpp index 6382a9cb6f..f12f02b4f8 100644 --- a/netwerk/streamconv/converters/nsUnknownDecoder.cpp +++ b/netwerk/streamconv/converters/nsUnknownDecoder.cpp @@ -315,6 +315,12 @@ nsUnknownDecoder::GetMIMETypeFromContent(nsIRequest* aRequest, uint32_t aLength, nsACString& type) { + // Note: This is only used by sniffer, therefore we do not need to lock anything here. + nsCOMPtr channel(do_QueryInterface(aRequest)); + nsCOMPtr loadInfo = channel->GetLoadInfo(); + if (loadInfo->GetSkipContentSniffing()) { + return NS_OK; + } mBuffer = const_cast(reinterpret_cast(aData)); mBufferLen = aLength; DetermineContentType(aRequest); @@ -345,6 +351,11 @@ bool nsUnknownDecoder::AllowSniffing(nsIRequest* aRequest) return false; } + nsCOMPtr loadInfo = channel->GetLoadInfo(); + if (loadInfo->GetSkipContentSniffing()) { + return false; + } + bool isLocalFile = false; if (NS_FAILED(uri->SchemeIs("file", &isLocalFile)) || isLocalFile) { return false; @@ -391,10 +402,17 @@ void nsUnknownDecoder::DetermineContentType(nsIRequest* aRequest) NS_ASSERTION(mContentType.IsEmpty(), "Content type is already known."); if (!mContentType.IsEmpty()) return; + nsCOMPtr channel(do_QueryInterface(aRequest)); + if (channel) { + nsCOMPtr loadInfo = channel->GetLoadInfo(); + if (loadInfo->GetSkipContentSniffing()) { + return; + } + } + const char* testData = mBuffer; uint32_t testDataLen = mBufferLen; // Check if data are compressed. - nsCOMPtr channel(do_QueryInterface(aRequest)); if (channel) { nsresult rv = ConvertEncodedData(aRequest, mBuffer, mBufferLen); if (NS_SUCCEEDED(rv)) { @@ -561,6 +579,11 @@ bool nsUnknownDecoder::SniffForXML(nsIRequest* aRequest) bool nsUnknownDecoder::SniffURI(nsIRequest* aRequest) { + nsCOMPtr channel(do_QueryInterface(aRequest)); + nsCOMPtr loadInfo = channel->GetLoadInfo(); + if (loadInfo->GetSkipContentSniffing()) { + return false; + } nsCOMPtr mimeService(do_GetService("@mozilla.org/mime;1")); if (mimeService) { nsCOMPtr channel = do_QueryInterface(aRequest); @@ -592,6 +615,12 @@ bool nsUnknownDecoder::LastDitchSniff(nsIRequest* aRequest) // All we can do now is try to guess whether this is text/plain or // application/octet-stream + nsCOMPtr channel(do_QueryInterface(aRequest)); + nsCOMPtr loadInfo = channel->GetLoadInfo(); + if (loadInfo->GetSkipContentSniffing()) { + return false; + } + const char* testData; uint32_t testDataLen; if (mDecodedData.IsEmpty()) { @@ -791,6 +820,11 @@ nsBinaryDetector::DetermineContentType(nsIRequest* aRequest) return; } + nsCOMPtr loadInfo = httpChannel->GetLoadInfo(); + if (loadInfo->GetSkipContentSniffing()) { + return; + } + // It's an HTTP channel. Check for the text/plain mess nsAutoCString contentTypeHdr; httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"), diff --git a/parser/html/nsHtml5StreamParser.cpp b/parser/html/nsHtml5StreamParser.cpp index 9779aa194e..47de91ba02 100644 --- a/parser/html/nsHtml5StreamParser.cpp +++ b/parser/html/nsHtml5StreamParser.cpp @@ -166,6 +166,7 @@ nsHtml5StreamParser::nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor, , mLoadFlusher(new nsHtml5LoadFlusher(aExecutor)) , mFlushTimer(do_CreateInstance("@mozilla.org/timer;1")) , mMode(aMode) + , mSkipContentSniffing(false) { NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); mFlushTimer->SetTarget(mThread); @@ -549,7 +550,7 @@ nsHtml5StreamParser::FinalizeSniffing(const uint8_t* aFromSegment, // can be nul } // meta scan failed. - if (mCharsetSource >= kCharsetFromHintPrevDoc) { + if (!mSkipContentSniffing && mCharsetSource >= kCharsetFromHintPrevDoc) { mFeedChardet = false; return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment, aCount, aWriteCount); } @@ -874,6 +875,13 @@ nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) mObserver->OnStartRequest(aRequest, aContext); } mRequest = aRequest; + nsCOMPtr myChannel(do_QueryInterface(aRequest)); + nsCOMPtr loadInfo = myChannel->GetLoadInfo(); + mSkipContentSniffing = loadInfo->GetSkipContentSniffing(); + + if (mSkipContentSniffing) { + mFeedChardet = false; + } mStreamState = STREAM_BEING_READ; diff --git a/parser/html/nsHtml5StreamParser.h b/parser/html/nsHtml5StreamParser.h index 2560f84abb..2b48378239 100644 --- a/parser/html/nsHtml5StreamParser.h +++ b/parser/html/nsHtml5StreamParser.h @@ -561,6 +561,11 @@ class nsHtml5StreamParser : public nsICharsetDetectionObserver { */ eParserMode mMode; + /** + * Whether the parser should not sniff the content type. + */ + bool mSkipContentSniffing; + /** * The pref html5.flushtimer.initialdelay: Time in milliseconds between * the time a network buffer is seen and the timer firing when the From cca20ae131782ff5f1011c9ec7cac0e13924c287 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Tue, 12 Aug 2025 17:01:36 +0200 Subject: [PATCH 2/6] Issue #2258 - Part 2: Move XCTO:nosniff check into sniffers. This fixes a regression for the JSON viewer from part 1 as it relies on sniffing to prettify (and should carve out the exception even if `nosniff` headers are sent). No real functional changes otherwise. Just catering to a corner case. --- image/imgLoader.cpp | 7 +++++++ netwerk/base/nsNetUtil.cpp | 10 ---------- netwerk/protocol/http/nsHttpChannel.cpp | 2 +- netwerk/streamconv/converters/nsUnknownDecoder.cpp | 8 +++++--- toolkit/components/mediasniffer/nsMediaSniffer.cpp | 4 ++++ 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index d8e50cb2eb..f3e614d0a2 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -2489,6 +2489,13 @@ imgLoader::GetMIMETypeFromContent(nsIRequest* aRequest, uint32_t aLength, nsACString& aContentType) { + nsCOMPtr channel(do_QueryInterface(aRequest)); + if (channel) { + nsCOMPtr loadInfo = channel->GetLoadInfo(); + if (loadInfo->GetSkipContentSniffing()) { + return NS_ERROR_NOT_AVAILABLE; + } + } return GetMimeTypeFromContent((const char*)aContents, aLength, aContentType); } diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index d6db22098a..ce62cfa8fc 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -2129,16 +2129,6 @@ NS_SniffContent(const char *aSnifferType, nsIRequest *aRequest, const uint8_t *aData, uint32_t aLength, nsACString &aSniffedType) { - // In case XCTO nosniff was present, we could just skip sniffing here - nsCOMPtr channel = do_QueryInterface(aRequest); - if (channel) { - nsCOMPtr loadInfo = channel->GetLoadInfo(); - if (loadInfo->GetSkipContentSniffing()) { - aSniffedType.Truncate(); - return; - } - } - typedef nsCategoryCache ContentSnifferCache; extern ContentSnifferCache* gNetSniffers; extern ContentSnifferCache* gDataSniffers; diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index c28606982e..dba009ea30 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -1106,7 +1106,7 @@ ProcessXCTO(nsIURI* aURI, nsHttpResponseHead* aResponseHead, nsILoadInfo* aLoadI policyType == nsIContentPolicy::TYPE_SUBDOCUMENT) { // If the header XCTO nosniff is set for any browsing context, then // we set the skipContentSniffing flag on the Loadinfo. Within - // NS_SniffContent we then bail early and do not do any sniffing. + // GetMIMETypeFromContent we then bail early and do not do any sniffing. aLoadInfo->SetSkipContentSniffing(true); return NS_OK; } diff --git a/netwerk/streamconv/converters/nsUnknownDecoder.cpp b/netwerk/streamconv/converters/nsUnknownDecoder.cpp index f12f02b4f8..bab9b84c98 100644 --- a/netwerk/streamconv/converters/nsUnknownDecoder.cpp +++ b/netwerk/streamconv/converters/nsUnknownDecoder.cpp @@ -317,9 +317,11 @@ nsUnknownDecoder::GetMIMETypeFromContent(nsIRequest* aRequest, { // Note: This is only used by sniffer, therefore we do not need to lock anything here. nsCOMPtr channel(do_QueryInterface(aRequest)); - nsCOMPtr loadInfo = channel->GetLoadInfo(); - if (loadInfo->GetSkipContentSniffing()) { - return NS_OK; + if (channel) { + nsCOMPtr loadInfo = channel->GetLoadInfo(); + if (loadInfo->GetSkipContentSniffing()) { + return NS_ERROR_NOT_AVAILABLE; + } } mBuffer = const_cast(reinterpret_cast(aData)); mBufferLen = aLength; diff --git a/toolkit/components/mediasniffer/nsMediaSniffer.cpp b/toolkit/components/mediasniffer/nsMediaSniffer.cpp index d00dea894b..5c6fee065e 100644 --- a/toolkit/components/mediasniffer/nsMediaSniffer.cpp +++ b/toolkit/components/mediasniffer/nsMediaSniffer.cpp @@ -138,6 +138,10 @@ nsMediaSniffer::GetMIMETypeFromContent(nsIRequest* aRequest, nsACString& aSniffedType) { nsCOMPtr channel = do_QueryInterface(aRequest); if (channel) { + nsCOMPtr loadInfo = channel->GetLoadInfo(); + if (loadInfo->GetSkipContentSniffing()) { + return NS_ERROR_NOT_AVAILABLE; + } nsLoadFlags loadFlags = 0; channel->GetLoadFlags(&loadFlags); if (!(loadFlags & nsIChannel::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE)) { From 707c3e3fa89e6aa1352c50735367cde9ddc85752 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Tue, 12 Aug 2025 19:04:34 +0200 Subject: [PATCH 3/6] Issue #2258 - Part 3: Allow sniffing with XCTO:nosniff + empty MIME type. This moves the checking code back to NS_SniffContent and specifically checks requests for either: - Empty `Content-type` header, OR - A known JSON MIME type If present, sniffing is allowed despite `nosniff` because in the first case this is webmaster error (conflicting `nosniff` without MIME type would always fail, so sniff it), and in the second case we need this carveout or our json viewer will break. --- image/imgLoader.cpp | 7 ----- netwerk/base/nsNetUtil.cpp | 31 ++++++++++++++++++- netwerk/protocol/http/nsHttpChannel.cpp | 2 +- .../converters/nsUnknownDecoder.cpp | 22 ------------- .../mediasniffer/nsMediaSniffer.cpp | 4 --- 5 files changed, 31 insertions(+), 35 deletions(-) diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index f3e614d0a2..d8e50cb2eb 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -2489,13 +2489,6 @@ imgLoader::GetMIMETypeFromContent(nsIRequest* aRequest, uint32_t aLength, nsACString& aContentType) { - nsCOMPtr channel(do_QueryInterface(aRequest)); - if (channel) { - nsCOMPtr loadInfo = channel->GetLoadInfo(); - if (loadInfo->GetSkipContentSniffing()) { - return NS_ERROR_NOT_AVAILABLE; - } - } return GetMimeTypeFromContent((const char*)aContents, aLength, aContentType); } diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index ce62cfa8fc..2207e9e24d 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -16,6 +16,7 @@ #include "nsContentUtils.h" #include "nsHashKeys.h" #include "nsHttp.h" +#include "nsMimeTypes.h" #include "nsIAsyncStreamCopier.h" #include "nsIAuthPrompt.h" #include "nsIAuthPrompt2.h" @@ -2149,6 +2150,33 @@ NS_SniffContent(const char *aSnifferType, nsIRequest *aRequest, return; } + aSniffedType.Truncate(); + + nsCOMPtr channel = do_QueryInterface(aRequest); + if (channel) { + nsCOMPtr loadInfo = channel->GetLoadInfo(); + if (loadInfo->GetSkipContentSniffing()) { + // In case XCTO nosniff was present, we should skip sniffing here, but... + nsAutoCString currentContentType; + channel->GetContentType(currentContentType); + // We cannot skip sniffing if the current MIME type is a JSON file. + // The JSON-Viewer relies on its own sniffer to determine if it can render + // the page, so we need to make an exception if the Server provides a valid + // JSON MIME type (application/json, application/web-manifest or text/json). + // We also don't skip sniffing if the currently-known content type is empty, + // to deal with webmaster errors (nosniff is set but no content-type supplied) + // See Issue #2258. + if (!currentContentType.Equals(APPLICATION_JSON) && + !currentContentType.Equals(APPLICATION_WEB_MANIFEST) && + !currentContentType.Equals(TEXT_JSON) && + !currentContentType.IsEmpty()) { + // Content type supplied and it's not a JSON type; honor XCTO:nosniff. + return; + } + } + } + + // Iterate through the sniffers... nsCOMArray sniffers; cache->GetEntries(sniffers); for (int32_t i = 0; i < sniffers.Count(); ++i) { @@ -2157,8 +2185,9 @@ NS_SniffContent(const char *aSnifferType, nsIRequest *aRequest, return; } } + + // If we get here, there's nothing more to be done, return with a truncated aSniffedType. - aSniffedType.Truncate(); } bool diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index dba009ea30..c28606982e 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -1106,7 +1106,7 @@ ProcessXCTO(nsIURI* aURI, nsHttpResponseHead* aResponseHead, nsILoadInfo* aLoadI policyType == nsIContentPolicy::TYPE_SUBDOCUMENT) { // If the header XCTO nosniff is set for any browsing context, then // we set the skipContentSniffing flag on the Loadinfo. Within - // GetMIMETypeFromContent we then bail early and do not do any sniffing. + // NS_SniffContent we then bail early and do not do any sniffing. aLoadInfo->SetSkipContentSniffing(true); return NS_OK; } diff --git a/netwerk/streamconv/converters/nsUnknownDecoder.cpp b/netwerk/streamconv/converters/nsUnknownDecoder.cpp index bab9b84c98..d4aa09f2b9 100644 --- a/netwerk/streamconv/converters/nsUnknownDecoder.cpp +++ b/netwerk/streamconv/converters/nsUnknownDecoder.cpp @@ -316,13 +316,6 @@ nsUnknownDecoder::GetMIMETypeFromContent(nsIRequest* aRequest, nsACString& type) { // Note: This is only used by sniffer, therefore we do not need to lock anything here. - nsCOMPtr channel(do_QueryInterface(aRequest)); - if (channel) { - nsCOMPtr loadInfo = channel->GetLoadInfo(); - if (loadInfo->GetSkipContentSniffing()) { - return NS_ERROR_NOT_AVAILABLE; - } - } mBuffer = const_cast(reinterpret_cast(aData)); mBufferLen = aLength; DetermineContentType(aRequest); @@ -353,11 +346,6 @@ bool nsUnknownDecoder::AllowSniffing(nsIRequest* aRequest) return false; } - nsCOMPtr loadInfo = channel->GetLoadInfo(); - if (loadInfo->GetSkipContentSniffing()) { - return false; - } - bool isLocalFile = false; if (NS_FAILED(uri->SchemeIs("file", &isLocalFile)) || isLocalFile) { return false; @@ -405,13 +393,6 @@ void nsUnknownDecoder::DetermineContentType(nsIRequest* aRequest) if (!mContentType.IsEmpty()) return; nsCOMPtr channel(do_QueryInterface(aRequest)); - if (channel) { - nsCOMPtr loadInfo = channel->GetLoadInfo(); - if (loadInfo->GetSkipContentSniffing()) { - return; - } - } - const char* testData = mBuffer; uint32_t testDataLen = mBufferLen; // Check if data are compressed. @@ -583,9 +564,6 @@ bool nsUnknownDecoder::SniffURI(nsIRequest* aRequest) { nsCOMPtr channel(do_QueryInterface(aRequest)); nsCOMPtr loadInfo = channel->GetLoadInfo(); - if (loadInfo->GetSkipContentSniffing()) { - return false; - } nsCOMPtr mimeService(do_GetService("@mozilla.org/mime;1")); if (mimeService) { nsCOMPtr channel = do_QueryInterface(aRequest); diff --git a/toolkit/components/mediasniffer/nsMediaSniffer.cpp b/toolkit/components/mediasniffer/nsMediaSniffer.cpp index 5c6fee065e..d00dea894b 100644 --- a/toolkit/components/mediasniffer/nsMediaSniffer.cpp +++ b/toolkit/components/mediasniffer/nsMediaSniffer.cpp @@ -138,10 +138,6 @@ nsMediaSniffer::GetMIMETypeFromContent(nsIRequest* aRequest, nsACString& aSniffedType) { nsCOMPtr channel = do_QueryInterface(aRequest); if (channel) { - nsCOMPtr loadInfo = channel->GetLoadInfo(); - if (loadInfo->GetSkipContentSniffing()) { - return NS_ERROR_NOT_AVAILABLE; - } nsLoadFlags loadFlags = 0; channel->GetLoadFlags(&loadFlags); if (!(loadFlags & nsIChannel::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE)) { From bd734f795cad712b3fcccf928adfde410856f6ce Mon Sep 17 00:00:00 2001 From: Moonchild Date: Tue, 12 Aug 2025 19:09:07 +0200 Subject: [PATCH 4/6] Issue #2258 - Part 4: Clean up unused pointers. --- netwerk/streamconv/converters/nsUnknownDecoder.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/netwerk/streamconv/converters/nsUnknownDecoder.cpp b/netwerk/streamconv/converters/nsUnknownDecoder.cpp index d4aa09f2b9..5fe9bba442 100644 --- a/netwerk/streamconv/converters/nsUnknownDecoder.cpp +++ b/netwerk/streamconv/converters/nsUnknownDecoder.cpp @@ -562,8 +562,6 @@ bool nsUnknownDecoder::SniffForXML(nsIRequest* aRequest) bool nsUnknownDecoder::SniffURI(nsIRequest* aRequest) { - nsCOMPtr channel(do_QueryInterface(aRequest)); - nsCOMPtr loadInfo = channel->GetLoadInfo(); nsCOMPtr mimeService(do_GetService("@mozilla.org/mime;1")); if (mimeService) { nsCOMPtr channel = do_QueryInterface(aRequest); From e3de626c1f3921439da82933cd84b2d4947a338f Mon Sep 17 00:00:00 2001 From: Moonchild Date: Thu, 14 Aug 2025 17:50:18 +0200 Subject: [PATCH 5/6] Bug 1875345 - Report 24 instead of 32 as the colorDepth (and pixelDepth) on Linux (assuming 8 of 32 bits are for the alpha channel). This now matches the logic in our equivalent Windows code, and this is also per spec ("number of bits...excluding the alpha channel"): https://drafts.csswg.org/cssom-view/#dom-screen-colordepth With this change, the WPT test starts passing on Ubuntu 22.04 (which was previously flagged as an unexpected failure). --- widget/gtk/nsScreenGtk.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/widget/gtk/nsScreenGtk.cpp b/widget/gtk/nsScreenGtk.cpp index 61e6605b76..39a0620cfd 100644 --- a/widget/gtk/nsScreenGtk.cpp +++ b/widget/gtk/nsScreenGtk.cpp @@ -97,17 +97,21 @@ NS_IMETHODIMP nsScreenGtk :: GetPixelDepth(int32_t *aPixelDepth) { GdkVisual * visual = gdk_screen_get_system_visual(gdk_screen_get_default()); - *aPixelDepth = gdk_visual_get_depth(visual); - + uint32_t pixelDepth = gdk_visual_get_depth(visual); + if (pixelDepth == 32) { + // If a device reports 32 bits per pixel, it's still only using 8 bits + // per color component, which is what our callers want to know. + // (Some devices report 32 and some devices report 24, because Linux) + pixelDepth = 24; + } + *aPixelDepth = pixelDepth; return NS_OK; - } // GetPixelDepth NS_IMETHODIMP nsScreenGtk :: GetColorDepth(int32_t *aColorDepth) { return GetPixelDepth ( aColorDepth ); - } // GetColorDepth NS_IMETHODIMP From 6d47d819faaee5bb734389b46232b1a0bda9c9c6 Mon Sep 17 00:00:00 2001 From: Moonchild Date: Sun, 17 Aug 2025 09:13:02 +0200 Subject: [PATCH 6/6] Issue #2850 - Alias `:focus-visible` to `:-moz-focusring` Band-aid to have it be parsed as valid with reasonably-expected behaviour. --- layout/style/nsCSSPseudoClassList.h | 1 + 1 file changed, 1 insertion(+) diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index 196c5d9f26..f1ab538357 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -171,6 +171,7 @@ CSS_STATE_PSEUDO_CLASS(disabled, ":disabled", 0, "", NS_EVENT_STATE_DISABLED) CSS_STATE_PSEUDO_CLASS(enabled, ":enabled", 0, "", NS_EVENT_STATE_ENABLED) CSS_STATE_PSEUDO_CLASS(focus, ":focus", 0, "", NS_EVENT_STATE_FOCUS) CSS_STATE_PSEUDO_CLASS(focusWithin, ":focus-within", 0, "", NS_EVENT_STATE_FOCUS_WITHIN) +CSS_STATE_PSEUDO_CLASS(focusVisible, ":focus-visible", 0, "", NS_EVENT_STATE_FOCUSRING) CSS_STATE_PSEUDO_CLASS(hover, ":hover", 0, "", NS_EVENT_STATE_HOVER) CSS_STATE_PSEUDO_CLASS(mozDragOver, ":-moz-drag-over", 0, "", NS_EVENT_STATE_DRAGOVER) CSS_STATE_PSEUDO_CLASS(target, ":target", 0, "", NS_EVENT_STATE_URLTARGET)