Bug 1736026 - Show HTTP status code in CORS messages r=necko-reviewers,emilio,valentin
authorMichael[tm] Smith <mike@w3.org>
Thu, 21 Oct 2021 02:55:15 +0000
changeset 596540 2b65a0fbcf8bb4b0ce59905595fd1a4c579e211b
parent 596539 bfae5c0b444760a9047faa10f215e9c02d28732e
child 596541 d3ad47305d043c6d9a63b05388c206caa7726b71
push id151894
push usermarcos@marcosc.com
push dateThu, 21 Oct 2021 03:19:34 +0000
treeherderautoland@2b65a0fbcf8b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnecko-reviewers, emilio, valentin
bugs1736026
milestone95.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1736026 - Show HTTP status code in CORS messages r=necko-reviewers,emilio,valentin Differential Revision: https://phabricator.services.mozilla.com/D128596
devtools/client/webconsole/test/browser/browser_webconsole_cors_errors.js
devtools/server/actors/errordocs.js
dom/base/test/test_warning_for_blocked_cross_site_request.html
dom/locales/en-US/chrome/security/security.properties
netwerk/protocol/http/nsCORSListenerProxy.cpp
--- a/devtools/client/webconsole/test/browser/browser_webconsole_cors_errors.js
+++ b/devtools/client/webconsole/test/browser/browser_webconsole_cors_errors.js
@@ -38,41 +38,46 @@ add_task(async function() {
   makeFaultyCorsCall("CORSDisabled");
   message = await onCorsMessage;
   await checkCorsMessage(message, "CORSDisabled");
   await pushPref("content.cors.disable", false);
 
   info("Test CORSPreflightDidNotSucceed");
   onCorsMessage = waitForMessage(
     hud,
-    `CORS preflight response did not succeed`
+    `(Reason: CORS preflight response did not succeed). Status code: `
   );
   makeFaultyCorsCall("CORSPreflightDidNotSucceed");
   message = await onCorsMessage;
   await checkCorsMessage(message, "CORSPreflightDidNotSucceed");
 
   info("Test CORS did not succeed");
-  onCorsMessage = waitForMessage(hud, "Reason: CORS request did not succeed");
+  onCorsMessage = waitForMessage(
+    hud,
+    "(Reason: CORS request did not succeed). Status code: "
+  );
   makeFaultyCorsCall("CORSDidNotSucceed");
   message = await onCorsMessage;
   await checkCorsMessage(message, "CORSDidNotSucceed");
 
   info("Test CORSExternalRedirectNotAllowed");
   onCorsMessage = waitForMessage(
     hud,
     "Reason: CORS request external redirect not allowed"
   );
   makeFaultyCorsCall("CORSExternalRedirectNotAllowed");
   message = await onCorsMessage;
   await checkCorsMessage(message, "CORSExternalRedirectNotAllowed");
 
   info("Test CORSMissingAllowOrigin");
   onCorsMessage = waitForMessage(
     hud,
-    `Reason: CORS header ${quote("Access-Control-Allow-Origin")} missing`
+    `(Reason: CORS header ${quote(
+      "Access-Control-Allow-Origin"
+    )} missing). Status code: `
   );
   makeFaultyCorsCall("CORSMissingAllowOrigin");
   message = await onCorsMessage;
   await checkCorsMessage(message, "CORSMissingAllowOrigin");
 
   info("Test CORSMultipleAllowOriginNotAllowed");
   onCorsMessage = waitForMessage(
     hud,
--- a/devtools/server/actors/errordocs.js
+++ b/devtools/server/actors/errordocs.js
@@ -140,27 +140,27 @@ const ErrorCategories = {
 };
 
 const baseCorsErrorUrl =
   "https://developer.mozilla.org/docs/Web/HTTP/CORS/Errors/";
 const corsParams =
   "?utm_source=devtools&utm_medium=firefox-cors-errors&utm_campaign=default";
 const CorsErrorDocs = {
   CORSDisabled: "CORSDisabled",
-  CORSDidNotSucceed: "CORSDidNotSucceed",
+  CORSDidNotSucceed2: "CORSDidNotSucceed",
   CORSOriginHeaderNotAdded: "CORSOriginHeaderNotAdded",
   CORSExternalRedirectNotAllowed: "CORSExternalRedirectNotAllowed",
   CORSRequestNotHttp: "CORSRequestNotHttp",
-  CORSMissingAllowOrigin: "CORSMissingAllowOrigin",
+  CORSMissingAllowOrigin2: "CORSMissingAllowOrigin",
   CORSMultipleAllowOriginNotAllowed: "CORSMultipleAllowOriginNotAllowed",
   CORSAllowOriginNotMatchingOrigin: "CORSAllowOriginNotMatchingOrigin",
   CORSNotSupportingCredentials: "CORSNotSupportingCredentials",
   CORSMethodNotFound: "CORSMethodNotFound",
   CORSMissingAllowCredentials: "CORSMissingAllowCredentials",
-  CORSPreflightDidNotSucceed2: "CORSPreflightDidNotSucceed",
+  CORSPreflightDidNotSucceed3: "CORSPreflightDidNotSucceed",
   CORSInvalidAllowMethod: "CORSInvalidAllowMethod",
   CORSInvalidAllowHeader: "CORSInvalidAllowHeader",
   CORSMissingAllowHeaderFromPreflight2: "CORSMissingAllowHeaderFromPreflight",
 };
 
 const baseStorageAccessPolicyErrorUrl =
   "https://developer.mozilla.org/docs/Mozilla/Firefox/Privacy/Storage_access_policy/Errors/";
 const storageAccessPolicyParams =
--- a/dom/base/test/test_warning_for_blocked_cross_site_request.html
+++ b/dom/base/test/test_warning_for_blocked_cross_site_request.html
@@ -33,28 +33,28 @@ var tests = {
   xhr : {
     uri_test : "http://invalid",
     result : null,
     category: "CORSAllowOriginNotMatchingOrigin"
   },
   font : {
     uri_test : "font_bad",
     result : null,
-    category: "CORSMissingAllowOrigin",
+    category: "CORSMissingAllowOrigin2",
   },
   shape_outside : {
     uri_test : "bad_shape_outside",
     result : null,
-    category: "CORSMissingAllowOrigin",
+    category: "CORSMissingAllowOrigin2",
     ignore_windowID: true,
   },
   mask_image : {
     uri_test : "bad_mask_image",
     result : null,
-    category: "CORSMissingAllowOrigin",
+    category: "CORSMissingAllowOrigin2",
     ignore_windowID: true,
   },
 }
 
 function testsComplete() {
   for (var testName in tests) {
     var test = tests[testName];
     if (test.result == null) {
--- a/dom/locales/en-US/chrome/security/security.properties
+++ b/dom/locales/en-US/chrome/security/security.properties
@@ -5,27 +5,27 @@
 # Mixed Content Blocker
 # LOCALIZATION NOTE: "%1$S" is the URI of the blocked mixed content resource
 BlockMixedDisplayContent = Blocked loading mixed display content “%1$S”
 BlockMixedActiveContent = Blocked loading mixed active content “%1$S”
 
 # CORS
 # LOCALIZATION NOTE: Do not translate "Access-Control-Allow-Origin", Access-Control-Allow-Credentials, Access-Control-Allow-Methods, Access-Control-Allow-Headers
 CORSDisabled=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS disabled).
-CORSDidNotSucceed=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS request did not succeed).
+CORSDidNotSucceed2=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS request did not succeed). Status code: %2$S.
 CORSOriginHeaderNotAdded=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS header ‘Origin’ cannot be added).
 CORSExternalRedirectNotAllowed=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS request external redirect not allowed).
 CORSRequestNotHttp=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS request not http).
-CORSMissingAllowOrigin=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
+CORSMissingAllowOrigin2=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: %2$S.
 CORSMultipleAllowOriginNotAllowed=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: Multiple CORS header ‘Access-Control-Allow-Origin’ not allowed).
 CORSAllowOriginNotMatchingOrigin=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘%2$S’).
 CORSNotSupportingCredentials=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ‘%1$S’. (Reason: Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’).
 CORSMethodNotFound=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: Did not find method in CORS header ‘Access-Control-Allow-Methods’).
 CORSMissingAllowCredentials=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: expected ‘true’ in CORS header ‘Access-Control-Allow-Credentials’).
-CORSPreflightDidNotSucceed2=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS preflight response did not succeed).
+CORSPreflightDidNotSucceed3=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: CORS preflight response did not succeed). Status code: %2$S.
 CORSInvalidAllowMethod=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: invalid token ‘%2$S’ in CORS header ‘Access-Control-Allow-Methods’).
 CORSInvalidAllowHeader=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: invalid token ‘%2$S’ in CORS header ‘Access-Control-Allow-Headers’).
 CORSMissingAllowHeaderFromPreflight2=Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at %1$S. (Reason: header ‘%2$S’ is not allowed according to header ‘Access-Control-Allow-Headers’ from CORS preflight response).
 
 # LOCALIZATION NOTE: Do not translate "Strict-Transport-Security", "HSTS", "max-age" or "includeSubDomains"
 STSUnknownError=Strict-Transport-Security: An unknown error occurred processing the header specified by the site.
 STSUntrustworthyConnection=Strict-Transport-Security: The connection to the site is untrustworthy, so the specified header was ignored.
 STSCouldNotParseHeader=Strict-Transport-Security: The site specified a header that could not be parsed successfully.
--- a/netwerk/protocol/http/nsCORSListenerProxy.cpp
+++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp
@@ -54,16 +54,25 @@
 
 using namespace mozilla;
 using namespace mozilla::net;
 
 #define PREFLIGHT_CACHE_SIZE 100
 // 5 seconds is chosen to be compatible with Chromium.
 #define PREFLIGHT_DEFAULT_EXPIRY_SECONDS 5
 
+static inline nsAutoString GetStatusCodeAsString(nsIHttpChannel* aHttp) {
+  nsAutoString result;
+  uint32_t code;
+  if (NS_SUCCEEDED(aHttp->GetResponseStatus(&code))) {
+    result.AppendInt(code);
+  }
+  return result;
+}
+
 static void LogBlockedRequest(nsIRequest* aRequest, const char* aProperty,
                               const char16_t* aParam, uint32_t aBlockingReason,
                               nsIHttpChannel* aCreatingChannel) {
   nsresult rv = NS_OK;
 
   nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
 
   NS_SetRequestBlockingReason(channel, aBlockingReason);
@@ -495,26 +504,26 @@ nsresult nsCORSListenerProxy::CheckReque
                       nsILoadInfo::BLOCKING_REASON_CORSDISABLED, topChannel);
     return NS_ERROR_DOM_BAD_URI;
   }
 
   // Check if the request failed
   nsresult status;
   nsresult rv = aRequest->GetStatus(&status);
   if (NS_FAILED(rv)) {
-    LogBlockedRequest(aRequest, "CORSDidNotSucceed", nullptr,
+    LogBlockedRequest(aRequest, "CORSDidNotSucceed2", nullptr,
                       nsILoadInfo::BLOCKING_REASON_CORSDIDNOTSUCCEED,
                       topChannel);
     return rv;
   }
 
   if (NS_FAILED(status)) {
     if (NS_BINDING_ABORTED != status) {
       // Don't want to log mere cancellation as an error.
-      LogBlockedRequest(aRequest, "CORSDidNotSucceed", nullptr,
+      LogBlockedRequest(aRequest, "CORSDidNotSucceed2", nullptr,
                         nsILoadInfo::BLOCKING_REASON_CORSDIDNOTSUCCEED,
                         topChannel);
     }
     return status;
   }
 
   // Test that things worked on a HTTP level
   nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
@@ -554,17 +563,18 @@ nsresult nsCORSListenerProxy::CheckReque
         nsILoadInfo::BLOCKING_REASON_CORSMULTIPLEALLOWORIGINNOTALLOWED,
         topChannel);
     return rv;
   }
 
   rv = http->GetResponseHeader("Access-Control-Allow-Origin"_ns,
                                allowedOriginHeader);
   if (NS_FAILED(rv)) {
-    LogBlockedRequest(aRequest, "CORSMissingAllowOrigin", nullptr,
+    auto statusCode = GetStatusCodeAsString(http);
+    LogBlockedRequest(aRequest, "CORSMissingAllowOrigin2", statusCode.get(),
                       nsILoadInfo::BLOCKING_REASON_CORSMISSINGALLOWORIGIN,
                       topChannel);
     return rv;
   }
 
   // Bug 1210985 - Explicitly point out the error that the credential is
   // not supported if the allowing origin is '*'. Note that this check
   // has to be done before the condition
@@ -1052,17 +1062,18 @@ nsresult nsCORSListenerProxy::CheckPrefl
   }
 
   if (!doPreflight) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(http);
   if (!internal) {
-    LogBlockedRequest(aChannel, "CORSDidNotSucceed", nullptr,
+    auto statusCode = GetStatusCodeAsString(http);
+    LogBlockedRequest(aChannel, "CORSDidNotSucceed2", statusCode.get(),
                       nsILoadInfo::BLOCKING_REASON_CORSDIDNOTSUCCEED,
                       mHttpChannel);
     return NS_ERROR_DOM_BAD_URI;
   }
 
   internal->SetCorsPreflightParameters(
       headers.IsEmpty() ? loadInfoHeaders : headers,
       aUpdateType == UpdateType::StripRequestBodyHeader);
@@ -1295,17 +1306,18 @@ nsresult nsCORSPreflightListener::CheckP
   nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
   nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aRequest);
   NS_ENSURE_STATE(internal);
   nsCOMPtr<nsIHttpChannel> parentHttpChannel = do_QueryInterface(mCallback);
 
   bool succeedded;
   rv = http->GetRequestSucceeded(&succeedded);
   if (NS_FAILED(rv) || !succeedded) {
-    LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed2", nullptr,
+    auto statusCode = GetStatusCodeAsString(http);
+    LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed3", statusCode.get(),
                       nsILoadInfo::BLOCKING_REASON_CORSPREFLIGHTDIDNOTSUCCEED,
                       parentHttpChannel);
     return NS_ERROR_DOM_BAD_URI;
   }
 
   nsAutoCString headerVal;
   // The "Access-Control-Allow-Methods" header contains a comma separated
   // list of method names.