StructuredClone.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sts=4 et sw=4 tw=99:
  3. * This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. #ifndef js_StructuredClone_h
  7. #define js_StructuredClone_h
  8. #include "mozilla/Attributes.h"
  9. #include "mozilla/BufferList.h"
  10. #include <stdint.h>
  11. #include "jstypes.h"
  12. #include "js/RootingAPI.h"
  13. #include "js/TypeDecls.h"
  14. #include "js/Value.h"
  15. struct JSRuntime;
  16. struct JSStructuredCloneReader;
  17. struct JSStructuredCloneWriter;
  18. // API for the HTML5 internal structured cloning algorithm.
  19. namespace JS {
  20. enum class StructuredCloneScope : uint32_t {
  21. SameProcessSameThread,
  22. SameProcessDifferentThread,
  23. DifferentProcess
  24. };
  25. enum TransferableOwnership {
  26. /** Transferable data has not been filled in yet */
  27. SCTAG_TMO_UNFILLED = 0,
  28. /** Structured clone buffer does not yet own the data */
  29. SCTAG_TMO_UNOWNED = 1,
  30. /** All values at least this large are owned by the clone buffer */
  31. SCTAG_TMO_FIRST_OWNED = 2,
  32. /** Data is a pointer that can be freed */
  33. SCTAG_TMO_ALLOC_DATA = 2,
  34. /** Data is a memory mapped pointer */
  35. SCTAG_TMO_MAPPED_DATA = 3,
  36. /**
  37. * Data is embedding-specific. The engine can free it by calling the
  38. * freeTransfer op. The embedding can also use SCTAG_TMO_USER_MIN and
  39. * greater, up to 32 bits, to distinguish specific ownership variants.
  40. */
  41. SCTAG_TMO_CUSTOM = 4,
  42. SCTAG_TMO_USER_MIN
  43. };
  44. class CloneDataPolicy
  45. {
  46. bool sharedArrayBuffer_;
  47. public:
  48. // The default is to allow all policy-controlled aspects.
  49. CloneDataPolicy() :
  50. sharedArrayBuffer_(true)
  51. {}
  52. // In the JS engine, SharedArrayBuffers can only be cloned intra-process
  53. // because the shared memory areas are allocated in process-private memory.
  54. // Clients should therefore deny SharedArrayBuffers when cloning data that
  55. // are to be transmitted inter-process.
  56. //
  57. // Clients should also deny SharedArrayBuffers when cloning data that are to
  58. // be transmitted intra-process if policy needs dictate such denial.
  59. CloneDataPolicy& denySharedArrayBuffer() {
  60. sharedArrayBuffer_ = false;
  61. return *this;
  62. }
  63. bool isSharedArrayBufferAllowed() const {
  64. return sharedArrayBuffer_;
  65. }
  66. };
  67. } /* namespace JS */
  68. /**
  69. * Read structured data from the reader r. This hook is used to read a value
  70. * previously serialized by a call to the WriteStructuredCloneOp hook.
  71. *
  72. * tag and data are the pair of uint32_t values from the header. The callback
  73. * may use the JS_Read* APIs to read any other relevant parts of the object
  74. * from the reader r. closure is any value passed to the JS_ReadStructuredClone
  75. * function. Return the new object on success, nullptr on error/exception.
  76. */
  77. typedef JSObject* (*ReadStructuredCloneOp)(JSContext* cx, JSStructuredCloneReader* r,
  78. uint32_t tag, uint32_t data, void* closure);
  79. /**
  80. * Structured data serialization hook. The engine can write primitive values,
  81. * Objects, Arrays, Dates, RegExps, TypedArrays, ArrayBuffers, Sets, Maps,
  82. * and SharedTypedArrays. Any other type of object requires application support.
  83. * This callback must first use the JS_WriteUint32Pair API to write an object
  84. * header, passing a value greater than JS_SCTAG_USER to the tag parameter.
  85. * Then it can use the JS_Write* APIs to write any other relevant parts of
  86. * the value v to the writer w. closure is any value passed to the
  87. * JS_WriteStructuredClone function.
  88. *
  89. * Return true on success, false on error/exception.
  90. */
  91. typedef bool (*WriteStructuredCloneOp)(JSContext* cx, JSStructuredCloneWriter* w,
  92. JS::HandleObject obj, void* closure);
  93. /**
  94. * This is called when JS_WriteStructuredClone is given an invalid transferable.
  95. * To follow HTML5, the application must throw a DATA_CLONE_ERR DOMException
  96. * with error set to one of the JS_SCERR_* values.
  97. */
  98. typedef void (*StructuredCloneErrorOp)(JSContext* cx, uint32_t errorid);
  99. /**
  100. * This is called when JS_ReadStructuredClone receives a transferable object
  101. * not known to the engine. If this hook does not exist or returns false, the
  102. * JS engine calls the reportError op if set, otherwise it throws a
  103. * DATA_CLONE_ERR DOM Exception. This method is called before any other
  104. * callback and must return a non-null object in returnObject on success.
  105. */
  106. typedef bool (*ReadTransferStructuredCloneOp)(JSContext* cx, JSStructuredCloneReader* r,
  107. uint32_t tag, void* content, uint64_t extraData,
  108. void* closure,
  109. JS::MutableHandleObject returnObject);
  110. /**
  111. * Called when JS_WriteStructuredClone receives a transferable object not
  112. * handled by the engine. If this hook does not exist or returns false, the JS
  113. * engine will call the reportError hook or fall back to throwing a
  114. * DATA_CLONE_ERR DOM Exception. This method is called before any other
  115. * callback.
  116. *
  117. * tag: indicates what type of transferable this is. Must be greater than
  118. * 0xFFFF0201 (value of the internal SCTAG_TRANSFER_MAP_PENDING_ENTRY)
  119. *
  120. * ownership: see TransferableOwnership, above. Used to communicate any needed
  121. * ownership info to the FreeTransferStructuredCloneOp.
  122. *
  123. * content, extraData: what the ReadTransferStructuredCloneOp will receive
  124. */
  125. typedef bool (*TransferStructuredCloneOp)(JSContext* cx,
  126. JS::Handle<JSObject*> obj,
  127. void* closure,
  128. // Output:
  129. uint32_t* tag,
  130. JS::TransferableOwnership* ownership,
  131. void** content,
  132. uint64_t* extraData);
  133. /**
  134. * Called when freeing an unknown transferable object. Note that it
  135. * should never trigger a garbage collection (and will assert in a
  136. * debug build if it does.)
  137. */
  138. typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership,
  139. void* content, uint64_t extraData, void* closure);
  140. // The maximum supported structured-clone serialization format version.
  141. // Increment this when anything at all changes in the serialization format.
  142. // (Note that this does not need to be bumped for Transferable-only changes,
  143. // since they are never saved to persistent storage.)
  144. #define JS_STRUCTURED_CLONE_VERSION 8
  145. struct JSStructuredCloneCallbacks {
  146. ReadStructuredCloneOp read;
  147. WriteStructuredCloneOp write;
  148. StructuredCloneErrorOp reportError;
  149. ReadTransferStructuredCloneOp readTransfer;
  150. TransferStructuredCloneOp writeTransfer;
  151. FreeTransferStructuredCloneOp freeTransfer;
  152. };
  153. enum OwnTransferablePolicy {
  154. OwnsTransferablesIfAny,
  155. IgnoreTransferablesIfAny,
  156. NoTransferables
  157. };
  158. class MOZ_NON_MEMMOVABLE JSStructuredCloneData : public mozilla::BufferList<js::SystemAllocPolicy>
  159. {
  160. typedef js::SystemAllocPolicy AllocPolicy;
  161. typedef mozilla::BufferList<js::SystemAllocPolicy> BufferList;
  162. static const size_t kInitialSize = 0;
  163. static const size_t kInitialCapacity = 4096;
  164. static const size_t kStandardCapacity = 4096;
  165. const JSStructuredCloneCallbacks* callbacks_;
  166. void* closure_;
  167. OwnTransferablePolicy ownTransferables_;
  168. void setOptionalCallbacks(const JSStructuredCloneCallbacks* callbacks,
  169. void* closure,
  170. OwnTransferablePolicy policy) {
  171. callbacks_ = callbacks;
  172. closure_ = closure;
  173. ownTransferables_ = policy;
  174. }
  175. friend struct JSStructuredCloneWriter;
  176. friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer);
  177. public:
  178. explicit JSStructuredCloneData(AllocPolicy aAP = AllocPolicy())
  179. : BufferList(kInitialSize, kInitialCapacity, kStandardCapacity, aAP)
  180. , callbacks_(nullptr)
  181. , closure_(nullptr)
  182. , ownTransferables_(OwnTransferablePolicy::NoTransferables)
  183. {}
  184. MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers)
  185. : BufferList(Move(buffers))
  186. , callbacks_(nullptr)
  187. , closure_(nullptr)
  188. , ownTransferables_(OwnTransferablePolicy::NoTransferables)
  189. {}
  190. JSStructuredCloneData(JSStructuredCloneData&& other) = default;
  191. JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default;
  192. ~JSStructuredCloneData();
  193. using BufferList::BufferList;
  194. };
  195. /** Note: if the *data contains transferable objects, it can be read only once. */
  196. JS_PUBLIC_API(bool)
  197. JS_ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data, uint32_t version,
  198. JS::StructuredCloneScope scope,
  199. JS::MutableHandleValue vp,
  200. const JSStructuredCloneCallbacks* optionalCallbacks, void* closure);
  201. JS_PUBLIC_API(bool)
  202. JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, JSStructuredCloneData* data,
  203. JS::StructuredCloneScope scope,
  204. JS::CloneDataPolicy cloneDataPolicy,
  205. const JSStructuredCloneCallbacks* optionalCallbacks,
  206. void* closure, JS::HandleValue transferable);
  207. JS_PUBLIC_API(bool)
  208. JS_StructuredCloneHasTransferables(JSStructuredCloneData& data, bool* hasTransferable);
  209. JS_PUBLIC_API(bool)
  210. JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp,
  211. const JSStructuredCloneCallbacks* optionalCallbacks, void* closure);
  212. /** RAII sugar for JS_WriteStructuredClone. */
  213. class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
  214. const JS::StructuredCloneScope scope_;
  215. JSStructuredCloneData data_;
  216. uint32_t version_;
  217. public:
  218. JSAutoStructuredCloneBuffer(JS::StructuredCloneScope scope,
  219. const JSStructuredCloneCallbacks* callbacks, void* closure)
  220. : scope_(scope), version_(JS_STRUCTURED_CLONE_VERSION)
  221. {
  222. data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
  223. }
  224. JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other);
  225. JSAutoStructuredCloneBuffer& operator=(JSAutoStructuredCloneBuffer&& other);
  226. ~JSAutoStructuredCloneBuffer() { clear(); }
  227. JSStructuredCloneData& data() { return data_; }
  228. bool empty() const { return !data_.Size(); }
  229. void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
  230. /** Copy some memory. It will be automatically freed by the destructor. */
  231. bool copy(const JSStructuredCloneData& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
  232. const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
  233. /**
  234. * Adopt some memory. It will be automatically freed by the destructor.
  235. * data must have been allocated by the JS engine (e.g., extracted via
  236. * JSAutoStructuredCloneBuffer::steal).
  237. */
  238. void adopt(JSStructuredCloneData&& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
  239. const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
  240. /**
  241. * Release the buffer and transfer ownership to the caller.
  242. */
  243. void steal(JSStructuredCloneData* data, uint32_t* versionp=nullptr,
  244. const JSStructuredCloneCallbacks** callbacks=nullptr, void** closure=nullptr);
  245. /**
  246. * Abandon ownership of any transferable objects stored in the buffer,
  247. * without freeing the buffer itself. Useful when copying the data out into
  248. * an external container, though note that you will need to use adopt() to
  249. * properly release that data eventually.
  250. */
  251. void abandon() { data_.ownTransferables_ = OwnTransferablePolicy::IgnoreTransferablesIfAny; }
  252. bool read(JSContext* cx, JS::MutableHandleValue vp,
  253. const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
  254. bool write(JSContext* cx, JS::HandleValue v,
  255. const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
  256. bool write(JSContext* cx, JS::HandleValue v, JS::HandleValue transferable,
  257. JS::CloneDataPolicy cloneDataPolicy,
  258. const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
  259. private:
  260. // Copy and assignment are not supported.
  261. JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer& other) = delete;
  262. JSAutoStructuredCloneBuffer& operator=(const JSAutoStructuredCloneBuffer& other) = delete;
  263. };
  264. // The range of tag values the application may use for its own custom object types.
  265. #define JS_SCTAG_USER_MIN ((uint32_t) 0xFFFF8000)
  266. #define JS_SCTAG_USER_MAX ((uint32_t) 0xFFFFFFFF)
  267. #define JS_SCERR_RECURSION 0
  268. #define JS_SCERR_TRANSFERABLE 1
  269. #define JS_SCERR_DUP_TRANSFERABLE 2
  270. #define JS_SCERR_UNSUPPORTED_TYPE 3
  271. JS_PUBLIC_API(bool)
  272. JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1, uint32_t* p2);
  273. JS_PUBLIC_API(bool)
  274. JS_ReadBytes(JSStructuredCloneReader* r, void* p, size_t len);
  275. JS_PUBLIC_API(bool)
  276. JS_ReadTypedArray(JSStructuredCloneReader* r, JS::MutableHandleValue vp);
  277. JS_PUBLIC_API(bool)
  278. JS_WriteUint32Pair(JSStructuredCloneWriter* w, uint32_t tag, uint32_t data);
  279. JS_PUBLIC_API(bool)
  280. JS_WriteBytes(JSStructuredCloneWriter* w, const void* p, size_t len);
  281. JS_PUBLIC_API(bool)
  282. JS_WriteString(JSStructuredCloneWriter* w, JS::HandleString str);
  283. JS_PUBLIC_API(bool)
  284. JS_WriteTypedArray(JSStructuredCloneWriter* w, JS::HandleValue v);
  285. JS_PUBLIC_API(bool)
  286. JS_ObjectNotWritten(JSStructuredCloneWriter* w, JS::HandleObject obj);
  287. JS_PUBLIC_API(JS::StructuredCloneScope)
  288. JS_GetStructuredCloneScope(JSStructuredCloneWriter* w);
  289. #endif /* js_StructuredClone_h */