diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 5af831570b44..c48375c3b396 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -3130,8 +3130,9 @@ bool HttpBaseChannel::ShouldBlockOpaqueResponse() const { } OpaqueResponse HttpBaseChannel::BlockOrFilterOpaqueResponse( - OpaqueResponseBlocker* aORB, const nsAString& aReason, const char* aFormat, - ...) { + OpaqueResponseBlocker* aORB, const nsAString& aReason, + const OpaqueResponseBlockedTelemetryReason aTelemetryReason, + const char* aFormat, ...) { const bool shouldFilter = ShouldFilterOpaqueResponse(OpaqueResponseFilterFetch::BlockedByORB); @@ -3145,6 +3146,8 @@ OpaqueResponse HttpBaseChannel::BlockOrFilterOpaqueResponse( } if (shouldFilter) { + Telemetry::AccumulateCategorical( + Telemetry::LABELS_ORB_BLOCK_INITIATOR::FILTERED_FETCH); // The existence of `mORB` depends on `BlockOrFilterOpaqueResponse` being // called before or after sniffing has completed. // Another requirement is that `OpaqueResponseFilter` must come after @@ -3160,7 +3163,7 @@ OpaqueResponse HttpBaseChannel::BlockOrFilterOpaqueResponse( return OpaqueResponse::Allow; } - LogORBError(aReason); + LogORBError(aReason, aTelemetryReason); return OpaqueResponse::Block; } @@ -3241,12 +3244,14 @@ HttpBaseChannel::PerformOpaqueResponseSafelistCheckBeforeSniff() { case OpaqueResponseBlockedReason::BLOCKED_BLOCKLISTED_NEVER_SNIFFED: return BlockOrFilterOpaqueResponse( mORB, u"mimeType is an opaque-blocklisted-never-sniffed MIME type"_ns, + OpaqueResponseBlockedTelemetryReason::MIME_NEVER_SNIFFED, "BLOCKED_BLOCKLISTED_NEVER_SNIFFED"); case OpaqueResponseBlockedReason::BLOCKED_206_AND_BLOCKLISTED: // Step 3.3 return BlockOrFilterOpaqueResponse( mORB, u"response's status is 206 and mimeType is an opaque-blocklisted MIME type"_ns, + OpaqueResponseBlockedTelemetryReason::RESP_206_BLCLISTED, "BLOCKED_206_AND_BLOCKEDLISTED"); case OpaqueResponseBlockedReason:: BLOCKED_NOSNIFF_AND_EITHER_BLOCKLISTED_OR_TEXTPLAIN: @@ -3254,6 +3259,7 @@ HttpBaseChannel::PerformOpaqueResponseSafelistCheckBeforeSniff() { return BlockOrFilterOpaqueResponse( mORB, u"nosniff is true and mimeType is an opaque-blocklisted MIME type or its essence is 'text/plain'"_ns, + OpaqueResponseBlockedTelemetryReason::NOSNIFF_BLC_OR_TEXTP, "BLOCKED_NOSNIFF_AND_EITHER_BLOCKLISTED_OR_TEXTPLAIN"); default: break; @@ -3277,6 +3283,7 @@ HttpBaseChannel::PerformOpaqueResponseSafelistCheckBeforeSniff() { !IsFirstPartialResponse(*mResponseHead)) { return BlockOrFilterOpaqueResponse( mORB, u"response status is 206 and not first partial response"_ns, + OpaqueResponseBlockedTelemetryReason::RESP_206_BLCLISTED, "Is not a valid partial response given 0"); } @@ -3332,14 +3339,17 @@ OpaqueResponse HttpBaseChannel::PerformOpaqueResponseSafelistCheckAfterSniff( bool isMediaRequest; mLoadInfo->GetIsMediaRequest(&isMediaRequest); if (isMediaRequest) { - return BlockOrFilterOpaqueResponse(mORB, u"after sniff: media request"_ns, - "media request"); + return BlockOrFilterOpaqueResponse( + mORB, u"after sniff: media request"_ns, + OpaqueResponseBlockedTelemetryReason::AFTER_SNIFF_MEDIA, + "media request"); } // Step 11 if (aNoSniff) { - return BlockOrFilterOpaqueResponse(mORB, u"after sniff: nosniff is true"_ns, - "nosniff"); + return BlockOrFilterOpaqueResponse( + mORB, u"after sniff: nosniff is true"_ns, + OpaqueResponseBlockedTelemetryReason::AFTER_SNIFF_NOSNIFF, "nosniff"); } // Step 12 @@ -3347,6 +3357,7 @@ OpaqueResponse HttpBaseChannel::PerformOpaqueResponseSafelistCheckAfterSniff( (mResponseHead->Status() < 200 || mResponseHead->Status() > 299)) { return BlockOrFilterOpaqueResponse( mORB, u"after sniff: status code is not in allowed range"_ns, + OpaqueResponseBlockedTelemetryReason::AFTER_SNIFF_STA_CODE, "status code (%d) is not allowed", mResponseHead->Status()); } @@ -3363,6 +3374,7 @@ OpaqueResponse HttpBaseChannel::PerformOpaqueResponseSafelistCheckAfterSniff( return BlockOrFilterOpaqueResponse( mORB, u"after sniff: content-type declares image/video/audio, but sniffing fails"_ns, + OpaqueResponseBlockedTelemetryReason::AFTER_SNIFF_CT_FAIL, "ContentType is image/video/audio"); } @@ -3373,9 +3385,11 @@ bool HttpBaseChannel::NeedOpaqueResponseAllowedCheckAfterSniff() const { return mORB ? mORB->IsSniffing() : false; } -void HttpBaseChannel::BlockOpaqueResponseAfterSniff(const nsAString& aReason) { +void HttpBaseChannel::BlockOpaqueResponseAfterSniff( + const nsAString& aReason, + const OpaqueResponseBlockedTelemetryReason aTelemetryReason) { MOZ_DIAGNOSTIC_ASSERT(mORB); - LogORBError(aReason); + LogORBError(aReason, aTelemetryReason); mORB->BlockResponse(this, NS_ERROR_FAILURE); } @@ -6191,7 +6205,9 @@ HttpBaseChannel::GetIsProxyUsed(bool* aIsProxyUsed) { return NS_OK; } -void HttpBaseChannel::LogORBError(const nsAString& aReason) { +void HttpBaseChannel::LogORBError( + const nsAString& aReason, + const OpaqueResponseBlockedTelemetryReason aTelemetryReason) { RefPtr doc; mLoadInfo->GetLoadingDocument(getter_AddRefs(doc)); @@ -6215,6 +6231,33 @@ void HttpBaseChannel::LogORBError(const nsAString& aReason) { nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "ORB"_ns, doc, nsContentUtils::eNECKO_PROPERTIES, "ResourceBlockedORB", params); + + Telemetry::LABELS_ORB_BLOCK_REASON label{ + static_cast(aTelemetryReason)}; + Telemetry::AccumulateCategorical(label); + + switch (mLoadInfo->GetExternalContentPolicyType()) { + case ExtContentPolicy::TYPE_FETCH: + Telemetry::AccumulateCategorical( + Telemetry::LABELS_ORB_BLOCK_INITIATOR::BLOCKED_FETCH); + break; + case ExtContentPolicy::TYPE_IMAGE: + Telemetry::AccumulateCategorical( + Telemetry::LABELS_ORB_BLOCK_INITIATOR::IMAGE); + break; + case ExtContentPolicy::TYPE_SCRIPT: + Telemetry::AccumulateCategorical( + Telemetry::LABELS_ORB_BLOCK_INITIATOR::SCRIPT); + break; + case ExtContentPolicy::TYPE_MEDIA: + Telemetry::AccumulateCategorical( + Telemetry::LABELS_ORB_BLOCK_INITIATOR::MEDIA); + break; + default: + Telemetry::AccumulateCategorical( + Telemetry::LABELS_ORB_BLOCK_INITIATOR::OTHER); + break; + } } NS_IMETHODIMP HttpBaseChannel::SetEarlyHintLinkType( diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index de6908e265f1..9e8373fe09bb 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -70,7 +70,6 @@ namespace net { extern mozilla::LazyLogModule gHttpLog; class OpaqueResponseBlocker; -class OpaqueResponseBlockingInfo; class PreferredAlternativeDataTypeParams; enum CacheDisposition : uint8_t { @@ -459,7 +458,8 @@ class HttpBaseChannel : public nsHashPropertyBag, [[nodiscard]] nsresult OverrideSecurityInfo( nsITransportSecurityInfo* aSecurityInfo); - void LogORBError(const nsAString& aReason); + void LogORBError(const nsAString& aReason, + const OpaqueResponseBlockedTelemetryReason aTelemetryReason); public: /* Necko internal use only... */ int64_t GetAltDataLength() { return mAltDataLength; } @@ -655,9 +655,10 @@ class HttpBaseChannel : public nsHashPropertyBag, bool ShouldFilterOpaqueResponse(OpaqueResponseFilterFetch aFilterType) const; bool ShouldBlockOpaqueResponse() const; - OpaqueResponse BlockOrFilterOpaqueResponse(OpaqueResponseBlocker* aORB, - const nsAString& aReason, - const char* aFormat, ...); + OpaqueResponse BlockOrFilterOpaqueResponse( + OpaqueResponseBlocker* aORB, const nsAString& aReason, + const OpaqueResponseBlockedTelemetryReason aTelemetryReason, + const char* aFormat, ...); OpaqueResponse PerformOpaqueResponseSafelistCheckBeforeSniff(); @@ -665,7 +666,9 @@ class HttpBaseChannel : public nsHashPropertyBag, const nsACString& aContentType, bool aNoSniff); bool NeedOpaqueResponseAllowedCheckAfterSniff() const; - void BlockOpaqueResponseAfterSniff(const nsAString& aReason); + void BlockOpaqueResponseAfterSniff( + const nsAString& aReason, + const OpaqueResponseBlockedTelemetryReason aTelemetryReason); void AllowOpaqueResponseAfterSniff(); void SetChannelBlockedByOpaqueResponse(); bool Http3Allowed() const; diff --git a/netwerk/protocol/http/OpaqueResponseUtils.cpp b/netwerk/protocol/http/OpaqueResponseUtils.cpp index a664236bb577..50954d23908a 100644 --- a/netwerk/protocol/http/OpaqueResponseUtils.cpp +++ b/netwerk/protocol/http/OpaqueResponseUtils.cpp @@ -436,7 +436,9 @@ OpaqueResponseBlocker::EnsureOpaqueResponseIsAllowedAfterJavaScriptValidation( } return aChannel->BlockOrFilterOpaqueResponse( - this, u"Javascript validation failed"_ns, "Javascript validation failed"); + this, u"Javascript validation failed"_ns, + OpaqueResponseBlockedTelemetryReason::JS_VALIDATION_FAILED, + "Javascript validation failed"); } static void RecordTelemetry(const TimeStamp& aStartOfValidation, diff --git a/netwerk/protocol/http/OpaqueResponseUtils.h b/netwerk/protocol/http/OpaqueResponseUtils.h index 111fb43ca8ff..021a0d92c4f8 100644 --- a/netwerk/protocol/http/OpaqueResponseUtils.h +++ b/netwerk/protocol/http/OpaqueResponseUtils.h @@ -47,6 +47,20 @@ enum class OpaqueResponseBlockedReason : uint32_t { BLOCKED_SHOULD_SNIFF }; +enum class OpaqueResponseBlockedTelemetryReason : uint32_t { + MIME_NEVER_SNIFFED, + RESP_206_BLCLISTED, + NOSNIFF_BLC_OR_TEXTP, + RESP_206_NO_FIRST, + AFTER_SNIFF_MEDIA, + AFTER_SNIFF_NOSNIFF, + AFTER_SNIFF_STA_CODE, + AFTER_SNIFF_CT_FAIL, + MEDIA_NOT_INITIAL, + MEDIA_INCORRECT_RESP, + JS_VALIDATION_FAILED +}; + enum class OpaqueResponse { Block, Allow, SniffCompressed, Sniff }; OpaqueResponseBlockedReason GetOpaqueResponseBlockedReason( diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index 8f7980ac87e9..40543aa443ee 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -9854,14 +9854,16 @@ void nsHttpChannel::DisableIsOpaqueResponseAllowedAfterSniffCheck( if (!isInitialRequest) { // Step 8.1 BlockOpaqueResponseAfterSniff( - u"media request after sniffing, but not initial request"_ns); + u"media request after sniffing, but not initial request"_ns, + OpaqueResponseBlockedTelemetryReason::MEDIA_NOT_INITIAL); return; } if (mResponseHead->Status() != 200 && mResponseHead->Status() != 206) { // Step 8.2 BlockOpaqueResponseAfterSniff( - u"media request's response status is neither 200 nor 206"_ns); + u"media request's response status is neither 200 nor 206"_ns, + OpaqueResponseBlockedTelemetryReason::MEDIA_INCORRECT_RESP); return; } } diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index f52755c26ff1..c5bb13a78acb 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -18144,6 +18144,45 @@ "bug_numbers": [1812051], "description": "If any opaque response was blocked for a given top-level window context." }, + "ORB_BLOCK_REASON": { + "record_in_processes": ["main"], + "products": ["firefox"], + "alert_emails": ["sefeng@mozilla.com", "afarre@mozilla.com"], + "expires_in_version": "never", + "kind": "categorical", + "labels": [ + "MIME_NEVER_SNIFFED", + "RESP_206_BLCLISTED", + "NOSNIFF_BLC_OR_TEXTP", + "RESP_206_NO_FIRST", + "AFTER_SNIFF_MEDIA", + "AFTER_SNIFF_NOSNIFF", + "AFTER_SNIFF_STA_CODE", + "AFTER_SNIFF_CT_FAIL", + "MEDIA_NOT_INITIAL", + "MEDIA_INCORRECT_RESP", + "JS_VALIDATION_FAILED" + ], + "bug_numbers": [1833216], + "description": "The reason of why this request was blocked by ORB" + }, + "ORB_BLOCK_INITIATOR": { + "record_in_processes": ["main"], + "products": ["firefox"], + "alert_emails": ["sefeng@mozilla.com", "afarre@mozilla.com"], + "expires_in_version": "never", + "kind": "categorical", + "labels": [ + "FILTERED_FETCH", + "BLOCKED_FETCH", + "IMAGE", + "SCRIPT", + "MEDIA", + "OTHER" + ], + "bug_numbers": [1833216], + "description": "The initiator of this ORB blocked request." + }, "EVENT_LONGTASK": { "record_in_processes": ["main", "content"], "products": ["firefox", "fennec"],