|
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/NullPtr.h" |
|
11 |
|
12 #include <stdint.h> |
|
13 |
|
14 #include "jstypes.h" |
|
15 |
|
16 #include "js/RootingAPI.h" |
|
17 #include "js/TypeDecls.h" |
|
18 #include "js/Value.h" |
|
19 |
|
20 struct JSRuntime; |
|
21 struct JSStructuredCloneReader; |
|
22 struct JSStructuredCloneWriter; |
|
23 |
|
24 // API for the HTML5 internal structured cloning algorithm. |
|
25 |
|
26 namespace JS { |
|
27 enum TransferableOwnership { |
|
28 // Transferable data has not been filled in yet |
|
29 SCTAG_TMO_UNFILLED = 0, |
|
30 |
|
31 // Structured clone buffer does not yet own the data |
|
32 SCTAG_TMO_UNOWNED = 1, |
|
33 |
|
34 // All values at least this large are owned by the clone buffer |
|
35 SCTAG_TMO_FIRST_OWNED = 2, |
|
36 |
|
37 // Data is a pointer that can be freed |
|
38 SCTAG_TMO_ALLOC_DATA = 2, |
|
39 |
|
40 // Data is a SharedArrayBufferObject's buffer |
|
41 SCTAG_TMO_SHARED_BUFFER = 3, |
|
42 |
|
43 // Data is a memory mapped pointer |
|
44 SCTAG_TMO_MAPPED_DATA = 4, |
|
45 |
|
46 // Data is embedding-specific. The engine can free it by calling the |
|
47 // freeTransfer op. The embedding can also use SCTAG_TMO_USER_MIN and |
|
48 // greater, up to 32 bits, to distinguish specific ownership variants. |
|
49 SCTAG_TMO_CUSTOM = 5, |
|
50 |
|
51 SCTAG_TMO_USER_MIN |
|
52 }; |
|
53 } /* namespace JS */ |
|
54 |
|
55 // Read structured data from the reader r. This hook is used to read a value |
|
56 // previously serialized by a call to the WriteStructuredCloneOp hook. |
|
57 // |
|
58 // tag and data are the pair of uint32_t values from the header. The callback |
|
59 // may use the JS_Read* APIs to read any other relevant parts of the object |
|
60 // from the reader r. closure is any value passed to the JS_ReadStructuredClone |
|
61 // function. Return the new object on success, nullptr on error/exception. |
|
62 typedef JSObject *(*ReadStructuredCloneOp)(JSContext *cx, JSStructuredCloneReader *r, |
|
63 uint32_t tag, uint32_t data, void *closure); |
|
64 |
|
65 // Structured data serialization hook. The engine can write primitive values, |
|
66 // Objects, Arrays, Dates, RegExps, TypedArrays, and ArrayBuffers. Any other |
|
67 // type of object requires application support. This callback must first use |
|
68 // the JS_WriteUint32Pair API to write an object header, passing a value |
|
69 // greater than JS_SCTAG_USER to the tag parameter. Then it can use the |
|
70 // JS_Write* APIs to write any other relevant parts of the value v to the |
|
71 // writer w. closure is any value passed to the JS_WriteStructuredCLone function. |
|
72 // |
|
73 // Return true on success, false on error/exception. |
|
74 typedef bool (*WriteStructuredCloneOp)(JSContext *cx, JSStructuredCloneWriter *w, |
|
75 JS::HandleObject obj, void *closure); |
|
76 |
|
77 // This is called when JS_WriteStructuredClone is given an invalid transferable. |
|
78 // To follow HTML5, the application must throw a DATA_CLONE_ERR DOMException |
|
79 // with error set to one of the JS_SCERR_* values. |
|
80 typedef void (*StructuredCloneErrorOp)(JSContext *cx, uint32_t errorid); |
|
81 |
|
82 // This is called when JS_ReadStructuredClone receives a transferable object |
|
83 // not known to the engine. If this hook does not exist or returns false, the |
|
84 // JS engine calls the reportError op if set, otherwise it throws a |
|
85 // DATA_CLONE_ERR DOM Exception. This method is called before any other |
|
86 // callback and must return a non-null object in returnObject on success. |
|
87 typedef bool (*ReadTransferStructuredCloneOp)(JSContext *cx, JSStructuredCloneReader *r, |
|
88 uint32_t tag, void *content, uint64_t extraData, |
|
89 void *closure, |
|
90 JS::MutableHandleObject returnObject); |
|
91 |
|
92 // Called when JS_WriteStructuredClone receives a transferable object not |
|
93 // handled by the engine. If this hook does not exist or returns false, the JS |
|
94 // engine will call the reportError hook or fall back to throwing a |
|
95 // DATA_CLONE_ERR DOM Exception. This method is called before any other |
|
96 // callback. |
|
97 // |
|
98 // tag: indicates what type of transferable this is. Must be greater than |
|
99 // 0xFFFF0201 (value of the internal SCTAG_TRANSFER_MAP_PENDING_ENTRY) |
|
100 // |
|
101 // ownership: see TransferableOwnership, above. Used to communicate any needed |
|
102 // ownership info to the FreeTransferStructuredCloneOp. |
|
103 // |
|
104 // content, extraData: what the ReadTransferStructuredCloneOp will receive |
|
105 // |
|
106 typedef bool (*TransferStructuredCloneOp)(JSContext *cx, |
|
107 JS::Handle<JSObject*> obj, |
|
108 void *closure, |
|
109 // Output: |
|
110 uint32_t *tag, |
|
111 JS::TransferableOwnership *ownership, |
|
112 void **content, |
|
113 uint64_t *extraData); |
|
114 |
|
115 // Called when JS_ClearStructuredClone has to free an unknown transferable |
|
116 // object. Note that it should never trigger a garbage collection (and will |
|
117 // assert in a debug build if it does.) |
|
118 typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwnership ownership, |
|
119 void *content, uint64_t extraData, void *closure); |
|
120 |
|
121 // The maximum supported structured-clone serialization format version. Note |
|
122 // that this does not need to be bumped for Transferable-only changes, since |
|
123 // they are never saved to persistent storage. |
|
124 #define JS_STRUCTURED_CLONE_VERSION 2 |
|
125 |
|
126 struct JSStructuredCloneCallbacks { |
|
127 ReadStructuredCloneOp read; |
|
128 WriteStructuredCloneOp write; |
|
129 StructuredCloneErrorOp reportError; |
|
130 ReadTransferStructuredCloneOp readTransfer; |
|
131 TransferStructuredCloneOp writeTransfer; |
|
132 FreeTransferStructuredCloneOp freeTransfer; |
|
133 }; |
|
134 |
|
135 // Note: if the *data contains transferable objects, it can be read only once. |
|
136 JS_PUBLIC_API(bool) |
|
137 JS_ReadStructuredClone(JSContext *cx, uint64_t *data, size_t nbytes, uint32_t version, |
|
138 JS::MutableHandleValue vp, |
|
139 const JSStructuredCloneCallbacks *optionalCallbacks, void *closure); |
|
140 |
|
141 // Note: On success, the caller is responsible for calling |
|
142 // JS_ClearStructuredClone(*datap, nbytes, optionalCallbacks, closure). |
|
143 JS_PUBLIC_API(bool) |
|
144 JS_WriteStructuredClone(JSContext *cx, JS::HandleValue v, uint64_t **datap, size_t *nbytesp, |
|
145 const JSStructuredCloneCallbacks *optionalCallbacks, |
|
146 void *closure, JS::HandleValue transferable); |
|
147 |
|
148 JS_PUBLIC_API(bool) |
|
149 JS_ClearStructuredClone(uint64_t *data, size_t nbytes, |
|
150 const JSStructuredCloneCallbacks *optionalCallbacks, |
|
151 void *closure); |
|
152 |
|
153 JS_PUBLIC_API(bool) |
|
154 JS_StructuredCloneHasTransferables(const uint64_t *data, size_t nbytes, bool *hasTransferable); |
|
155 |
|
156 JS_PUBLIC_API(bool) |
|
157 JS_StructuredClone(JSContext *cx, JS::HandleValue v, JS::MutableHandleValue vp, |
|
158 const JSStructuredCloneCallbacks *optionalCallbacks, void *closure); |
|
159 |
|
160 // RAII sugar for JS_WriteStructuredClone. |
|
161 class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) { |
|
162 uint64_t *data_; |
|
163 size_t nbytes_; |
|
164 uint32_t version_; |
|
165 const JSStructuredCloneCallbacks *callbacks_; |
|
166 void *closure_; |
|
167 |
|
168 public: |
|
169 JSAutoStructuredCloneBuffer() |
|
170 : data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION), |
|
171 callbacks_(nullptr), closure_(nullptr) |
|
172 {} |
|
173 |
|
174 JSAutoStructuredCloneBuffer(const JSStructuredCloneCallbacks *callbacks, void *closure) |
|
175 : data_(nullptr), nbytes_(0), version_(JS_STRUCTURED_CLONE_VERSION), |
|
176 callbacks_(callbacks), closure_(closure) |
|
177 {} |
|
178 |
|
179 JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer &&other); |
|
180 JSAutoStructuredCloneBuffer &operator=(JSAutoStructuredCloneBuffer &&other); |
|
181 |
|
182 ~JSAutoStructuredCloneBuffer() { clear(); } |
|
183 |
|
184 uint64_t *data() const { return data_; } |
|
185 size_t nbytes() const { return nbytes_; } |
|
186 |
|
187 void clear(); |
|
188 |
|
189 // Copy some memory. It will be automatically freed by the destructor. |
|
190 bool copy(const uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION); |
|
191 |
|
192 // Adopt some memory. It will be automatically freed by the destructor. |
|
193 // data must have been allocated by the JS engine (e.g., extracted via |
|
194 // JSAutoStructuredCloneBuffer::steal). |
|
195 void adopt(uint64_t *data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION); |
|
196 |
|
197 // Remove the buffer so that it will not be automatically freed. |
|
198 // After this, the caller is responsible for feeding the memory back to |
|
199 // JSAutoStructuredCloneBuffer::adopt. |
|
200 void steal(uint64_t **datap, size_t *nbytesp, uint32_t *versionp=nullptr); |
|
201 |
|
202 bool read(JSContext *cx, JS::MutableHandleValue vp, |
|
203 const JSStructuredCloneCallbacks *optionalCallbacks=nullptr, void *closure=nullptr); |
|
204 |
|
205 bool write(JSContext *cx, JS::HandleValue v, |
|
206 const JSStructuredCloneCallbacks *optionalCallbacks=nullptr, void *closure=nullptr); |
|
207 |
|
208 bool write(JSContext *cx, JS::HandleValue v, JS::HandleValue transferable, |
|
209 const JSStructuredCloneCallbacks *optionalCallbacks=nullptr, void *closure=nullptr); |
|
210 |
|
211 private: |
|
212 // Copy and assignment are not supported. |
|
213 JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer &other) MOZ_DELETE; |
|
214 JSAutoStructuredCloneBuffer &operator=(const JSAutoStructuredCloneBuffer &other) MOZ_DELETE; |
|
215 }; |
|
216 |
|
217 // The range of tag values the application may use for its own custom object types. |
|
218 #define JS_SCTAG_USER_MIN ((uint32_t) 0xFFFF8000) |
|
219 #define JS_SCTAG_USER_MAX ((uint32_t) 0xFFFFFFFF) |
|
220 |
|
221 #define JS_SCERR_RECURSION 0 |
|
222 #define JS_SCERR_TRANSFERABLE 1 |
|
223 |
|
224 JS_PUBLIC_API(void) |
|
225 JS_SetStructuredCloneCallbacks(JSRuntime *rt, const JSStructuredCloneCallbacks *callbacks); |
|
226 |
|
227 JS_PUBLIC_API(bool) |
|
228 JS_ReadUint32Pair(JSStructuredCloneReader *r, uint32_t *p1, uint32_t *p2); |
|
229 |
|
230 JS_PUBLIC_API(bool) |
|
231 JS_ReadBytes(JSStructuredCloneReader *r, void *p, size_t len); |
|
232 |
|
233 JS_PUBLIC_API(bool) |
|
234 JS_ReadTypedArray(JSStructuredCloneReader *r, JS::MutableHandleValue vp); |
|
235 |
|
236 JS_PUBLIC_API(bool) |
|
237 JS_WriteUint32Pair(JSStructuredCloneWriter *w, uint32_t tag, uint32_t data); |
|
238 |
|
239 JS_PUBLIC_API(bool) |
|
240 JS_WriteBytes(JSStructuredCloneWriter *w, const void *p, size_t len); |
|
241 |
|
242 JS_PUBLIC_API(bool) |
|
243 JS_WriteTypedArray(JSStructuredCloneWriter *w, JS::HandleValue v); |
|
244 |
|
245 #endif /* js_StructuredClone_h */ |