Bug 1215140 P9 Provide file and line number when FetchEvent.preventDefault() cancels a request. r=bz
authorBen Kelly <ben@wanderview.com>
Thu, 29 Oct 2015 19:53:25 -0700
changeset 270323 9b3a838a67fcedcaa214a44d3d78e74bd428d8c5
parent 270322 0705444d964354a6bfdac321bebc9d775f61d2fb
child 270324 6502d52719d815ea4d2647ba7e51ec7a6c9a5b27
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 P9 Provide file and line number when FetchEvent.preventDefault() cancels a request. r=bz * * * Bug 1215140 P9 interdiff 001
dom/base/ConsoleReportCollector.cpp
dom/events/Event.h
dom/workers/ServiceWorkerEvents.cpp
dom/workers/ServiceWorkerEvents.h
dom/workers/ServiceWorkerPrivate.cpp
--- a/dom/base/ConsoleReportCollector.cpp
+++ b/dom/base/ConsoleReportCollector.cpp
@@ -36,48 +36,51 @@ ConsoleReportCollector::AddConsoleReport
                                               aMessageName, aStringParams));
 }
 
 void
 ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  MutexAutoLock lock(mMutex);
+  nsTArray<PendingReport> reports;
 
-  for (uint32_t i = 0; i < mPendingReports.Length(); ++i) {
-    PendingReport& report = mPendingReports[i];
+  {
+    MutexAutoLock lock(mMutex);
+    mPendingReports.SwapElements(reports);
+  }
+
+  for (uint32_t i = 0; i < reports.Length(); ++i) {
+    PendingReport& report = reports[i];
 
     // It would be nice if we did not have to do this since ReportToConsole()
     // just turns around and converts it back to a spec.
     nsCOMPtr<nsIURI> uri;
     nsresult rv = NS_NewURI(getter_AddRefs(uri), report.mSourceFileURI);
     if (NS_FAILED(rv)) {
       continue;
     }
 
     // Convert back from nsTArray<nsString> to the char16_t** format required
     // by our l10n libraries and ReportToConsole. (bug 1219762)
-    UniquePtr<char16_t*> params;
+    UniquePtr<const char16_t*[]> params;
     uint32_t paramsLength = report.mStringParams.Length();
     if (paramsLength > 0) {
-      params.reset(new char16_t*[paramsLength]);
+      params = MakeUnique<const char16_t*[]>(paramsLength);
       for (uint32_t j = 0; j < paramsLength; ++j) {
-        params.get()[j] = const_cast<char16_t*>(report.mStringParams[j].get());
+        params[j] = report.mStringParams[j].get();
       }
     }
 
     nsContentUtils::ReportToConsole(report.mErrorFlags, report.mCategory,
                                     aDocument, report.mPropertiesFile,
                                     report.mMessageName.get(),
-                                    const_cast<const char16_t**>(params.get()),
+                                    params.get(),
                                     paramsLength, uri, EmptyString(),
                                     report.mLineNumber, report.mColumnNumber);
   }
-
-  mPendingReports.Clear();
 }
 
 ConsoleReportCollector::~ConsoleReportCollector()
 {
 }
 
 } // namespace mozilla
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -172,17 +172,17 @@ public:
 
   // xpidl implementation
   // void PreventDefault();
 
   // You MUST NOT call PreventDefaultJ(JSContext*) from C++ code.  A call of
   // this method always sets Event.defaultPrevented true for web contents.
   // If default action handler calls this, web applications meet wrong
   // defaultPrevented value.
-  void PreventDefault(JSContext* aCx);
+  virtual void PreventDefault(JSContext* aCx);
 
   // You MUST NOT call DefaultPrevented(JSContext*) from C++ code.  This may
   // return false even if PreventDefault() has been called.
   // See comments in its implementation for the detail.
   bool DefaultPrevented(JSContext* aCx) const;
 
   bool DefaultPrevented() const
   {
@@ -293,17 +293,18 @@ private:
   Event* mEvent;
   bool mOriginalWantsPopupControlCheck;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #define NS_FORWARD_TO_EVENT \
-  NS_FORWARD_NSIDOMEVENT(Event::)
+  NS_FORWARD_NSIDOMEVENT(Event::) \
+  virtual void PreventDefault(JSContext* aCx) override { Event::PreventDefault(aCx); }
 
 #define NS_FORWARD_NSIDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION(_to) \
   NS_IMETHOD GetType(nsAString& aType) override { return _to GetType(aType); } \
   NS_IMETHOD GetTarget(nsIDOMEventTarget** aTarget) override { return _to GetTarget(aTarget); } \
   NS_IMETHOD GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget) override { return _to GetCurrentTarget(aCurrentTarget); } \
   NS_IMETHOD GetEventPhase(uint16_t* aEventPhase) override { return _to GetEventPhase(aEventPhase); } \
   NS_IMETHOD GetBubbles(bool* aBubbles) override { return _to GetBubbles(aBubbles); } \
   NS_IMETHOD GetCancelable(bool* aCancelable) override { return _to GetCancelable(aCancelable); } \
@@ -321,17 +322,18 @@ private:
   NS_IMETHOD SetTarget(nsIDOMEventTarget* aTarget) override { return _to SetTarget(aTarget); } \
   NS_IMETHOD_(bool) IsDispatchStopped(void) override { return _to IsDispatchStopped(); } \
   NS_IMETHOD_(WidgetEvent*) GetInternalNSEvent(void) override { return _to GetInternalNSEvent(); } \
   NS_IMETHOD_(void) SetTrusted(bool aTrusted) override { _to SetTrusted(aTrusted); } \
   NS_IMETHOD_(void) SetOwner(EventTarget* aOwner) override { _to SetOwner(aOwner); } \
   NS_IMETHOD_(Event*) InternalDOMEvent() override { return _to InternalDOMEvent(); }
 
 #define NS_FORWARD_TO_EVENT_NO_SERIALIZATION_NO_DUPLICATION \
-  NS_FORWARD_NSIDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION(Event::)
+  NS_FORWARD_NSIDOMEVENT_NO_SERIALIZATION_NO_DUPLICATION(Event::) \
+  virtual void PreventDefault(JSContext* aCx) override { Event::PreventDefault(aCx); }
 
 inline nsISupports*
 ToSupports(mozilla::dom::Event* e)
 {
   return static_cast<nsIDOMEvent*>(e);
 }
 
 inline nsISupports*
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -58,16 +58,18 @@ CancelChannelRunnable::Run()
   MOZ_ASSERT(NS_IsMainThread());
   nsresult rv = mChannel->Cancel(mStatus);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 FetchEvent::FetchEvent(EventTarget* aOwner)
   : ExtendableEvent(aOwner)
+  , mPreventDefaultLineNumber(0)
+  , mPreventDefaultColumnNumber(0)
   , mIsReload(false)
   , mWaitToRespond(false)
 {
 }
 
 FetchEvent::~FetchEvent()
 {
 }
@@ -560,16 +562,55 @@ FetchEvent::RespondWith(JSContext* aCx, 
                            ir->IsNavigationRequest(), mScriptSpec,
                            NS_ConvertUTF8toUTF16(requestURL),
                            spec, line, column);
   aArg.AppendNativeHandler(handler);
 
   WaitUntil(aArg, aRv);
 }
 
+void
+FetchEvent::PreventDefault(JSContext* aCx)
+{
+  MOZ_ASSERT(aCx);
+
+  if (mPreventDefaultScriptSpec.IsEmpty()) {
+    // Note when the FetchEvent might have been canceled by script, but don't
+    // actually log the location until we are sure it matters.  This is
+    // determined in ServiceWorkerPrivate.cpp.  We only remember the first
+    // call to preventDefault() as its the most likely to have actually canceled
+    // the event.
+    nsJSUtils::GetCallingLocation(aCx, mPreventDefaultScriptSpec,
+                                  &mPreventDefaultLineNumber,
+                                  &mPreventDefaultColumnNumber);
+  }
+
+  Event::PreventDefault(aCx);
+}
+
+void
+FetchEvent::ReportCanceled()
+{
+  MOZ_ASSERT(!mPreventDefaultScriptSpec.IsEmpty());
+
+  RefPtr<InternalRequest> ir = mRequest->GetInternalRequest();
+  nsAutoCString url;
+  ir->GetURL(url);
+
+  // The variadic template provided by StringArrayAppender requires exactly
+  // an nsString.
+  NS_ConvertUTF8toUTF16 requestURL(url);
+  //nsString requestURL;
+  //CopyUTF8toUTF16(url, requestURL);
+
+  ::AsyncLog(mChannel.get(), mPreventDefaultScriptSpec,
+             mPreventDefaultLineNumber, mPreventDefaultColumnNumber,
+             NS_LITERAL_CSTRING("InterceptionCanceledWithURL"), &requestURL);
+}
+
 NS_IMPL_ADDREF_INHERITED(FetchEvent, ExtendableEvent)
 NS_IMPL_RELEASE_INHERITED(FetchEvent, ExtendableEvent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchEvent)
 NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, ExtendableEvent, mRequest)
 
--- a/dom/workers/ServiceWorkerEvents.h
+++ b/dom/workers/ServiceWorkerEvents.h
@@ -98,26 +98,32 @@ public:
   }
 };
 
 class FetchEvent final : public ExtendableEvent
 {
   nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
   RefPtr<Request> mRequest;
   nsCString mScriptSpec;
+  nsCString mPreventDefaultScriptSpec;
+  uint32_t mPreventDefaultLineNumber;
+  uint32_t mPreventDefaultColumnNumber;
   bool mIsReload;
   bool mWaitToRespond;
 protected:
   explicit FetchEvent(EventTarget* aOwner);
   ~FetchEvent();
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchEvent, ExtendableEvent)
-  NS_FORWARD_TO_EVENT
+
+  // Note, we cannot use NS_FORWARD_TO_EVENT because we want a different
+  // PreventDefault(JSContext*) override.
+  NS_FORWARD_NSIDOMEVENT(Event::)
 
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
   {
     return FetchEventBinding::Wrap(aCx, this, aGivenProto);
   }
 
   void PostInit(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
                 const nsACString& aScriptSpec);
@@ -149,16 +155,22 @@ public:
   void
   RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv);
 
   already_AddRefed<Promise>
   ForwardTo(const nsAString& aUrl);
 
   already_AddRefed<Promise>
   Default();
+
+  void
+  PreventDefault(JSContext* aCx) override;
+
+  void
+  ReportCanceled();
 };
 
 #ifndef MOZ_SIMPLEPUSH
 
 class PushMessageData final : public nsISupports,
                               public nsWrapperCache
 {
 public:
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -5,20 +5,16 @@
  * 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)
@@ -1166,29 +1162,17 @@ 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)) {
-        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);
-
-        }
+        event->ReportCanceled();
         runnable = new CancelChannelRunnable(mInterceptedChannel,
                                              NS_ERROR_INTERCEPTION_FAILED);
       } else {
         runnable = new ResumeRequest(mInterceptedChannel);
       }
 
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
     }