Bug 1487463 - implement StructuredCloneTester to be used in testing r=baku
authorPerry Jiang <perry@mozilla.com>
Tue, 02 Oct 2018 16:43:57 +0000
changeset 495026 f2737c4b2abebdc89bd3eb464ef1906df6234eb8
parent 495025 84b4b9b7586a12ecf26f1d8eeee5a7bdeed9468b
child 495027 a4d2c14d8fa5ca3531d15c83fdb1616b3e7fcfc8
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1487463
milestone64.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 1487463 - implement StructuredCloneTester to be used in testing r=baku StructuredCloneTester objects can configured to be serializable (or not) and deserializable (or not) by the structured clone algorithm. They can be used to test, for example, onmessageerror event handlers, where the messageerror event is fired when a message fails to be deserialized (but was successfully serialized). The class is pref'ed with "dom.testing.structuredclonetester.enabled". Differential Revision: https://phabricator.services.mozilla.com/D5207
dom/base/DOMPrefsInternal.h
dom/base/StructuredCloneHolder.cpp
dom/base/StructuredCloneTags.h
dom/base/StructuredCloneTester.cpp
dom/base/StructuredCloneTester.h
dom/base/moz.build
dom/webidl/StructuredCloneTester.webidl
dom/webidl/moz.build
modules/libpref/init/StaticPrefList.h
--- a/dom/base/DOMPrefsInternal.h
+++ b/dom/base/DOMPrefsInternal.h
@@ -15,16 +15,17 @@
 //     This is allows the use of DOMPrefs in WebIDL files.
 
 DOM_WEBIDL_PREF(canvas_imagebitmap_extensions_enabled)
 DOM_WEBIDL_PREF(dom_caches_enabled)
 DOM_WEBIDL_PREF(dom_webnotifications_serviceworker_enabled)
 DOM_WEBIDL_PREF(dom_webnotifications_requireinteraction_enabled)
 DOM_WEBIDL_PREF(dom_serviceWorkers_enabled)
 DOM_WEBIDL_PREF(dom_storageManager_enabled)
+DOM_WEBIDL_PREF(dom_testing_structuredclonetester_enabled)
 DOM_WEBIDL_PREF(dom_promise_rejection_events_enabled)
 DOM_WEBIDL_PREF(dom_push_enabled)
 DOM_WEBIDL_PREF(gfx_offscreencanvas_enabled)
 DOM_WEBIDL_PREF(dom_webkitBlink_dirPicker_enabled)
 DOM_WEBIDL_PREF(dom_netinfo_enabled)
 DOM_WEBIDL_PREF(dom_fetchObserver_enabled)
 DOM_WEBIDL_PREF(dom_enable_performance_observer)
 DOM_WEBIDL_PREF(dom_performance_enable_scheduler_timing)
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -8,31 +8,34 @@
 
 #include "ImageContainer.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/CryptoKey.h"
 #include "mozilla/dom/StructuredCloneBlob.h"
 #include "mozilla/dom/Directory.h"
 #include "mozilla/dom/DirectoryBinding.h"
+#include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/FileList.h"
 #include "mozilla/dom/FileListBinding.h"
 #include "mozilla/dom/FormData.h"
 #include "mozilla/dom/ImageBitmap.h"
 #include "mozilla/dom/ImageBitmapBinding.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ImageDataBinding.h"
 #include "mozilla/dom/StructuredClone.h"
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/OffscreenCanvas.h"
 #include "mozilla/dom/OffscreenCanvasBinding.h"
 #include "mozilla/dom/PMessagePort.h"
 #include "mozilla/dom/StructuredCloneTags.h"
+#include "mozilla/dom/StructuredCloneTester.h"
+#include "mozilla/dom/StructuredCloneTesterBinding.h"
 #include "mozilla/dom/SubtleCryptoBinding.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/dom/URLSearchParamsBinding.h"
 #include "mozilla/dom/WebCryptoCommon.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundUtils.h"
@@ -450,16 +453,20 @@ StructuredCloneHolder::ReadFullySerializ
       } else {
         result = cert->WrapObject(aCx, nullptr);
       }
     }
     return result;
   }
 #endif
 
+  if (aTag == SCTAG_DOM_STRUCTURED_CLONE_TESTER) {
+    return StructuredCloneTester::ReadStructuredClone(aCx, aReader);
+  }
+
   // Don't know what this is. Bail.
   xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
   return nullptr;
 }
 
 /* static */ bool
 StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
                                                      JSStructuredCloneWriter* aWriter,
@@ -500,16 +507,32 @@ StructuredCloneHolder::WriteFullySeriali
     if (NS_SUCCEEDED(UNWRAP_OBJECT(RTCCertificate, &obj, cert))) {
       MOZ_ASSERT(NS_IsMainThread());
       return JS_WriteUint32Pair(aWriter, SCTAG_DOM_RTC_CERTIFICATE, 0) &&
              cert->WriteStructuredClone(aWriter);
     }
   }
 #endif
 
+  // StructuredCloneTester - testing only
+  {
+    StructuredCloneTester* sct = nullptr;
+    if (NS_SUCCEEDED(UNWRAP_OBJECT(StructuredCloneTester, &obj, sct))) {
+      MOZ_ASSERT(StaticPrefs::dom_testing_structuredclonetester_enabled());
+
+      // "Fail" serialization
+      if (!sct->Serializable()) {
+        xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
+        return false;
+      }
+
+      return sct->WriteStructuredClone(aWriter);
+    }
+  }
+
   if (NS_IsMainThread() && xpc::IsReflector(obj)) {
     nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(obj);
     nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(base);
     if (principal) {
       auto nsjsprincipals = nsJSPrincipals::get(principal);
       return nsjsprincipals->write(aCx, aWriter);
     }
   }
--- a/dom/base/StructuredCloneTags.h
+++ b/dom/base/StructuredCloneTags.h
@@ -65,15 +65,17 @@ enum StructuredCloneTags {
   SCTAG_DOM_STRUCTURED_CLONE_HOLDER,
 
   // When adding a new tag for IDB, please don't add it to the end of the list!
   // Tags that are supported by IDB must not ever change. See the static assert
   // in IDBObjectStore.cpp, method CommonStructuredCloneReadCallback.
   // Adding to the end of the list would make removing of other tags harder in
   // future.
 
-  SCTAG_DOM_MAX
+  SCTAG_DOM_MAX,
+
+  SCTAG_DOM_STRUCTURED_CLONE_TESTER
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // StructuredCloneTags_h__
new file mode 100644
--- /dev/null
+++ b/dom/base/StructuredCloneTester.cpp
@@ -0,0 +1,121 @@
+/* -*- 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 "StructuredCloneTester.h"
+
+#include "js/StructuredClone.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/dom/StructuredCloneTags.h"
+#include "mozilla/dom/StructuredCloneTesterBinding.h"
+#include "xpcpublic.h"
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(StructuredCloneTester)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(StructuredCloneTester)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(StructuredCloneTester)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StructuredCloneTester)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+StructuredCloneTester::StructuredCloneTester(nsISupports* aParent,
+                                             const bool aSerializable,
+                                             const bool aDeserializable)
+  : mParent(aParent),
+    mSerializable(aSerializable),
+    mDeserializable(aDeserializable)
+{
+}
+
+/* static */ already_AddRefed<StructuredCloneTester>
+StructuredCloneTester::Constructor(const GlobalObject& aGlobal,
+                                   const bool aSerializable,
+                                   const bool aDeserializable,
+                                   ErrorResult& aRv)
+{
+  RefPtr<StructuredCloneTester> sct = new StructuredCloneTester(aGlobal.GetAsSupports(),
+                                                                aSerializable,
+                                                                aDeserializable);
+  return sct.forget();
+}
+
+bool
+StructuredCloneTester::Serializable() const
+{
+  return mSerializable;
+}
+
+bool
+StructuredCloneTester::Deserializable() const
+{
+  return mDeserializable;
+}
+
+/* static */ JSObject*
+StructuredCloneTester::ReadStructuredClone(JSContext* aCx,
+                                           JSStructuredCloneReader* aReader)
+{
+  uint32_t serializable = 0;
+  uint32_t deserializable = 0;
+
+  if (!JS_ReadUint32Pair(aReader, &serializable, &deserializable)) {
+    return nullptr;
+  }
+
+  nsIGlobalObject* global = xpc::CurrentNativeGlobal(aCx);
+
+  if (NS_WARN_IF(!global)) {
+    return nullptr;
+  }
+
+  // Prevent the return value from being trashed by a GC during ~nsRefPtr
+  JS::RootedObject result(aCx);
+
+  RefPtr<StructuredCloneTester> sct = new StructuredCloneTester(
+    global,
+    static_cast<bool>(serializable),
+    static_cast<bool>(deserializable)
+  );
+
+  // "Fail" deserialization
+  if (!sct->Deserializable()) {
+    xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
+    return nullptr;
+  }
+
+  result = sct->WrapObject(aCx, nullptr);
+
+  return result;
+}
+
+bool
+StructuredCloneTester::WriteStructuredClone(JSStructuredCloneWriter* aWriter) const
+{
+  return JS_WriteUint32Pair(aWriter, SCTAG_DOM_STRUCTURED_CLONE_TESTER, 0) &&
+         JS_WriteUint32Pair(aWriter, static_cast<uint32_t>(Serializable()),
+                            static_cast<uint32_t>(Deserializable()));
+}
+
+nsISupports*
+StructuredCloneTester::GetParentObject() const
+{
+  return mParent;
+}
+
+JSObject*
+StructuredCloneTester::WrapObject(JSContext* aCx,
+                                  JS::Handle<JSObject*> aGivenProto)
+{
+  return StructuredCloneTester_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/base/StructuredCloneTester.h
@@ -0,0 +1,70 @@
+/* -*- 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_StructuredCloneTester_h
+#define mozilla_dom_StructuredCloneTester_h
+
+#include "mozilla/AlreadyAddRefed.h"
+#include "nsCOMPtr.h"
+#include "nsISupports.h"
+#include "nsWrapperCache.h"
+
+struct JSStructuredCloneReader;
+struct JSStructuredCloneWriter;
+
+namespace mozilla {
+
+class ErrorResult;
+
+namespace dom {
+
+class GlobalObject;
+
+class StructuredCloneTester final : public nsISupports
+                                  , public nsWrapperCache
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StructuredCloneTester)
+
+  static already_AddRefed<StructuredCloneTester>
+  Constructor(const GlobalObject& aGlobal, const bool aSerializable,
+              const bool aDeserializable, ErrorResult& aRv);
+
+  bool
+  Serializable() const;
+
+  bool
+  Deserializable() const;
+
+  static JSObject*
+  ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader);
+
+  bool
+  WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
+
+  nsISupports*
+  GetParentObject() const;
+
+  // nsWrapperCache interface
+  JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+private:
+  StructuredCloneTester(nsISupports* aParent,
+                        const bool aSerializable,
+                        const bool aDeserializable);
+  ~StructuredCloneTester() = default;
+
+  nsCOMPtr<nsISupports> mParent;
+  bool mSerializable;
+  bool mDeserializable;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_StructuredCloneTester_h
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -215,16 +215,17 @@ EXPORTS.mozilla.dom += [
     'SameProcessMessageQueue.h',
     'ScreenLuminance.h',
     'ScreenOrientation.h',
     'Selection.h',
     'ShadowRoot.h',
     'StructuredCloneBlob.h',
     'StructuredCloneHolder.h',
     'StructuredCloneTags.h',
+    'StructuredCloneTester.h',
     'StyleSheetList.h',
     'SubtleCrypto.h',
     'SyncMessageSender.h',
     'TabGroup.h',
     'Text.h',
     'Timeout.h',
     'TimeoutHandler.h',
     'TimeoutManager.h',
@@ -370,16 +371,17 @@ UNIFIED_SOURCES += [
     'SameProcessMessageQueue.cpp',
     'ScreenLuminance.cpp',
     'ScreenOrientation.cpp',
     'Selection.cpp',
     'SelectionChangeEventDispatcher.cpp',
     'ShadowRoot.cpp',
     'StructuredCloneBlob.cpp',
     'StructuredCloneHolder.cpp',
+    'StructuredCloneTester.cpp',
     'StyleSheetList.cpp',
     'SubtleCrypto.cpp',
     'TabGroup.cpp',
     'Text.cpp',
     'TextInputProcessor.cpp',
     'ThirdPartyUtil.cpp',
     'Timeout.cpp',
     'TimeoutBudgetManager.cpp',
new file mode 100644
--- /dev/null
+++ b/dom/webidl/StructuredCloneTester.webidl
@@ -0,0 +1,15 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ */
+
+// The WebIDL compiler does not accept a Pref-ed interface exposed to any scopes
+// other than *only* `Window`, so the Func is Pref-ed instead.
+[Constructor(boolean serializable, boolean deserializable),
+ Exposed=(Window,Worker),
+ Func="mozilla::dom::DOMPrefs::dom_testing_structuredclonetester_enabled"]
+interface StructuredCloneTester {
+  readonly attribute boolean serializable;
+  readonly attribute boolean deserializable;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -772,16 +772,17 @@ WEBIDL_FILES = [
     'SourceBufferList.webidl',
     'StereoPannerNode.webidl',
     'Storage.webidl',
     'StorageEvent.webidl',
     'StorageManager.webidl',
     'StorageType.webidl',
     'StreamFilter.webidl',
     'StreamFilterDataEvent.webidl',
+    'StructuredCloneTester.webidl',
     'StyleSheet.webidl',
     'StyleSheetList.webidl',
     'SubtleCrypto.webidl',
     'SVGAElement.webidl',
     'SVGAngle.webidl',
     'SVGAnimatedAngle.webidl',
     'SVGAnimatedBoolean.webidl',
     'SVGAnimatedEnumeration.webidl',
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -281,16 +281,22 @@ VARCACHE_PREF(
 )
 
 VARCACHE_PREF(
   "dom.serviceWorkers.testing.enabled",
    dom_serviceWorkers_testing_enabled,
   RelaxedAtomicBool, false
 )
 
+VARCACHE_PREF(
+  "dom.testing.structuredclonetester.enabled",
+  dom_testing_structuredclonetester_enabled,
+  RelaxedAtomicBool, false
+)
+
 // Enable Storage API for all platforms except Android.
 #if !defined(MOZ_WIDGET_ANDROID)
 # define PREF_VALUE true
 #else
 # define PREF_VALUE false
 #endif
 VARCACHE_PREF(
   "dom.storageManager.enabled",