Bug 1475073 - Pass individual CORS errors as categories to web console error messages. r=baku, a=lizzard
authorChristoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Fri, 20 Jul 2018 19:57:41 +0200
changeset 478374 40006339de0c
parent 478373 3a49b45d3428
child 478375 e2e1d461ee93
push id9639
push userryanvm@gmail.com
push date2018-08-10 20:54 +0000
treeherdermozilla-beta@4471d22def67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku, lizzard
bugs1475073
milestone62.0
Bug 1475073 - Pass individual CORS errors as categories to web console error messages. r=baku, a=lizzard
dom/base/test/test_warning_for_blocked_cross_site_request.html
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelChild.h
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/InterceptedHttpChannel.cpp
netwerk/protocol/http/InterceptedHttpChannel.h
netwerk/protocol/http/NullHttpChannel.cpp
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/protocol/http/nsCORSListenerProxy.cpp
netwerk/protocol/http/nsCORSListenerProxy.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
netwerk/protocol/http/nsIHttpChannel.idl
netwerk/protocol/viewsource/nsViewSourceChannel.cpp
--- a/dom/base/test/test_warning_for_blocked_cross_site_request.html
+++ b/dom/base/test/test_warning_for_blocked_cross_site_request.html
@@ -22,21 +22,23 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 
 var tests = {
   font : {
     uri_test : "font_bad",
-    result : null
+    result : null,
+    category: "CORSMissingAllowOrigin",
   },
   xhr : {
     uri_test : "http://invalid",
-    result : null
+    result : null,
+    category: "CORSAllowOriginNotMatchingOrigin"
   },
 }
 
 function testsComplete() {
   for (var testName in tests) {
     var test = tests[testName];
     if (test.result == null)
       return false;
@@ -45,24 +47,26 @@ function testsComplete() {
 }
 
 SpecialPowers.registerConsoleListener(function CORSMsgListener(aMsg) {
   if (!/Cross-Origin Request Blocked/.test(aMsg.message))
     return;
 
   for (var testName in tests) {
     var test = tests[testName];
+    var category = test.category;
     if (test.result != null)
       continue;
 
     var testRegexp = new RegExp(test.uri_test);
     if (testRegexp.test(aMsg.message)) {
       test.result = true;
       ok(true, "Got \"Cross-site request blocked\" warning message for " + testName);
-      ok(aMsg.category == "CORS", "Got warning message with category \"" + aMsg.category + "\", expected \"CORS\"");
+      ok(aMsg.category == category,
+         "Got warning message with category \"" + aMsg.category + "\", expected \"" + category + "\"");
       // Got the message we wanted - make sure it is destined for a valid inner window
       ok(aMsg.windowID != 0, "Valid (non-zero) windowID for the cross-site request blocked message.");
       break;
     }
   }
 
   if (testsComplete()) {
     SimpleTest.executeSoon(cleanup);
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -3969,30 +3969,32 @@ HttpChannelChild::ActorDestroy(ActorDest
   // and BackgroundChild might have pending IPC messages.
   // Clean up BackgroundChild at this time to prevent memleak.
   if (aWhy != Deletion) {
     CleanupBackgroundChannel();
   }
 }
 
 mozilla::ipc::IPCResult
-HttpChannelChild::RecvLogBlockedCORSRequest(const nsString& aMessage)
+HttpChannelChild::RecvLogBlockedCORSRequest(const nsString& aMessage,
+                                            const nsCString& aCategory)
 {
-  Unused << LogBlockedCORSRequest(aMessage);
+  Unused << LogBlockedCORSRequest(aMessage, aCategory);
   return IPC_OK();
 }
 
 NS_IMETHODIMP
-HttpChannelChild::LogBlockedCORSRequest(const nsAString & aMessage)
+HttpChannelChild::LogBlockedCORSRequest(const nsAString & aMessage,
+                                        const nsACString& aCategory)
 {
   if (mLoadInfo) {
     uint64_t innerWindowID = mLoadInfo->GetInnerWindowID();
     bool privateBrowsing = !!mLoadInfo->GetOriginAttributes().mPrivateBrowsingId;
     nsCORSListenerProxy::LogBlockedCORSRequest(innerWindowID, privateBrowsing,
-                                               aMessage);
+                                               aMessage, aCategory);
   }
   return NS_OK;
 }
 
 void
 HttpChannelChild::MaybeCallSynthesizedCallback()
 {
   if (!mSynthesizedCallback) {
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -186,18 +186,18 @@ protected:
 
   nsresult
   AsyncCall(void (HttpChannelChild::*funcPtr)(),
             nsRunnableMethod<HttpChannelChild> **retval = nullptr) override;
 
   // Get event target for processing network events.
   already_AddRefed<nsIEventTarget> GetNeckoTarget() override;
 
-  virtual mozilla::ipc::IPCResult RecvLogBlockedCORSRequest(const nsString& aMessage) override;
-  NS_IMETHOD LogBlockedCORSRequest(const nsAString & aMessage) override;
+  virtual mozilla::ipc::IPCResult RecvLogBlockedCORSRequest(const nsString& aMessage, const nsCString& aCategory) override;
+  NS_IMETHOD LogBlockedCORSRequest(const nsAString & aMessage, const nsACString& aCategory) override;
 
 private:
   // this section is for main-thread-only object
   // all the references need to be proxy released on main thread.
   uint32_t mCacheKey;
   nsCOMPtr<nsIChildChannel> mRedirectChannelChild;
   RefPtr<InterceptStreamListener> mInterceptListener;
   // Needed to call AsyncOpen in FinishInterceptedRedirect
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -2349,19 +2349,21 @@ void
 HttpChannelParent::DoSendSetPriority(int16_t aValue)
 {
   if (!mIPCClosed) {
     Unused << SendSetPriority(aValue);
   }
 }
 
 nsresult
-HttpChannelParent::LogBlockedCORSRequest(const nsAString& aMessage)
+HttpChannelParent::LogBlockedCORSRequest(const nsAString& aMessage,
+                                         const nsACString& aCategory)
 {
   if (mIPCClosed ||
-      NS_WARN_IF(!SendLogBlockedCORSRequest(nsString(aMessage)))) {
+      NS_WARN_IF(!SendLogBlockedCORSRequest(nsString(aMessage),
+                                            nsCString(aCategory)))) {
     return NS_ERROR_UNEXPECTED;
   }
   return NS_OK;
 }
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -217,17 +217,17 @@ protected:
   void FailDiversion(nsresult aErrorCode);
 
   friend class HttpChannelParentListener;
   RefPtr<mozilla::dom::TabParent> mTabParent;
 
   MOZ_MUST_USE nsresult
   ReportSecurityMessage(const nsAString& aMessageTag,
                         const nsAString& aMessageCategory) override;
-  nsresult LogBlockedCORSRequest(const nsAString& aMessage) override;
+  nsresult LogBlockedCORSRequest(const nsAString& aMessage, const nsACString& aCategory) override;
 
   // Calls SendDeleteSelf and sets mIPCClosed to true because we should not
   // send any more messages after that. Bug 1274886
   MOZ_MUST_USE bool DoSendDeleteSelf();
   // Called to notify the parent channel to not send any more IPC messages.
   virtual mozilla::ipc::IPCResult RecvDeletingChannel() override;
   virtual mozilla::ipc::IPCResult RecvFinishInterceptedRedirect() override;
 
--- a/netwerk/protocol/http/InterceptedHttpChannel.cpp
+++ b/netwerk/protocol/http/InterceptedHttpChannel.cpp
@@ -588,17 +588,18 @@ InterceptedHttpChannel::AsyncOpen2(nsISt
   if (NS_WARN_IF(NS_FAILED(rv))) {
     Cancel(rv);
     return rv;
   }
   return AsyncOpen(listener, nullptr);
 }
 
 NS_IMETHODIMP
-InterceptedHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage)
+InterceptedHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage,
+                                              const nsACString& aCategory)
 {
   // Synthetic responses should not trigger CORS blocking.
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 InterceptedHttpChannel::SetupFallbackChannel(const char*  aFallbackKey)
 {
--- a/netwerk/protocol/http/InterceptedHttpChannel.h
+++ b/netwerk/protocol/http/InterceptedHttpChannel.h
@@ -163,17 +163,17 @@ public:
 
   NS_IMETHOD
   AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext) override;
 
   NS_IMETHOD
   AsyncOpen2(nsIStreamListener *aListener) override;
 
   NS_IMETHOD
-  LogBlockedCORSRequest(const nsAString & aMessage) override;
+  LogBlockedCORSRequest(const nsAString & aMessage, const nsACString& aCategory) override;
 
   NS_IMETHOD
   SetupFallbackChannel(const char * aFallbackKey) override;
 
   NS_IMETHOD
   SetPriority(int32_t aPriority) override;
 
   NS_IMETHOD
--- a/netwerk/protocol/http/NullHttpChannel.cpp
+++ b/netwerk/protocol/http/NullHttpChannel.cpp
@@ -901,17 +901,18 @@ NullHttpChannel::GetIsMainDocumentChanne
 
 NS_IMETHODIMP
 NullHttpChannel::SetIsMainDocumentChannel(bool aValue)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
-NullHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage)
+NullHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage,
+                                       const nsACString& aCategory)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 NullHttpChannel::SetReportResourceTiming(bool enabled) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -147,17 +147,17 @@ child:
   async DeleteSelf();
 
   // Tell the child to issue a deprecation warning.
   async IssueDeprecationWarning(uint32_t warning, bool asError);
 
   // When CORS blocks the request in the parent process, it doesn't have the
   // correct window ID, so send the message to the child for logging to the web
   // console.
-  async LogBlockedCORSRequest(nsString message);
+  async LogBlockedCORSRequest(nsString message, nsCString category);
 
   async AttachStreamFilter(Endpoint<PStreamFilterParent> aEndpoint);
 
   // See ADivertableParentChannel::CancelDiversion
   async CancelDiversion();
 
 both:
   // After receiving this message, the parent also calls
--- a/netwerk/protocol/http/nsCORSListenerProxy.cpp
+++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp
@@ -81,39 +81,41 @@ LogBlockedRequest(nsIRequest* aRequest,
                                              blockedMessage);
 
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to log blocked cross-site request (no formalizedStr");
     return;
   }
 
   nsAutoString msg(blockedMessage.get());
+  nsDependentCString category(aProperty);
 
   if (XRE_IsParentProcess()) {
     if (aCreatingChannel) {
-      rv = aCreatingChannel->LogBlockedCORSRequest(msg);
+      rv = aCreatingChannel->LogBlockedCORSRequest(msg, category);
       if (NS_SUCCEEDED(rv)) {
         return;
       }
     }
     NS_WARNING("Failed to log blocked cross-site request to web console from parent->child, falling back to browser console");
   }
 
   bool privateBrowsing = false;
   if (aRequest) {
     nsCOMPtr<nsILoadGroup> loadGroup;
     rv = aRequest->GetLoadGroup(getter_AddRefs(loadGroup));
     NS_ENSURE_SUCCESS_VOID(rv);
     privateBrowsing = nsContentUtils::IsInPrivateBrowsing(loadGroup);
   }
 
-  // log message ourselves
+  // we are passing aProperty as the category so we can link to the
+  // appropriate MDN docs depending on the specific error.
   uint64_t innerWindowID = nsContentUtils::GetInnerWindowID(aRequest);
   nsCORSListenerProxy::LogBlockedCORSRequest(innerWindowID, privateBrowsing,
-                                             msg);
+                                             msg, category);
 }
 
 //////////////////////////////////////////////////////////////////////////
 // Preflight cache
 
 class nsPreflightCache
 {
 public:
@@ -1584,17 +1586,18 @@ nsCORSListenerProxy::StartCORSPreflight(
 
   return NS_OK;
 }
 
 // static
 void
 nsCORSListenerProxy::LogBlockedCORSRequest(uint64_t aInnerWindowID,
                                            bool aPrivateBrowsing,
-                                           const nsAString& aMessage)
+                                           const nsAString& aMessage,
+                                           const nsACString& aCategory)
 {
   nsresult rv = NS_OK;
 
   // Build the error object and log it to the console
   nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv));
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to log blocked cross-site request (no console)");
     return;
@@ -1611,27 +1614,28 @@ nsCORSListenerProxy::LogBlockedCORSReque
   // the error to the browser console.
   if (aInnerWindowID > 0) {
     rv = scriptError->InitWithSanitizedSource(aMessage,
                                               EmptyString(), // sourceName
                                               EmptyString(), // sourceLine
                                               0,             // lineNumber
                                               0,             // columnNumber
                                               nsIScriptError::warningFlag,
-                                              "CORS",
+                                              aCategory,
                                               aInnerWindowID);
   }
   else {
+    nsCString category = PromiseFlatCString(aCategory);
     rv = scriptError->Init(aMessage,
                            EmptyString(), // sourceName
                            EmptyString(), // sourceLine
                            0,             // lineNumber
                            0,             // columnNumber
                            nsIScriptError::warningFlag,
-                           "CORS",
+                           category.get(),
                            aPrivateBrowsing);
   }
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to log blocked cross-site request (scriptError init failed)");
     return;
   }
   console->LogMessage(scriptError);
 }
--- a/netwerk/protocol/http/nsCORSListenerProxy.h
+++ b/netwerk/protocol/http/nsCORSListenerProxy.h
@@ -71,17 +71,18 @@ public:
                              DataURIHandling aAllowDataURI);
 
   void SetInterceptController(nsINetworkInterceptController* aInterceptController);
 
   // When CORS blocks a request, log the message to the web console, or the
   // browser console if no valid inner window ID is found.
   static void LogBlockedCORSRequest(uint64_t aInnerWindowID,
                                     bool aPrivateBrowsing,
-                                    const nsAString& aMessage);
+                                    const nsAString& aMessage,
+                                    const nsACString& aCategory);
 private:
   // Only HttpChannelParent can call RemoveFromCorsPreflightCache
   friend class mozilla::net::HttpChannelParent;
   // Only nsHttpChannel can invoke CORS preflights
   friend class mozilla::net::nsHttpChannel;
 
   static void RemoveFromCorsPreflightCache(nsIURI* aURI,
                                            nsIPrincipal* aRequestingPrincipal);
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -421,20 +421,20 @@ nsHttpChannel::AddSecurityMessage(const 
         return mWarningReporter->ReportSecurityMessage(aMessageTag,
                                                        aMessageCategory);
     }
     return HttpBaseChannel::AddSecurityMessage(aMessageTag,
                                                aMessageCategory);
 }
 
 NS_IMETHODIMP
-nsHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage)
+nsHttpChannel::LogBlockedCORSRequest(const nsAString& aMessage, const nsACString& aCategory)
 {
     if (mWarningReporter) {
-        return mWarningReporter->LogBlockedCORSRequest(aMessage);
+        return mWarningReporter->LogBlockedCORSRequest(aMessage, aCategory);
     }
     return NS_ERROR_UNEXPECTED;
 }
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel <private>
 //-----------------------------------------------------------------------------
 
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -45,17 +45,17 @@ class nsChannelClassifier;
 class Http2PushedStream;
 
 class HttpChannelSecurityWarningReporter : public nsISupports
 {
 public:
   virtual MOZ_MUST_USE nsresult
   ReportSecurityMessage(const nsAString& aMessageTag,
                         const nsAString& aMessageCategory) = 0;
-  virtual nsresult LogBlockedCORSRequest(const nsAString& aMessage) = 0;
+  virtual nsresult LogBlockedCORSRequest(const nsAString& aMessage, const nsACString& aCategory) = 0;
 };
 
 //-----------------------------------------------------------------------------
 // nsHttpChannel
 //-----------------------------------------------------------------------------
 
 // Use to support QI nsIChannel to nsHttpChannel
 #define NS_HTTPCHANNEL_IID                         \
@@ -185,17 +185,17 @@ public:
     NS_IMETHOD GetResponseEnd(mozilla::TimeStamp *aResponseEnd) override;
     // nsICorsPreflightCallback
     NS_IMETHOD OnPreflightSucceeded() override;
     NS_IMETHOD OnPreflightFailed(nsresult aError) override;
 
     MOZ_MUST_USE nsresult
     AddSecurityMessage(const nsAString& aMessageTag,
                        const nsAString& aMessageCategory) override;
-    NS_IMETHOD LogBlockedCORSRequest(const nsAString& aMessage) override;
+    NS_IMETHOD LogBlockedCORSRequest(const nsAString& aMessage, const nsACString& aCategory) override;
 
     void SetWarningReporter(HttpChannelSecurityWarningReporter *aReporter);
     HttpChannelSecurityWarningReporter* GetWarningReporter();
 public: /* internal necko use only */
 
     uint32_t GetRequestTime() const
     {
         return mRequestTime;
--- a/netwerk/protocol/http/nsIHttpChannel.idl
+++ b/netwerk/protocol/http/nsIHttpChannel.idl
@@ -503,11 +503,14 @@ interface nsIHttpChannel : nsIChannel
 
     /**
      * In e10s, the information that the CORS response blocks the load is in the
      * parent, which doesn't know the true window id of the request, so we may
      * need to proxy the request to the child.
      *
      * @param aMessage
      *        The message to print in the console.
+     *
+     * @param aCategory
+     *        The category under which the message should be displayed.
      */
-    void logBlockedCORSRequest(in AString aMessage);
+    void logBlockedCORSRequest(in AString aMessage, in ACString aCategory);
 };
--- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
@@ -1128,16 +1128,17 @@ nsViewSourceChannel::SetCorsPreflightPar
 
 void
 nsViewSourceChannel::SetAltDataForChild(bool aIsForChild)
 {
     mHttpChannelInternal->SetAltDataForChild(aIsForChild);
 }
 
 NS_IMETHODIMP
-nsViewSourceChannel::LogBlockedCORSRequest(const nsAString& aMessage)
+nsViewSourceChannel::LogBlockedCORSRequest(const nsAString& aMessage,
+                                           const nsACString& aCategory)
 {
   if (!mHttpChannel) {
     NS_WARNING("nsViewSourceChannel::LogBlockedCORSRequest mHttpChannel is null");
     return NS_ERROR_UNEXPECTED;
   }
-  return mHttpChannel->LogBlockedCORSRequest(aMessage);
+  return mHttpChannel->LogBlockedCORSRequest(aMessage, aCategory);
 }