Bug 1219852 - P1 Extract common JS values for rejected respondWith() promises. r=bz, a=ritu
authorBen Kelly <ben@wanderview.com>
Sat, 31 Oct 2015 10:34:20 -0700
changeset 305440 2894bcec34479f25add81b79bf9907b632d1ade7
parent 305439 cf8145ff1418da37cb8e2bdb003ea77665851082
child 305441 77efb8bcd1296d38e10f7ffee42125c748df9029
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
bugs1219852
milestone44.0a2
Bug 1219852 - P1 Extract common JS values for rejected respondWith() promises. r=bz, a=ritu
dom/workers/ServiceWorkerEvents.cpp
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -17,16 +17,18 @@
 #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/DOMException.h"
+#include "mozilla/dom/DOMExceptionBinding.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"
 
 #ifndef MOZ_SIMPLEPUSH
@@ -34,17 +36,19 @@
 #include "nsIUnicodeEncoder.h"
 
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/FetchUtil.h"
 #include "mozilla/dom/TypedArray.h"
 #endif
 
 #include "js/Conversions.h"
+#include "js/TypeDecls.h"
 #include "WorkerPrivate.h"
+#include "xpcpublic.h"
 
 using namespace mozilla::dom;
 
 BEGIN_WORKERS_NAMESPACE
 
 CancelChannelRunnable::CancelChannelRunnable(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
                                              nsresult aStatus)
   : mChannel(aChannel)
@@ -341,16 +345,84 @@ void RespondWithCopyComplete(void* aClos
              NS_LITERAL_CSTRING("InterceptionFailedWithURL"),
              &data->mRequestURL);
     event = new CancelChannelRunnable(data->mInterceptedChannel,
                                       NS_ERROR_INTERCEPTION_FAILED);
   }
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(event)));
 }
 
+namespace {
+
+void
+ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
+                  nsACString& aSourceSpecOut, uint32_t *aLineOut,
+                  uint32_t *aColumnOut, nsString& aMessageOut)
+{
+  MOZ_ASSERT(aLineOut);
+  MOZ_ASSERT(aColumnOut);
+
+  if (aValue.isObject()) {
+    JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
+    RefPtr<DOMException> domException;
+
+    // Try to process as an Error object.  Use the file/line/column values
+    // from the Error as they will be more specific to the root cause of
+    // the problem.
+    JSErrorReport* err = obj ? JS_ErrorFromException(aCx, obj) : nullptr;
+    if (err) {
+      // Use xpc to extract the error message only.  We don't actually send
+      // this report anywhere.
+      RefPtr<xpc::ErrorReport> report = new xpc::ErrorReport();
+      report->Init(err,
+                   "<unknown>", // fallback message
+                   false,       // chrome
+                   0);          // window ID
+
+      if (!report->mFileName.IsEmpty()) {
+        CopyUTF16toUTF8(report->mFileName, aSourceSpecOut);
+        *aLineOut = report->mLineNumber;
+        *aColumnOut = report->mColumn;
+      }
+      aMessageOut.Assign(report->mErrorMsg);
+    }
+
+    // Next, try to unwrap the rejection value as a DOMException.
+    else if(NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException))) {
+
+      nsAutoString filename;
+      if (NS_SUCCEEDED(domException->GetFilename(filename)) &&
+          !filename.IsEmpty()) {
+        CopyUTF16toUTF8(filename, aSourceSpecOut);
+        *aLineOut = domException->LineNumber();
+        *aColumnOut = domException->ColumnNumber();
+      }
+
+      domException->GetName(aMessageOut);
+      aMessageOut.AppendLiteral(": ");
+
+      nsAutoString message;
+      domException->GetMessageMoz(message);
+      aMessageOut.Append(message);
+    }
+  }
+
+  // If we could not unwrap a specific error type, then perform default safe
+  // string conversions on primitives.  Objects will result in "[Object]"
+  // unfortunately.
+  if (aMessageOut.IsEmpty()) {
+    nsAutoJSString jsString;
+    if (jsString.init(aCx, aValue)) {
+      aMessageOut = jsString;
+    }
+  }
+}
+
+} // anonymous namespace
+
 class MOZ_STACK_CLASS AutoCancel
 {
   RefPtr<RespondWithHandler> mOwner;
   nsCString mMessageName;
   nsTArray<nsString> mParams;
 
 public:
   AutoCancel(RespondWithHandler* aOwner, const nsString& aRequestURL)
@@ -509,23 +581,27 @@ RespondWithHandler::ResolvedCallback(JSC
   MOZ_ASSERT(!closure);
   autoCancel.Reset();
   mRequestWasHandled = true;
 }
 
 void
 RespondWithHandler::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
 {
-  nsAutoJSString rejectionString;
-  if (rejectionString.init(aCx, aValue)) {
-    ::AsyncLog(mInterceptedChannel, mRespondWithScriptSpec, mRespondWithLineNumber,
-               mRespondWithColumnNumber,
-               NS_LITERAL_CSTRING("InterceptionRejectedResponseWithURL"),
-               &mRequestURL, &rejectionString);
-  }
+  nsCString sourceSpec = mRespondWithScriptSpec;
+  uint32_t line = mRespondWithLineNumber;
+  uint32_t column = mRespondWithColumnNumber;
+  nsString valueString;
+
+  ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString);
+
+  ::AsyncLog(mInterceptedChannel, sourceSpec, line, column,
+             NS_LITERAL_CSTRING("InterceptionRejectedResponseWithURL"),
+             &mRequestURL, &valueString);
+
   CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
 }
 
 void
 RespondWithHandler::CancelRequest(nsresult aStatus)
 {
   nsCOMPtr<nsIRunnable> runnable =
     new CancelChannelRunnable(mInterceptedChannel, aStatus);