1 #include "node_internals.h"
2 #include "node_buffer.h"
3 #include "node_errors.h"
4 #include "util-inl.h"
5 #include "base_object-inl.h"
6
7 namespace node {
8
9 using v8::Array;
10 using v8::ArrayBuffer;
11 using v8::Context;
12 using v8::Function;
13 using v8::FunctionCallbackInfo;
14 using v8::FunctionTemplate;
15 using v8::Integer;
16 using v8::Isolate;
17 using v8::Just;
18 using v8::Local;
19 using v8::Maybe;
20 using v8::MaybeLocal;
21 using v8::Nothing;
22 using v8::Object;
23 using v8::SharedArrayBuffer;
24 using v8::String;
25 using v8::Value;
26 using v8::ValueDeserializer;
27 using v8::ValueSerializer;
28
29 namespace {
30
31 class SerializerContext : public BaseObject,
32 public ValueSerializer::Delegate {
33 public:
34 SerializerContext(Environment* env,
35 Local<Object> wrap);
36
37 ~SerializerContext() override = default;
38
39 void ThrowDataCloneError(Local<String> message) override;
40 Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object) override;
41 Maybe<uint32_t> GetSharedArrayBufferId(
42 Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) override;
43
44 static void SetTreatArrayBufferViewsAsHostObjects(
45 const FunctionCallbackInfo<Value>& args);
46
47 static void New(const FunctionCallbackInfo<Value>& args);
48 static void WriteHeader(const FunctionCallbackInfo<Value>& args);
49 static void WriteValue(const FunctionCallbackInfo<Value>& args);
50 static void ReleaseBuffer(const FunctionCallbackInfo<Value>& args);
51 static void TransferArrayBuffer(const FunctionCallbackInfo<Value>& args);
52 static void WriteUint32(const FunctionCallbackInfo<Value>& args);
53 static void WriteUint64(const FunctionCallbackInfo<Value>& args);
54 static void WriteDouble(const FunctionCallbackInfo<Value>& args);
55 static void WriteRawBytes(const FunctionCallbackInfo<Value>& args);
56
57 SET_NO_MEMORY_INFO()
58 SET_MEMORY_INFO_NAME(SerializerContext)
59 SET_SELF_SIZE(SerializerContext)
60
61 private:
62 ValueSerializer serializer_;
63 };
64
65 class DeserializerContext : public BaseObject,
66 public ValueDeserializer::Delegate {
67 public:
68 DeserializerContext(Environment* env,
69 Local<Object> wrap,
70 Local<Value> buffer);
71
72 ~DeserializerContext() override = default;
73
74 MaybeLocal<Object> ReadHostObject(Isolate* isolate) override;
75
76 static void New(const FunctionCallbackInfo<Value>& args);
77 static void ReadHeader(const FunctionCallbackInfo<Value>& args);
78 static void ReadValue(const FunctionCallbackInfo<Value>& args);
79 static void TransferArrayBuffer(const FunctionCallbackInfo<Value>& args);
80 static void GetWireFormatVersion(const FunctionCallbackInfo<Value>& args);
81 static void ReadUint32(const FunctionCallbackInfo<Value>& args);
82 static void ReadUint64(const FunctionCallbackInfo<Value>& args);
83 static void ReadDouble(const FunctionCallbackInfo<Value>& args);
84 static void ReadRawBytes(const FunctionCallbackInfo<Value>& args);
85
86 SET_NO_MEMORY_INFO()
87 SET_MEMORY_INFO_NAME(DeserializerContext)
88 SET_SELF_SIZE(DeserializerContext)
89
90 private:
91 const uint8_t* data_;
92 const size_t length_;
93
94 ValueDeserializer deserializer_;
95 };
96
SerializerContext(Environment * env,Local<Object> wrap)97 SerializerContext::SerializerContext(Environment* env, Local<Object> wrap)
98 : BaseObject(env, wrap),
99 serializer_(env->isolate(), this) {
100 MakeWeak();
101 }
102
ThrowDataCloneError(Local<String> message)103 void SerializerContext::ThrowDataCloneError(Local<String> message) {
104 Local<Value> args[1] = { message };
105 Local<Value> get_data_clone_error =
106 object()->Get(env()->context(),
107 env()->get_data_clone_error_string())
108 .ToLocalChecked();
109
110 CHECK(get_data_clone_error->IsFunction());
111 MaybeLocal<Value> error =
112 get_data_clone_error.As<Function>()->Call(env()->context(),
113 object(),
114 arraysize(args),
115 args);
116
117 if (error.IsEmpty()) return;
118
119 env()->isolate()->ThrowException(error.ToLocalChecked());
120 }
121
GetSharedArrayBufferId(Isolate * isolate,Local<SharedArrayBuffer> shared_array_buffer)122 Maybe<uint32_t> SerializerContext::GetSharedArrayBufferId(
123 Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) {
124 Local<Value> args[1] = { shared_array_buffer };
125 Local<Value> get_shared_array_buffer_id =
126 object()->Get(env()->context(),
127 env()->get_shared_array_buffer_id_string())
128 .ToLocalChecked();
129
130 if (!get_shared_array_buffer_id->IsFunction()) {
131 return ValueSerializer::Delegate::GetSharedArrayBufferId(
132 isolate, shared_array_buffer);
133 }
134
135 MaybeLocal<Value> id =
136 get_shared_array_buffer_id.As<Function>()->Call(env()->context(),
137 object(),
138 arraysize(args),
139 args);
140
141 if (id.IsEmpty()) return Nothing<uint32_t>();
142
143 return id.ToLocalChecked()->Uint32Value(env()->context());
144 }
145
WriteHostObject(Isolate * isolate,Local<Object> input)146 Maybe<bool> SerializerContext::WriteHostObject(Isolate* isolate,
147 Local<Object> input) {
148 MaybeLocal<Value> ret;
149 Local<Value> args[1] = { input };
150
151 Local<Value> write_host_object =
152 object()->Get(env()->context(),
153 env()->write_host_object_string()).ToLocalChecked();
154
155 if (!write_host_object->IsFunction()) {
156 return ValueSerializer::Delegate::WriteHostObject(isolate, input);
157 }
158
159 ret = write_host_object.As<Function>()->Call(env()->context(),
160 object(),
161 arraysize(args),
162 args);
163
164 if (ret.IsEmpty())
165 return Nothing<bool>();
166
167 return Just(true);
168 }
169
New(const FunctionCallbackInfo<Value> & args)170 void SerializerContext::New(const FunctionCallbackInfo<Value>& args) {
171 Environment* env = Environment::GetCurrent(args);
172 if (!args.IsConstructCall()) {
173 return THROW_ERR_CONSTRUCT_CALL_REQUIRED(
174 env, "Class constructor Serializer cannot be invoked without 'new'");
175 }
176
177 new SerializerContext(env, args.This());
178 }
179
WriteHeader(const FunctionCallbackInfo<Value> & args)180 void SerializerContext::WriteHeader(const FunctionCallbackInfo<Value>& args) {
181 SerializerContext* ctx;
182 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
183 ctx->serializer_.WriteHeader();
184 }
185
WriteValue(const FunctionCallbackInfo<Value> & args)186 void SerializerContext::WriteValue(const FunctionCallbackInfo<Value>& args) {
187 SerializerContext* ctx;
188 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
189 Maybe<bool> ret =
190 ctx->serializer_.WriteValue(ctx->env()->context(), args[0]);
191
192 if (ret.IsJust()) args.GetReturnValue().Set(ret.FromJust());
193 }
194
SetTreatArrayBufferViewsAsHostObjects(const FunctionCallbackInfo<Value> & args)195 void SerializerContext::SetTreatArrayBufferViewsAsHostObjects(
196 const FunctionCallbackInfo<Value>& args) {
197 SerializerContext* ctx;
198 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
199
200 bool value = args[0]->BooleanValue(ctx->env()->isolate());
201 ctx->serializer_.SetTreatArrayBufferViewsAsHostObjects(value);
202 }
203
ReleaseBuffer(const FunctionCallbackInfo<Value> & args)204 void SerializerContext::ReleaseBuffer(const FunctionCallbackInfo<Value>& args) {
205 SerializerContext* ctx;
206 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
207
208 // Note: Both ValueSerializer and this Buffer::New() variant use malloc()
209 // as the underlying allocator.
210 std::pair<uint8_t*, size_t> ret = ctx->serializer_.Release();
211 auto buf = Buffer::New(ctx->env(),
212 reinterpret_cast<char*>(ret.first),
213 ret.second);
214
215 if (!buf.IsEmpty()) {
216 args.GetReturnValue().Set(buf.ToLocalChecked());
217 }
218 }
219
TransferArrayBuffer(const FunctionCallbackInfo<Value> & args)220 void SerializerContext::TransferArrayBuffer(
221 const FunctionCallbackInfo<Value>& args) {
222 SerializerContext* ctx;
223 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
224
225 Maybe<uint32_t> id = args[0]->Uint32Value(ctx->env()->context());
226 if (id.IsNothing()) return;
227
228 if (!args[1]->IsArrayBuffer())
229 return node::THROW_ERR_INVALID_ARG_TYPE(
230 ctx->env(), "arrayBuffer must be an ArrayBuffer");
231
232 Local<ArrayBuffer> ab = args[1].As<ArrayBuffer>();
233 ctx->serializer_.TransferArrayBuffer(id.FromJust(), ab);
234 return;
235 }
236
WriteUint32(const FunctionCallbackInfo<Value> & args)237 void SerializerContext::WriteUint32(const FunctionCallbackInfo<Value>& args) {
238 SerializerContext* ctx;
239 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
240
241 Maybe<uint32_t> value = args[0]->Uint32Value(ctx->env()->context());
242 if (value.IsNothing()) return;
243
244 ctx->serializer_.WriteUint32(value.FromJust());
245 }
246
WriteUint64(const FunctionCallbackInfo<Value> & args)247 void SerializerContext::WriteUint64(const FunctionCallbackInfo<Value>& args) {
248 SerializerContext* ctx;
249 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
250
251 Maybe<uint32_t> arg0 = args[0]->Uint32Value(ctx->env()->context());
252 Maybe<uint32_t> arg1 = args[1]->Uint32Value(ctx->env()->context());
253 if (arg0.IsNothing() || arg1.IsNothing())
254 return;
255
256 uint64_t hi = arg0.FromJust();
257 uint64_t lo = arg1.FromJust();
258 ctx->serializer_.WriteUint64((hi << 32) | lo);
259 }
260
WriteDouble(const FunctionCallbackInfo<Value> & args)261 void SerializerContext::WriteDouble(const FunctionCallbackInfo<Value>& args) {
262 SerializerContext* ctx;
263 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
264
265 Maybe<double> value = args[0]->NumberValue(ctx->env()->context());
266 if (value.IsNothing()) return;
267
268 ctx->serializer_.WriteDouble(value.FromJust());
269 }
270
WriteRawBytes(const FunctionCallbackInfo<Value> & args)271 void SerializerContext::WriteRawBytes(const FunctionCallbackInfo<Value>& args) {
272 SerializerContext* ctx;
273 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
274
275 if (!args[0]->IsArrayBufferView()) {
276 return node::THROW_ERR_INVALID_ARG_TYPE(
277 ctx->env(), "source must be a TypedArray or a DataView");
278 }
279
280 ArrayBufferViewContents<char> bytes(args[0]);
281 ctx->serializer_.WriteRawBytes(bytes.data(), bytes.length());
282 }
283
DeserializerContext(Environment * env,Local<Object> wrap,Local<Value> buffer)284 DeserializerContext::DeserializerContext(Environment* env,
285 Local<Object> wrap,
286 Local<Value> buffer)
287 : BaseObject(env, wrap),
288 data_(reinterpret_cast<const uint8_t*>(Buffer::Data(buffer))),
289 length_(Buffer::Length(buffer)),
290 deserializer_(env->isolate(), data_, length_, this) {
291 object()->Set(env->context(), env->buffer_string(), buffer).Check();
292
293 MakeWeak();
294 }
295
ReadHostObject(Isolate * isolate)296 MaybeLocal<Object> DeserializerContext::ReadHostObject(Isolate* isolate) {
297 Local<Value> read_host_object =
298 object()->Get(env()->context(),
299 env()->read_host_object_string()).ToLocalChecked();
300
301 if (!read_host_object->IsFunction()) {
302 return ValueDeserializer::Delegate::ReadHostObject(isolate);
303 }
304
305 Isolate::AllowJavascriptExecutionScope allow_js(isolate);
306 MaybeLocal<Value> ret =
307 read_host_object.As<Function>()->Call(env()->context(),
308 object(),
309 0,
310 nullptr);
311
312 if (ret.IsEmpty())
313 return MaybeLocal<Object>();
314
315 Local<Value> return_value = ret.ToLocalChecked();
316 if (!return_value->IsObject()) {
317 env()->ThrowTypeError("readHostObject must return an object");
318 return MaybeLocal<Object>();
319 }
320
321 return return_value.As<Object>();
322 }
323
New(const FunctionCallbackInfo<Value> & args)324 void DeserializerContext::New(const FunctionCallbackInfo<Value>& args) {
325 Environment* env = Environment::GetCurrent(args);
326 if (!args.IsConstructCall()) {
327 return THROW_ERR_CONSTRUCT_CALL_REQUIRED(
328 env, "Class constructor Deserializer cannot be invoked without 'new'");
329 }
330
331 if (!args[0]->IsArrayBufferView()) {
332 return node::THROW_ERR_INVALID_ARG_TYPE(
333 env, "buffer must be a TypedArray or a DataView");
334 }
335
336 new DeserializerContext(env, args.This(), args[0]);
337 }
338
ReadHeader(const FunctionCallbackInfo<Value> & args)339 void DeserializerContext::ReadHeader(const FunctionCallbackInfo<Value>& args) {
340 DeserializerContext* ctx;
341 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
342
343 Maybe<bool> ret = ctx->deserializer_.ReadHeader(ctx->env()->context());
344
345 if (ret.IsJust()) args.GetReturnValue().Set(ret.FromJust());
346 }
347
ReadValue(const FunctionCallbackInfo<Value> & args)348 void DeserializerContext::ReadValue(const FunctionCallbackInfo<Value>& args) {
349 DeserializerContext* ctx;
350 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
351
352 MaybeLocal<Value> ret = ctx->deserializer_.ReadValue(ctx->env()->context());
353
354 if (!ret.IsEmpty()) args.GetReturnValue().Set(ret.ToLocalChecked());
355 }
356
TransferArrayBuffer(const FunctionCallbackInfo<Value> & args)357 void DeserializerContext::TransferArrayBuffer(
358 const FunctionCallbackInfo<Value>& args) {
359 DeserializerContext* ctx;
360 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
361
362 Maybe<uint32_t> id = args[0]->Uint32Value(ctx->env()->context());
363 if (id.IsNothing()) return;
364
365 if (args[1]->IsArrayBuffer()) {
366 Local<ArrayBuffer> ab = args[1].As<ArrayBuffer>();
367 ctx->deserializer_.TransferArrayBuffer(id.FromJust(), ab);
368 return;
369 }
370
371 if (args[1]->IsSharedArrayBuffer()) {
372 Local<SharedArrayBuffer> sab = args[1].As<SharedArrayBuffer>();
373 ctx->deserializer_.TransferSharedArrayBuffer(id.FromJust(), sab);
374 return;
375 }
376
377 return node::THROW_ERR_INVALID_ARG_TYPE(
378 ctx->env(), "arrayBuffer must be an ArrayBuffer or SharedArrayBuffer");
379 }
380
GetWireFormatVersion(const FunctionCallbackInfo<Value> & args)381 void DeserializerContext::GetWireFormatVersion(
382 const FunctionCallbackInfo<Value>& args) {
383 DeserializerContext* ctx;
384 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
385
386 args.GetReturnValue().Set(ctx->deserializer_.GetWireFormatVersion());
387 }
388
ReadUint32(const FunctionCallbackInfo<Value> & args)389 void DeserializerContext::ReadUint32(const FunctionCallbackInfo<Value>& args) {
390 DeserializerContext* ctx;
391 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
392
393 uint32_t value;
394 bool ok = ctx->deserializer_.ReadUint32(&value);
395 if (!ok) return ctx->env()->ThrowError("ReadUint32() failed");
396 return args.GetReturnValue().Set(value);
397 }
398
ReadUint64(const FunctionCallbackInfo<Value> & args)399 void DeserializerContext::ReadUint64(const FunctionCallbackInfo<Value>& args) {
400 DeserializerContext* ctx;
401 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
402
403 uint64_t value;
404 bool ok = ctx->deserializer_.ReadUint64(&value);
405 if (!ok) return ctx->env()->ThrowError("ReadUint64() failed");
406
407 uint32_t hi = static_cast<uint32_t>(value >> 32);
408 uint32_t lo = static_cast<uint32_t>(value);
409
410 Isolate* isolate = ctx->env()->isolate();
411
412 Local<Value> ret[] = {
413 Integer::NewFromUnsigned(isolate, hi),
414 Integer::NewFromUnsigned(isolate, lo)
415 };
416 return args.GetReturnValue().Set(Array::New(isolate, ret, arraysize(ret)));
417 }
418
ReadDouble(const FunctionCallbackInfo<Value> & args)419 void DeserializerContext::ReadDouble(const FunctionCallbackInfo<Value>& args) {
420 DeserializerContext* ctx;
421 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
422
423 double value;
424 bool ok = ctx->deserializer_.ReadDouble(&value);
425 if (!ok) return ctx->env()->ThrowError("ReadDouble() failed");
426 return args.GetReturnValue().Set(value);
427 }
428
ReadRawBytes(const FunctionCallbackInfo<Value> & args)429 void DeserializerContext::ReadRawBytes(
430 const FunctionCallbackInfo<Value>& args) {
431 DeserializerContext* ctx;
432 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
433
434 Maybe<int64_t> length_arg = args[0]->IntegerValue(ctx->env()->context());
435 if (length_arg.IsNothing()) return;
436 size_t length = length_arg.FromJust();
437
438 const void* data;
439 bool ok = ctx->deserializer_.ReadRawBytes(length, &data);
440 if (!ok) return ctx->env()->ThrowError("ReadRawBytes() failed");
441
442 const uint8_t* position = reinterpret_cast<const uint8_t*>(data);
443 CHECK_GE(position, ctx->data_);
444 CHECK_LE(position + length, ctx->data_ + ctx->length_);
445
446 const uint32_t offset = static_cast<uint32_t>(position - ctx->data_);
447 CHECK_EQ(ctx->data_ + offset, position);
448
449 args.GetReturnValue().Set(offset);
450 }
451
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)452 void Initialize(Local<Object> target,
453 Local<Value> unused,
454 Local<Context> context,
455 void* priv) {
456 Environment* env = Environment::GetCurrent(context);
457 Local<FunctionTemplate> ser =
458 env->NewFunctionTemplate(SerializerContext::New);
459
460 ser->InstanceTemplate()->SetInternalFieldCount(
461 SerializerContext::kInternalFieldCount);
462 ser->Inherit(BaseObject::GetConstructorTemplate(env));
463
464 env->SetProtoMethod(ser, "writeHeader", SerializerContext::WriteHeader);
465 env->SetProtoMethod(ser, "writeValue", SerializerContext::WriteValue);
466 env->SetProtoMethod(ser, "releaseBuffer", SerializerContext::ReleaseBuffer);
467 env->SetProtoMethod(ser,
468 "transferArrayBuffer",
469 SerializerContext::TransferArrayBuffer);
470 env->SetProtoMethod(ser, "writeUint32", SerializerContext::WriteUint32);
471 env->SetProtoMethod(ser, "writeUint64", SerializerContext::WriteUint64);
472 env->SetProtoMethod(ser, "writeDouble", SerializerContext::WriteDouble);
473 env->SetProtoMethod(ser, "writeRawBytes", SerializerContext::WriteRawBytes);
474 env->SetProtoMethod(ser,
475 "_setTreatArrayBufferViewsAsHostObjects",
476 SerializerContext::SetTreatArrayBufferViewsAsHostObjects);
477
478 ser->ReadOnlyPrototype();
479 env->SetConstructorFunction(target, "Serializer", ser);
480
481 Local<FunctionTemplate> des =
482 env->NewFunctionTemplate(DeserializerContext::New);
483
484 des->InstanceTemplate()->SetInternalFieldCount(
485 DeserializerContext::kInternalFieldCount);
486 des->Inherit(BaseObject::GetConstructorTemplate(env));
487
488 env->SetProtoMethod(des, "readHeader", DeserializerContext::ReadHeader);
489 env->SetProtoMethod(des, "readValue", DeserializerContext::ReadValue);
490 env->SetProtoMethod(des,
491 "getWireFormatVersion",
492 DeserializerContext::GetWireFormatVersion);
493 env->SetProtoMethod(des,
494 "transferArrayBuffer",
495 DeserializerContext::TransferArrayBuffer);
496 env->SetProtoMethod(des, "readUint32", DeserializerContext::ReadUint32);
497 env->SetProtoMethod(des, "readUint64", DeserializerContext::ReadUint64);
498 env->SetProtoMethod(des, "readDouble", DeserializerContext::ReadDouble);
499 env->SetProtoMethod(des, "_readRawBytes", DeserializerContext::ReadRawBytes);
500
501 des->SetLength(1);
502 des->ReadOnlyPrototype();
503 env->SetConstructorFunction(target, "Deserializer", des);
504 }
505
506 } // anonymous namespace
507 } // namespace node
508
509 NODE_MODULE_CONTEXT_AWARE_INTERNAL(serdes, node::Initialize)
510