Bug 1215140 P6 Update service worker interception error strings to include detailed parameters. r=bz a=ritu l10n=ritu
authorBen Kelly <ben@wanderview.com>
Thu, 29 Oct 2015 19:53:25 -0700
changeset 305431 3eb450d0732dba2748966dbefc3428afd4b7a8e4
parent 305430 325d05344d2f3984e06cc7db66762341e9e84433
child 305432 278d5ae8efb755fe265d8cd155644dbc553b5096
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, ritu
bugs1215140
milestone44.0a2
Bug 1215140 P6 Update service worker interception error strings to include detailed parameters. r=bz a=ritu l10n=ritu
dom/locales/en-US/chrome/dom/dom.properties
dom/workers/ServiceWorkerEvents.cpp
dom/workers/ServiceWorkerPrivate.cpp
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -183,8 +183,24 @@ ClientRequestOpaqueInterception=A Servic
 # LOCALIZATION NOTE: Do not translate "ServiceWorker", "opaqueredirect", "Response", "FetchEvent.respondWith()", or "FetchEvent.request".
 BadOpaqueRedirectInterception=A ServiceWorker passed an opaqueredirect Response to FetchEvent.respondWith() while FetchEvent.request was not a navigation request.
 # LOCALIZATION NOTE: Do not translate "ServiceWorker" or "FetchEvent.preventDefault()".
 InterceptionCanceled=ServiceWorker canceled network interception by calling FetchEvent.preventDefault().
 # LOCALIZATION NOTE: Do not translate "ServiceWorker", "Promise", or "FetchEvent.respondWith()".
 InterceptionRejectedResponse=ServiceWorker passed a rejected Promise to FetchEvent.respondWith().  This typically means that the code that resolves the Promise has failed.
 WebrtcDeprecatedPrefixWarning=WebRTC interfaces with the "moz" prefix (mozRTCPeerConnection, mozRTCSessionDescription, mozRTCIceCandidate) have been deprecated.
 NavigatorGetUserMediaWarning=navigator.mozGetUserMedia has been replaced by navigator.mediaDevices.getUserMedia
+# LOCALIZATION NOTE: Do not translate "ServiceWorker". %S is a URL.
+InterceptionFailedWithURL=Failed to load '%S'. A ServiceWorker intercepted the request and encountered an unexpected error.
+# LOCALIZATION NOTE: Do not translate "ServiceWorker", "FetchEvent.respondWith()", "opaque", or "Response". %S is a URL.
+OpaqueInterceptionDisabledWithURL=Failed to load '%S'. A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while opaque interception is disabled.
+# LOCALIZATION NOTE: Do not translate "ServiceWorker", "FetchEvent.respondWith()", "FetchEvent", "no-cors", "opaque", "Response", or "RequestMode". %1$S is a URL. %2$S is a RequestMode value.
+BadOpaqueInterceptionRequestModeWithURL=Failed to load '%1$S'. A ServiceWorker passed an opaque Response to FetchEvent.respondWith() while handling a '%2$S' FetchEvent. Opaque Response objects are only valid when the RequestMode is 'no-cors'.
+# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Error", "Response", "FetchEvent.respondWith()", or "fetch()". %S is a URL.
+InterceptedErrorResponseWithURL=Failed to load '%S'. A ServiceWorker passed an Error Response to FetchEvent.respondWith(). This typically means the ServiceWorker performed an invalid fetch() call.
+# LOCALIZATION NOTE: Do not translate "ServiceWorker", "Response", "FetchEvent.respondWith()", or "Response.clone()". %S is a URL.
+InterceptedUsedResponseWithURL=Failed to load '%S'. A ServiceWorker passed a used Response to FetchEvent.respondWith(). The body of a Response may only be read once. Use Response.clone() to access the body multiple times.
+# LOCALIZATION NOTE: Do not translate "ServiceWorker", "opaqueredirect", "Response", "FetchEvent.respondWith()", or "FetchEvent". %s is a URL.
+BadOpaqueRedirectInterceptionWithURL=Failed to load '%S'. A ServiceWorker passed an opaqueredirect Response to FetchEvent.respondWith() while handling a non-navigation FetchEvent.
+# LOCALIZATION NOTE: Do not translate "ServiceWorker" or "FetchEvent.preventDefault()". %S is a URL.
+InterceptionCanceledWithURL=Failed to load '%S'. A ServiceWorker canceled the load by calling FetchEvent.preventDefault().
+# LOCALIZATION NOTE: Do not translate "ServiceWorker", "promise", or "FetchEvent.respondWith()". %1$S is a URL. %2$S is an error string.
+InterceptionRejectedResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with '%2$S'.
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -15,16 +15,17 @@
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStreamUtils.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsSerializationHelper.h"
 #include "nsQueryObject.h"
 
+#include "mozilla/ErrorResult.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/FetchEventBinding.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/WorkerScope.h"
 #include "mozilla/dom/workers/bindings/ServiceWorker.h"
 
@@ -32,16 +33,17 @@
 #include "nsIUnicodeDecoder.h"
 #include "nsIUnicodeEncoder.h"
 
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/TypedArray.h"
 #endif
 
+#include "js/Conversions.h"
 #include "WorkerPrivate.h"
 
 using namespace mozilla::dom;
 
 BEGIN_WORKERS_NAMESPACE
 
 CancelChannelRunnable::CancelChannelRunnable(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
                                              nsresult aStatus)
@@ -93,16 +95,50 @@ FetchEvent::Constructor(const GlobalObje
   e->mRequest = aOptions.mRequest.WasPassed() ?
       &aOptions.mRequest.Value() : nullptr;
   e->mIsReload = aOptions.mIsReload;
   return e.forget();
 }
 
 namespace {
 
+void
+AsyncLog(nsIInterceptedChannel *aInterceptedChannel,
+         const nsACString& aRespondWithScriptSpec,
+         uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber,
+         const nsACString& aMessageName, const nsTArray<nsString>& aParams)
+{
+  MOZ_ASSERT(aInterceptedChannel);
+  nsCOMPtr<nsIChannel> inner;
+  aInterceptedChannel->GetChannel(getter_AddRefs(inner));
+  nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(inner);
+  if (reporter) {
+    reporter->AddConsoleReport(nsIScriptError::errorFlag,
+                               NS_LITERAL_CSTRING("Service Worker Interception"),
+                               nsContentUtils::eDOM_PROPERTIES,
+                               aRespondWithScriptSpec,
+                               aRespondWithLineNumber,
+                               aRespondWithColumnNumber,
+                               aMessageName, aParams);
+  }
+}
+
+template<typename... Params>
+void
+AsyncLog(nsIInterceptedChannel* aInterceptedChannel,
+         const nsACString& aRespondWithScriptSpec,
+         uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber,
+         const nsACString& aMessageName, Params... aParams)
+{
+  nsTArray<nsString> paramsList(sizeof...(Params));
+  StringArrayAppender::Append(paramsList, sizeof...(Params), aParams...);
+  AsyncLog(aInterceptedChannel, aRespondWithScriptSpec, aRespondWithLineNumber,
+           aRespondWithColumnNumber, aMessageName, paramsList);
+}
+
 class FinishResponse final : public nsRunnable
 {
   nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
   RefPtr<InternalResponse> mInternalResponse;
   ChannelInfo mWorkerChannelInfo;
   const nsCString mScriptSpec;
   const nsCString mResponseURLSpec;
 
@@ -193,138 +229,169 @@ public:
 
 class RespondWithHandler final : public PromiseNativeHandler
 {
   nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
   const RequestMode mRequestMode;
   const DebugOnly<bool> mIsClientRequest;
   const bool mIsNavigationRequest;
   const nsCString mScriptSpec;
+  const nsString mRequestURL;
   const nsCString mRespondWithScriptSpec;
   const uint32_t mRespondWithLineNumber;
   const uint32_t mRespondWithColumnNumber;
   bool mRequestWasHandled;
 public:
   NS_DECL_ISUPPORTS
 
   RespondWithHandler(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
                      RequestMode aRequestMode, bool aIsClientRequest,
                      bool aIsNavigationRequest,
                      const nsACString& aScriptSpec,
+                     const nsAString& aRequestURL,
                      const nsACString& aRespondWithScriptSpec,
                      uint32_t aRespondWithLineNumber,
                      uint32_t aRespondWithColumnNumber)
     : mInterceptedChannel(aChannel)
     , mRequestMode(aRequestMode)
     , mIsClientRequest(aIsClientRequest)
     , mIsNavigationRequest(aIsNavigationRequest)
     , mScriptSpec(aScriptSpec)
+    , mRequestURL(aRequestURL)
     , mRespondWithScriptSpec(aRespondWithScriptSpec)
     , mRespondWithLineNumber(aRespondWithLineNumber)
     , mRespondWithColumnNumber(aRespondWithColumnNumber)
     , mRequestWasHandled(false)
   {
   }
 
   void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
 
   void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
 
   void CancelRequest(nsresult aStatus);
 
-  void AsyncLog(const nsACString& aMessageName);
+  void AsyncLog(const nsACString& aMessageName, const nsTArray<nsString>& aParams)
+  {
+    ::AsyncLog(mInterceptedChannel, mRespondWithScriptSpec, mRespondWithLineNumber,
+               mRespondWithColumnNumber, aMessageName, aParams);
+  }
 
 private:
   ~RespondWithHandler()
   {
     if (!mRequestWasHandled) {
-      AsyncLog(NS_LITERAL_CSTRING("InterceptionFailed"));
+      ::AsyncLog(mInterceptedChannel, mRespondWithScriptSpec,
+                 mRespondWithLineNumber, mRespondWithColumnNumber,
+                 NS_LITERAL_CSTRING("InterceptionFailedWithURL"), &mRequestURL);
       CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
     }
   }
 };
 
 struct RespondWithClosure
 {
   nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
   RefPtr<InternalResponse> mInternalResponse;
   ChannelInfo mWorkerChannelInfo;
   const nsCString mScriptSpec;
   const nsCString mResponseURLSpec;
+  const nsString mRequestURL;
+  const nsCString mRespondWithScriptSpec;
+  const uint32_t mRespondWithLineNumber;
+  const uint32_t mRespondWithColumnNumber;
 
   RespondWithClosure(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
                      InternalResponse* aInternalResponse,
                      const ChannelInfo& aWorkerChannelInfo,
                      const nsCString& aScriptSpec,
-                     const nsACString& aResponseURLSpec)
+                     const nsACString& aResponseURLSpec,
+                     const nsAString& aRequestURL,
+                     const nsACString& aRespondWithScriptSpec,
+                     uint32_t aRespondWithLineNumber,
+                     uint32_t aRespondWithColumnNumber)
     : mInterceptedChannel(aChannel)
     , mInternalResponse(aInternalResponse)
     , mWorkerChannelInfo(aWorkerChannelInfo)
     , mScriptSpec(aScriptSpec)
     , mResponseURLSpec(aResponseURLSpec)
+    , mRequestURL(aRequestURL)
+    , mRespondWithScriptSpec(aRespondWithScriptSpec)
+    , mRespondWithLineNumber(aRespondWithLineNumber)
+    , mRespondWithColumnNumber(aRespondWithColumnNumber)
   {
   }
 };
 
 void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
 {
   nsAutoPtr<RespondWithClosure> data(static_cast<RespondWithClosure*>(aClosure));
   nsCOMPtr<nsIRunnable> event;
   if (NS_SUCCEEDED(aStatus)) {
     event = new FinishResponse(data->mInterceptedChannel,
                                data->mInternalResponse,
                                data->mWorkerChannelInfo,
                                data->mScriptSpec,
                                data->mResponseURLSpec);
   } else {
+    AsyncLog(data->mInterceptedChannel, data->mRespondWithScriptSpec,
+             data->mRespondWithLineNumber, data->mRespondWithColumnNumber,
+             NS_LITERAL_CSTRING("InterceptionFailedWithURL"),
+             &data->mRequestURL);
     event = new CancelChannelRunnable(data->mInterceptedChannel,
                                       NS_ERROR_INTERCEPTION_FAILED);
   }
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(event)));
 }
 
 class MOZ_STACK_CLASS AutoCancel
 {
   RefPtr<RespondWithHandler> mOwner;
   nsCString mMessageName;
+  nsTArray<nsString> mParams;
 
 public:
-  explicit AutoCancel(RespondWithHandler* aOwner)
+  AutoCancel(RespondWithHandler* aOwner, const nsString& aRequestURL)
     : mOwner(aOwner)
-    , mMessageName(NS_LITERAL_CSTRING("InterceptionFailed"))
+    , mMessageName(NS_LITERAL_CSTRING("InterceptionFailedWithURL"))
   {
+    mParams.AppendElement(aRequestURL);
   }
 
   ~AutoCancel()
   {
     if (mOwner) {
-      mOwner->AsyncLog(mMessageName);
+      mOwner->AsyncLog(mMessageName, mParams);
       mOwner->CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
     }
   }
 
-  void SetCancelMessageName(const nsACString& aMessageName)
+  template<typename... Params>
+  void SetCancelMessage(const nsACString& aMessageName, Params... aParams)
   {
     MOZ_ASSERT(mOwner);
-    MOZ_ASSERT(mMessageName.EqualsLiteral("InterceptionFailed"));
+    MOZ_ASSERT(mMessageName.EqualsLiteral("InterceptionFailedWithURL"));
+    MOZ_ASSERT(mParams.Length() == 1);
     mMessageName = aMessageName;
+    mParams.Clear();
+    StringArrayAppender::Append(mParams, sizeof...(Params), aParams...);
   }
 
   void Reset()
   {
     mOwner = nullptr;
   }
 };
 
 NS_IMPL_ISUPPORTS0(RespondWithHandler)
 
 void
 RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
 {
-  AutoCancel autoCancel(this);
+  AutoCancel autoCancel(this, mRequestURL);
 
   if (!aValue.isObject()) {
     NS_WARNING("FetchEvent::RespondWith was passed a promise resolved to a non-Object value");
     return;
   }
 
   RefPtr<Response> response;
   nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response);
@@ -335,51 +402,56 @@ RespondWithHandler::ResolvedCallback(JSC
   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(worker);
   worker->AssertIsOnWorkerThread();
 
   // Allow opaque response interception to be disabled until we can ensure the
   // security implications are not a complete disaster.
   if (response->Type() == ResponseType::Opaque &&
       !worker->OpaqueInterceptionEnabled()) {
-    autoCancel.SetCancelMessageName(
-      NS_LITERAL_CSTRING("OpaqueInterceptionDisabled"));
+    autoCancel.SetCancelMessage(
+      NS_LITERAL_CSTRING("OpaqueInterceptionDisabledWithURL"), &mRequestURL);
     return;
   }
 
   // Section "HTTP Fetch", step 2.2:
   //  If one of the following conditions is true, return a network error:
   //    * response's type is "error".
   //    * request's mode is not "no-cors" and response's type is "opaque".
   //    * request is not a navigation request and response's type is
   //      "opaqueredirect".
 
   if (response->Type() == ResponseType::Error) {
-    autoCancel.SetCancelMessageName(
-      NS_LITERAL_CSTRING("InterceptedErrorResponse"));
+    autoCancel.SetCancelMessage(
+      NS_LITERAL_CSTRING("InterceptedErrorResponseWithURL"), &mRequestURL);
     return;
   }
 
   MOZ_ASSERT_IF(mIsClientRequest, mRequestMode == RequestMode::Same_origin);
 
   if (response->Type() == ResponseType::Opaque && mRequestMode != RequestMode::No_cors) {
-    autoCancel.SetCancelMessageName(
-      NS_LITERAL_CSTRING("BadOpaqueInterceptionRequestMode"));
+    uint32_t mode = static_cast<uint32_t>(mRequestMode);
+    NS_ConvertASCIItoUTF16 modeString(RequestModeValues::strings[mode].value,
+                                      RequestModeValues::strings[mode].length);
+
+    autoCancel.SetCancelMessage(
+      NS_LITERAL_CSTRING("BadOpaqueInterceptionRequestModeWithURL"),
+      &mRequestURL, &modeString);
     return;
   }
 
   if (!mIsNavigationRequest && response->Type() == ResponseType::Opaqueredirect) {
-    autoCancel.SetCancelMessageName(
-      NS_LITERAL_CSTRING("BadOpaqueRedirectInterception"));
+    autoCancel.SetCancelMessage(
+      NS_LITERAL_CSTRING("BadOpaqueRedirectInterceptionWithURL"), &mRequestURL);
     return;
   }
 
   if (NS_WARN_IF(response->BodyUsed())) {
-    autoCancel.SetCancelMessageName(
-      NS_LITERAL_CSTRING("InterceptedUsedResponse"));
+    autoCancel.SetCancelMessage(
+      NS_LITERAL_CSTRING("InterceptedUsedResponseWithURL"), &mRequestURL);
     return;
   }
 
   RefPtr<InternalResponse> ir = response->GetInternalResponse();
   if (NS_WARN_IF(!ir)) {
     return;
   }
 
@@ -392,17 +464,21 @@ RespondWithHandler::ResolvedCallback(JSC
     if (NS_WARN_IF(responseURL.IsEmpty())) {
       return;
     }
   }
 
   nsAutoPtr<RespondWithClosure> closure(new RespondWithClosure(mInterceptedChannel, ir,
                                                                worker->GetChannelInfo(),
                                                                mScriptSpec,
-                                                               responseURL));
+                                                               responseURL,
+                                                               mRequestURL,
+                                                               mRespondWithScriptSpec,
+                                                               mRespondWithLineNumber,
+                                                               mRespondWithColumnNumber));
   nsCOMPtr<nsIInputStream> body;
   ir->GetUnfilteredBody(getter_AddRefs(body));
   // Errors and redirects may not have a body.
   if (body) {
     response->SetBodyUsed();
 
     nsCOMPtr<nsIOutputStream> responseBody;
     rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody));
@@ -429,49 +505,35 @@ RespondWithHandler::ResolvedCallback(JSC
   MOZ_ASSERT(!closure);
   autoCancel.Reset();
   mRequestWasHandled = true;
 }
 
 void
 RespondWithHandler::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
 {
-  AsyncLog(NS_LITERAL_CSTRING("InterceptionRejectedResponse"));
+  nsAutoJSString rejectionString;
+  if (rejectionString.init(aCx, aValue)) {
+    ::AsyncLog(mInterceptedChannel, mRespondWithScriptSpec, mRespondWithLineNumber,
+               mRespondWithColumnNumber,
+               NS_LITERAL_CSTRING("InterceptionRejectedResponseWithURL"),
+               &mRequestURL, &rejectionString);
+  }
   CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
 }
 
 void
 RespondWithHandler::CancelRequest(nsresult aStatus)
 {
   nsCOMPtr<nsIRunnable> runnable =
     new CancelChannelRunnable(mInterceptedChannel, aStatus);
   NS_DispatchToMainThread(runnable);
   mRequestWasHandled = true;
 }
 
-void
-RespondWithHandler::AsyncLog(const nsACString& aMessageName)
-{
-  // TODO: pass request URL, line number
-  // TODO: pass rejection value
-  nsCOMPtr<nsIChannel> inner;
-  mInterceptedChannel->GetChannel(getter_AddRefs(inner));
-  nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(inner);
-  if (reporter) {
-    reporter->AddConsoleReport(nsIScriptError::errorFlag,
-                               NS_LITERAL_CSTRING("Service Worker Interception"),
-                               nsContentUtils::eDOM_PROPERTIES,
-                               mRespondWithScriptSpec,
-                               mRespondWithLineNumber,
-                               mRespondWithColumnNumber,
-                               aMessageName,
-                               nsTArray<nsString>());
-  }
-}
-
 } // namespace
 
 void
 FetchEvent::RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv)
 {
   if (EventPhase() == nsIDOMEvent::NONE || mWaitToRespond) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
@@ -482,21 +544,26 @@ FetchEvent::RespondWith(JSContext* aCx, 
   // information in any error reporting.  We should be guaranteed not to get
   // a file:// string here because service workers require http/https.
   nsCString spec;
   uint32_t line = 0;
   uint32_t column = 0;
   nsJSUtils::GetCallingLocation(aCx, spec, &line, &column);
 
   RefPtr<InternalRequest> ir = mRequest->GetInternalRequest();
+
+  nsAutoCString requestURL;
+  ir->GetURL(requestURL);
+
   StopImmediatePropagation();
   mWaitToRespond = true;
   RefPtr<RespondWithHandler> handler =
     new RespondWithHandler(mChannel, mRequest->Mode(), ir->IsClientRequest(),
                            ir->IsNavigationRequest(), mScriptSpec,
+                           NS_ConvertUTF8toUTF16(requestURL),
                            spec, line, column);
   aArg.AppendNativeHandler(handler);
 
   WaitUntil(aArg, aRv);
 }
 
 NS_IMPL_ADDREF_INHERITED(FetchEvent, ExtendableEvent)
 NS_IMPL_RELEASE_INHERITED(FetchEvent, ExtendableEvent)
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -5,16 +5,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ServiceWorkerPrivate.h"
 #include "ServiceWorkerManager.h"
 #include "nsStreamUtils.h"
 #include "nsStringStream.h"
 #include "mozilla/dom/FetchUtil.h"
 
+#include "nsIConsoleReportCollector.h"
+#include "nsIScriptError.h"
+#include "nsIScriptError.h"
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
 BEGIN_WORKERS_NAMESPACE
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ServiceWorkerPrivate)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerPrivate)
 NS_IMPL_CYCLE_COLLECTION(ServiceWorkerPrivate, mSupportsArray)
@@ -1162,17 +1166,31 @@ private:
     event->PostInit(mInterceptedChannel, mScriptSpec);
     event->SetTrusted(true);
 
     RefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
     nsresult rv2 = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
     if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) {
       nsCOMPtr<nsIRunnable> runnable;
       if (event->DefaultPrevented(aCx)) {
-        runnable = new CancelChannelRunnable(mInterceptedChannel, NS_ERROR_INTERCEPTION_CANCELED);
+        nsCOMPtr<nsIChannel> inner;
+        mInterceptedChannel->GetChannel(getter_AddRefs(inner));
+        nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(inner);
+        if (reporter) {
+          NS_ConvertUTF8toUTF16 requestURL(mSpec);
+          reporter->AddConsoleReport(nsIScriptError::errorFlag,
+                                     NS_LITERAL_CSTRING("Service Worker Interception"),
+                                     nsContentUtils::eDOM_PROPERTIES,
+                                     mScriptSpec, 0, 0,
+                                     NS_LITERAL_CSTRING("InterceptionCanceledWithURL"),
+                                     &requestURL);
+
+        }
+        runnable = new CancelChannelRunnable(mInterceptedChannel,
+                                             NS_ERROR_INTERCEPTION_FAILED);
       } else {
         runnable = new ResumeRequest(mInterceptedChannel);
       }
 
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
     }
 
     RefPtr<Promise> waitUntilPromise = event->GetPromise();