Bug 1215140 P6 Update service worker interception error strings to include detailed parameters. r=bz
authorBen Kelly <ben@wanderview.com>
Thu, 29 Oct 2015 19:53:25 -0700
changeset 270320 db5a90c49607b79bfeb78274622f593529d300f4
parent 270319 8cd3400e663c4c7663fcf50b3d2648bbbd6aadb2
child 270321 9f67d298ece269545f26de26f7f18f2ed53ddf45
push id67314
push userbkelly@mozilla.com
push dateFri, 30 Oct 2015 02:53:32 +0000
treeherdermozilla-inbound@6502d52719d8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1215140
milestone45.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 1215140 P6 Update service worker interception error strings to include detailed parameters. r=bz
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();