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