LCOV - code coverage report
Current view: top level - js/public - StructuredClone.h (source / functions) Hit Total Coverage
Test: output.info Lines: 29 33 87.9 %
Date: 2017-07-14 16:53:18 Functions: 12 15 80.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13