• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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