Bug 1238842 - Add error codes to Gecko by following W3C spec. r=brsun
authorTom Tung <ttung@mozilla.com>
Wed, 24 Feb 2016 17:56:22 +0800
changeset 285427 fb50d4d434bfbb237390f7f78261123a17fafa2a
parent 285426 405edcc5dbfaffd76929d92ab50339ed947bd8f9
child 285428 ff53b1ae1a195e266e9f84b179b26edfeef06844
push id72377
push userbrsun@mozilla.com
push dateThu, 25 Feb 2016 01:51:22 +0000
treeherdermozilla-inbound@fb50d4d434bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbrsun
bugs1238842
milestone47.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 1238842 - Add error codes to Gecko by following W3C spec. r=brsun
dom/bluetooth/common/BluetoothCommon.h
dom/bluetooth/common/BluetoothGattReplyRunnable.cpp
dom/bluetooth/common/BluetoothGattReplyRunnable.h
dom/bluetooth/common/BluetoothReplyRunnable.cpp
dom/bluetooth/common/BluetoothReplyRunnable.h
dom/bluetooth/common/BluetoothUtils.cpp
dom/bluetooth/common/BluetoothUtils.h
dom/bluetooth/ipc/BluetoothMessageUtils.h
dom/bluetooth/ipc/BluetoothTypes.ipdlh
dom/bluetooth/moz.build
--- a/dom/bluetooth/common/BluetoothCommon.h
+++ b/dom/bluetooth/common/BluetoothCommon.h
@@ -1119,17 +1119,20 @@ enum BluetoothGattStatus {
   GATT_STATUS_ATTRIBUTE_NOT_FOUND,
   GATT_STATUS_ATTRIBUTE_NOT_LONG,
   GATT_STATUS_INSUFFICIENT_ENCRYPTION_KEY_SIZE,
   GATT_STATUS_INVALID_ATTRIBUTE_LENGTH,
   GATT_STATUS_UNLIKELY_ERROR,
   GATT_STATUS_INSUFFICIENT_ENCRYPTION,
   GATT_STATUS_UNSUPPORTED_GROUP_TYPE,
   GATT_STATUS_INSUFFICIENT_RESOURCES,
-  GATT_STATUS_UNKNOWN_ERROR
+  GATT_STATUS_UNKNOWN_ERROR,
+  GATT_STATUS_BEGIN_OF_APPLICATION_ERROR = 0x80,
+  GATT_STATUS_END_OF_APPLICATION_ERROR = 0x9f,
+  GATT_STATUS_END_OF_ERROR = 0x100
 };
 
 enum BluetoothGattAuthReq {
   GATT_AUTH_REQ_NONE,
   GATT_AUTH_REQ_NO_MITM,
   GATT_AUTH_REQ_MITM,
   GATT_AUTH_REQ_SIGNED_NO_MITM,
   GATT_AUTH_REQ_SIGNED_MITM,
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/common/BluetoothGattReplyRunnable.cpp
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BluetoothGattReplyRunnable.h"
+#include "mozilla/dom/bluetooth/BluetoothTypes.h"
+#include "mozilla/dom/Promise.h"
+
+using namespace mozilla::dom;
+
+USING_BLUETOOTH_NAMESPACE
+
+BluetoothGattReplyRunnable::BluetoothGattReplyRunnable(Promise* aPromise)
+  : BluetoothReplyRunnable(nullptr, aPromise)
+{
+  MOZ_ASSERT(aPromise);
+}
+
+void
+BluetoothGattReplyRunnable::GattStatusToDOMStatus(
+  const BluetoothGattStatus aGattStatus, nsresult& aDOMStatus)
+{
+  /**
+   * https://webbluetoothcg.github.io/web-bluetooth/#error-handling
+   *
+   * ToDo:
+   * If the procedure times out or the ATT Bearer is terminated for any
+   * reason, return |NS_ERROR_DOM_NETWORK_ERR|.
+   */
+
+  // Error Code Mapping
+  if ((aGattStatus >= GATT_STATUS_BEGIN_OF_APPLICATION_ERROR) &&
+      (aGattStatus <= GATT_STATUS_END_OF_APPLICATION_ERROR) &&
+      IsWrite()) {
+    aDOMStatus = NS_ERROR_DOM_INVALID_MODIFICATION_ERR;
+    return;
+  }
+
+  switch (aGattStatus) {
+    case GATT_STATUS_INVALID_ATTRIBUTE_LENGTH:
+      aDOMStatus = NS_ERROR_DOM_INVALID_MODIFICATION_ERR;
+      break;
+    case GATT_STATUS_ATTRIBUTE_NOT_LONG:
+      /**
+       * ToDo:
+       * While receiving |GATT_STATUS_ATTRIBUTE_NOT_LONG|, we need to check
+       * whether 'Long' sub-procedure has been used or not.
+       * If we have used 'Long' sub-procedure, we need to retry the step
+       * without using 'Long' sub-procedure (e.g. Read Blob Request) based on
+       * W3C reuqirements. If it fails again due to the length of the value
+       * being written, convert the error status to
+       * |NS_ERROR_DOM_INVALID_MODIFICATION_ERR|.
+       * If 'Long' sub-procedure has not been used, convert the error status to
+       * |NS_ERROR_DOM_NOT_SUPPORTED_ERR|.
+       */
+      aDOMStatus = NS_ERROR_DOM_INVALID_MODIFICATION_ERR;
+      break;
+    case GATT_STATUS_INSUFFICIENT_AUTHENTICATION:
+    case GATT_STATUS_INSUFFICIENT_ENCRYPTION:
+    case GATT_STATUS_INSUFFICIENT_ENCRYPTION_KEY_SIZE:
+      /**
+       * ToDo:
+       * In W3C requirement, UA SHOULD attempt to increase the security level
+       * of the connection while receiving those error statuses. If it fails or
+       * UA doesn't suuport return the |NS_ERROR_DOM_SECURITY_ERR|.
+       *
+       * Note: The Gecko have already attempted to increase the security level
+       * after receiving |GATT_STATUS_INSUFFICIENT_AUTHENTICATION| or
+       * |GATT_STATUS_INSUFFICIENT_ENCRYPTION|. Only need to handle
+       * |GATT_STATUS_INSUFFICIENT_ENCRYPTION_KEY_SIZE| in the future.
+       */
+      aDOMStatus = NS_ERROR_DOM_SECURITY_ERR;
+      break;
+    case GATT_STATUS_INSUFFICIENT_AUTHORIZATION:
+      aDOMStatus = NS_ERROR_DOM_SECURITY_ERR;
+      break;
+    case GATT_STATUS_INVALID_HANDLE:
+    case GATT_STATUS_INVALID_PDU:
+    case GATT_STATUS_INVALID_OFFSET:
+    case GATT_STATUS_ATTRIBUTE_NOT_FOUND:
+    case GATT_STATUS_UNSUPPORTED_GROUP_TYPE:
+    case GATT_STATUS_READ_NOT_PERMITTED:
+    case GATT_STATUS_WRITE_NOT_PERMITTED:
+    case GATT_STATUS_REQUEST_NOT_SUPPORTED:
+    case GATT_STATUS_PREPARE_QUEUE_FULL:
+    case GATT_STATUS_INSUFFICIENT_RESOURCES:
+    case GATT_STATUS_UNLIKELY_ERROR:
+    default:
+      aDOMStatus = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+      break;
+  }
+}
+
+nsresult
+BluetoothGattReplyRunnable::FireErrorString()
+{
+  MOZ_ASSERT(mReply);
+
+  if (!mPromise ||
+      mReply->type() != BluetoothReply::TBluetoothReplyError ||
+      mReply->get_BluetoothReplyError().errorStatus().type() !=
+        BluetoothErrorStatus::TBluetoothGattStatus) {
+    return BluetoothReplyRunnable::FireErrorString();
+  }
+
+  nsresult domStatus = NS_OK;
+
+  GattStatusToDOMStatus(
+    mReply->get_BluetoothReplyError().errorStatus().get_BluetoothGattStatus(),
+    domStatus);
+  nsresult rv = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM, domStatus);
+  mPromise->MaybeReject(rv);
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/common/BluetoothGattReplyRunnable.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_BluetoothGattReplyRunnable_h
+#define mozilla_dom_bluetooth_BluetoothGattReplyRunnable_h
+
+#include "BluetoothReplyRunnable.h"
+
+class nsIDOMDOMRequest;
+
+namespace mozilla {
+namespace dom {
+class Promise;
+}
+}
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothReply;
+
+class BluetoothGattReplyRunnable : public BluetoothReplyRunnable
+{
+public:
+  BluetoothGattReplyRunnable(Promise* aPromise);
+
+protected:
+  virtual ~BluetoothGattReplyRunnable() {}
+
+private:
+  virtual nsresult FireErrorString() override;
+
+  void GattStatusToDOMStatus(const BluetoothGattStatus aGattStatus,
+                             nsresult& aDOMStatus);
+
+  virtual bool IsWrite()
+  {
+    return false;
+  }
+};
+
+class BluetoothGattVoidReplyRunnable : public BluetoothGattReplyRunnable
+{
+public:
+  BluetoothGattVoidReplyRunnable(Promise* aPromise)
+    : BluetoothGattReplyRunnable(aPromise) {}
+  ~BluetoothGattVoidReplyRunnable() {}
+
+protected:
+  virtual bool
+  ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) override
+  {
+    aValue.setUndefined();
+    return true;
+  }
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif // mozilla_dom_bluetooth_BluetoothGattReplyRunnable_h
--- a/dom/bluetooth/common/BluetoothReplyRunnable.cpp
+++ b/dom/bluetooth/common/BluetoothReplyRunnable.cpp
@@ -14,18 +14,18 @@
 #include "nsServiceManagerUtils.h"
 
 using namespace mozilla::dom;
 
 USING_BLUETOOTH_NAMESPACE
 
 BluetoothReplyRunnable::BluetoothReplyRunnable(nsIDOMDOMRequest* aReq,
                                                Promise* aPromise)
-  : mDOMRequest(aReq)
-  , mPromise(aPromise)
+  : mPromise(aPromise)
+  , mDOMRequest(aReq)
   , mErrorStatus(STATUS_FAIL)
 {}
 
 void
 BluetoothReplyRunnable::SetReply(BluetoothReply* aReply)
 {
   mReply = aReply;
 }
@@ -92,18 +92,17 @@ BluetoothReplyRunnable::Run()
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mReply);
 
   AutoSafeJSContext cx;
   JS::Rooted<JS::Value> v(cx, JS::UndefinedValue());
 
   nsresult rv;
   if (mReply->type() != BluetoothReply::TBluetoothReplySuccess) {
-    SetError(mReply->get_BluetoothReplyError().errorString(),
-             mReply->get_BluetoothReplyError().errorStatus());
+    ParseErrorStatus();
     rv = FireErrorString();
   } else if (!ParseSuccessfulReply(&v)) {
     rv = FireErrorString();
   } else {
     rv = FireReplySuccess(v);
   }
 
   if (NS_FAILED(rv)) {
@@ -124,16 +123,32 @@ BluetoothReplyRunnable::Run()
 void
 BluetoothReplyRunnable::OnSuccessFired()
 {}
 
 void
 BluetoothReplyRunnable::OnErrorFired()
 {}
 
+void
+BluetoothReplyRunnable::ParseErrorStatus()
+{
+  MOZ_ASSERT(mReply);
+  MOZ_ASSERT(mReply->type() == BluetoothReply::TBluetoothReplyError);
+
+  if (mReply->get_BluetoothReplyError().errorStatus().type() ==
+      BluetoothErrorStatus::TBluetoothStatus) {
+    SetError(
+      mReply->get_BluetoothReplyError().errorString(),
+      mReply->get_BluetoothReplyError().errorStatus().get_BluetoothStatus());
+  } else {
+    SetError(mReply->get_BluetoothReplyError().errorString(), STATUS_FAIL);
+  }
+}
+
 BluetoothVoidReplyRunnable::BluetoothVoidReplyRunnable(nsIDOMDOMRequest* aReq,
                                                        Promise* aPromise)
   : BluetoothReplyRunnable(aReq, aPromise)
 {}
 
 BluetoothVoidReplyRunnable::~BluetoothVoidReplyRunnable()
 {}
 
--- a/dom/bluetooth/common/BluetoothReplyRunnable.h
+++ b/dom/bluetooth/common/BluetoothReplyRunnable.h
@@ -43,38 +43,42 @@ public:
 
   virtual void ReleaseMembers();
 
 protected:
   virtual ~BluetoothReplyRunnable();
 
   virtual bool ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue) = 0;
 
+  virtual nsresult FireErrorString();
+
   // This is an autoptr so we don't have to bring the ipdl include into the
   // header. We assume we'll only be running this once and it should die on
   // scope out of Run() anyways.
   nsAutoPtr<BluetoothReply> mReply;
 
+  RefPtr<Promise> mPromise;
+
 private:
+  virtual void ParseErrorStatus();
+
   nsresult FireReplySuccess(JS::Handle<JS::Value> aVal);
-  nsresult FireErrorString();
 
   virtual void OnSuccessFired();
   virtual void OnErrorFired();
 
   /**
    * Either mDOMRequest or mPromise is not nullptr to reply applications
    * success or error string. One special case is internal IPC that require
    * neither mDOMRequest nor mPromise to reply applications.
    * E.g., GetAdaptersTask triggered by BluetoothManager
    *
    * TODO: remove mDOMRequest once all methods adopt Promise.
    */
   nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
-  RefPtr<Promise> mPromise;
 
   BluetoothStatus mErrorStatus;
   nsString mErrorString;
 };
 
 class BluetoothVoidReplyRunnable : public BluetoothReplyRunnable
 {
 public:
--- a/dom/bluetooth/common/BluetoothUtils.cpp
+++ b/dom/bluetooth/common/BluetoothUtils.cpp
@@ -808,16 +808,30 @@ DispatchReplyError(BluetoothReplyRunnabl
   BluetoothReply* reply =
     new BluetoothReply(BluetoothReplyError(aStatus, EmptyString()));
 
   aRunnable->SetReply(reply);
   NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable)));
 }
 
 void
+DispatchReplyError(BluetoothReplyRunnable* aRunnable,
+                   const enum BluetoothGattStatus aGattStatus)
+{
+  MOZ_ASSERT(aRunnable);
+
+  // Reply will be deleted by the runnable after running on main thread
+  BluetoothReply* reply =
+    new BluetoothReply(BluetoothReplyError(aGattStatus, EmptyString()));
+
+  aRunnable->SetReply(reply);
+  NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(aRunnable)));
+}
+
+void
 DispatchStatusChangedEvent(const nsAString& aType,
                            const BluetoothAddress& aAddress,
                            bool aStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   InfallibleTArray<BluetoothNamedValue> data;
   AppendNamedValue(data, "address", aAddress);
--- a/dom/bluetooth/common/BluetoothUtils.h
+++ b/dom/bluetooth/common/BluetoothUtils.h
@@ -374,16 +374,30 @@ DispatchReplyError(BluetoothReplyRunnabl
  *
  * @param aRunnable  the runnable to reply bluetooth request.
  * @param aStatus    the error status to reply failed request.
  */
 void
 DispatchReplyError(BluetoothReplyRunnable* aRunnable,
                    const enum BluetoothStatus aStatus);
 
+/**
+ * Dispatch failed bluetooth reply with error bluetooth gatt status and
+ * string.
+ *
+ * This function is for bluetooth to return Promise as the error status is
+ * bluetooth gatt status.
+ *
+ * @param aRunnable   the runnable to reply bluetooth request.
+ * @param aGattStatus the bluettoh gatt error status to reply failed request.
+ */
+void
+DispatchReplyError(BluetoothReplyRunnable* aRunnable,
+                   const enum BluetoothGattStatus aGattStatus);
+
 void
 DispatchStatusChangedEvent(const nsAString& aType,
                            const BluetoothAddress& aDeviceAddress,
                            bool aStatus);
 
 //
 // BluetoothNamedValue manipulation
 //
--- a/dom/bluetooth/ipc/BluetoothMessageUtils.h
+++ b/dom/bluetooth/ipc/BluetoothMessageUtils.h
@@ -362,11 +362,19 @@ struct ParamTraits<mozilla::dom::bluetoo
         !ReadParam(aMsg, aIter, &(aResult->mServiceUuids))) {
       return false;
     }
 
     return true;
   }
 };
 
+template <>
+struct ParamTraits<mozilla::dom::bluetooth::BluetoothGattStatus>
+  : public ContiguousEnumSerializer<
+             mozilla::dom::bluetooth::BluetoothGattStatus,
+             mozilla::dom::bluetooth::GATT_STATUS_SUCCESS,
+             mozilla::dom::bluetooth::GATT_STATUS_END_OF_ERROR>
+{ };
+
 } // namespace IPC
 
 #endif // mozilla_dom_bluetooth_ipc_BluetoothMessageUtils_h
--- a/dom/bluetooth/ipc/BluetoothTypes.ipdlh
+++ b/dom/bluetooth/ipc/BluetoothTypes.ipdlh
@@ -15,16 +15,18 @@ using mozilla::dom::bluetooth::Bluetooth
 using mozilla::dom::bluetooth::BluetoothGattCharProp
   from "mozilla/dom/bluetooth/BluetoothCommon.h";
 using mozilla::dom::bluetooth::BluetoothGattId
   from "mozilla/dom/bluetooth/BluetoothCommon.h";
 using mozilla::dom::bluetooth::BluetoothGattResponse
   from "mozilla/dom/bluetooth/BluetoothCommon.h";
 using mozilla::dom::bluetooth::BluetoothGattServiceId
   from "mozilla/dom/bluetooth/BluetoothCommon.h";
+using mozilla::dom::bluetooth::BluetoothGattStatus
+  from "mozilla/dom/bluetooth/BluetoothCommon.h";
 using mozilla::dom::bluetooth::BluetoothGattWriteType
   from "mozilla/dom/bluetooth/BluetoothCommon.h";
 using mozilla::dom::bluetooth::BluetoothRemoteName
   from "mozilla/dom/bluetooth/BluetoothCommon.h";
 using mozilla::dom::bluetooth::BluetoothSspVariant
   from "mozilla/dom/bluetooth/BluetoothCommon.h";
 using mozilla::dom::bluetooth::BluetoothStatus
   from "mozilla/dom/bluetooth/BluetoothCommon.h";
@@ -81,19 +83,25 @@ struct BluetoothSignal
   BluetoothValue value;
 };
 
 struct BluetoothReplySuccess
 {
   BluetoothValue value;
 };
 
+union BluetoothErrorStatus
+{
+  BluetoothStatus;
+  BluetoothGattStatus;
+};
+
 struct BluetoothReplyError
 {
-  BluetoothStatus errorStatus;
+  BluetoothErrorStatus errorStatus;
   nsString errorString;
 };
 
 union BluetoothReply
 {
   BluetoothReplySuccess;
   BluetoothReplyError;
 };
--- a/dom/bluetooth/moz.build
+++ b/dom/bluetooth/moz.build
@@ -11,16 +11,17 @@ if CONFIG['MOZ_B2G_BT']:
     #
 
     if CONFIG['MOZ_B2G_RIL']:
         SOURCES += [
             'common/BluetoothRilListener.cpp'
         ]
 
     SOURCES += [
+        'common/BluetoothGattReplyRunnable.cpp',
         'common/BluetoothHidManager.cpp',
         'common/BluetoothInterface.cpp',
         'common/BluetoothProfileController.cpp',
         'common/BluetoothReplyRunnable.cpp',
         'common/BluetoothService.cpp',
         'common/BluetoothUtils.cpp',
         'common/BluetoothUuid.cpp',
         'common/ObexBase.cpp',