• 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 
173   new SerializerContext(env, args.This());
174 }
175 
WriteHeader(const FunctionCallbackInfo<Value> & args)176 void SerializerContext::WriteHeader(const FunctionCallbackInfo<Value>& args) {
177   SerializerContext* ctx;
178   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
179   ctx->serializer_.WriteHeader();
180 }
181 
WriteValue(const FunctionCallbackInfo<Value> & args)182 void SerializerContext::WriteValue(const FunctionCallbackInfo<Value>& args) {
183   SerializerContext* ctx;
184   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
185   Maybe<bool> ret =
186       ctx->serializer_.WriteValue(ctx->env()->context(), args[0]);
187 
188   if (ret.IsJust()) args.GetReturnValue().Set(ret.FromJust());
189 }
190 
SetTreatArrayBufferViewsAsHostObjects(const FunctionCallbackInfo<Value> & args)191 void SerializerContext::SetTreatArrayBufferViewsAsHostObjects(
192     const FunctionCallbackInfo<Value>& args) {
193   SerializerContext* ctx;
194   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
195 
196   bool value = args[0]->BooleanValue(ctx->env()->isolate());
197   ctx->serializer_.SetTreatArrayBufferViewsAsHostObjects(value);
198 }
199 
ReleaseBuffer(const FunctionCallbackInfo<Value> & args)200 void SerializerContext::ReleaseBuffer(const FunctionCallbackInfo<Value>& args) {
201   SerializerContext* ctx;
202   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
203 
204   // Note: Both ValueSerializer and this Buffer::New() variant use malloc()
205   // as the underlying allocator.
206   std::pair<uint8_t*, size_t> ret = ctx->serializer_.Release();
207   auto buf = Buffer::New(ctx->env(),
208                          reinterpret_cast<char*>(ret.first),
209                          ret.second,
210                          true /* uses_malloc */);
211 
212   if (!buf.IsEmpty()) {
213     args.GetReturnValue().Set(buf.ToLocalChecked());
214   }
215 }
216 
TransferArrayBuffer(const FunctionCallbackInfo<Value> & args)217 void SerializerContext::TransferArrayBuffer(
218     const FunctionCallbackInfo<Value>& args) {
219   SerializerContext* ctx;
220   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
221 
222   Maybe<uint32_t> id = args[0]->Uint32Value(ctx->env()->context());
223   if (id.IsNothing()) return;
224 
225   if (!args[1]->IsArrayBuffer())
226     return node::THROW_ERR_INVALID_ARG_TYPE(
227         ctx->env(), "arrayBuffer must be an ArrayBuffer");
228 
229   Local<ArrayBuffer> ab = args[1].As<ArrayBuffer>();
230   ctx->serializer_.TransferArrayBuffer(id.FromJust(), ab);
231   return;
232 }
233 
WriteUint32(const FunctionCallbackInfo<Value> & args)234 void SerializerContext::WriteUint32(const FunctionCallbackInfo<Value>& args) {
235   SerializerContext* ctx;
236   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
237 
238   Maybe<uint32_t> value = args[0]->Uint32Value(ctx->env()->context());
239   if (value.IsNothing()) return;
240 
241   ctx->serializer_.WriteUint32(value.FromJust());
242 }
243 
WriteUint64(const FunctionCallbackInfo<Value> & args)244 void SerializerContext::WriteUint64(const FunctionCallbackInfo<Value>& args) {
245   SerializerContext* ctx;
246   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
247 
248   Maybe<uint32_t> arg0 = args[0]->Uint32Value(ctx->env()->context());
249   Maybe<uint32_t> arg1 = args[1]->Uint32Value(ctx->env()->context());
250   if (arg0.IsNothing() || arg1.IsNothing())
251     return;
252 
253   uint64_t hi = arg0.FromJust();
254   uint64_t lo = arg1.FromJust();
255   ctx->serializer_.WriteUint64((hi << 32) | lo);
256 }
257 
WriteDouble(const FunctionCallbackInfo<Value> & args)258 void SerializerContext::WriteDouble(const FunctionCallbackInfo<Value>& args) {
259   SerializerContext* ctx;
260   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
261 
262   Maybe<double> value = args[0]->NumberValue(ctx->env()->context());
263   if (value.IsNothing()) return;
264 
265   ctx->serializer_.WriteDouble(value.FromJust());
266 }
267 
WriteRawBytes(const FunctionCallbackInfo<Value> & args)268 void SerializerContext::WriteRawBytes(const FunctionCallbackInfo<Value>& args) {
269   SerializerContext* ctx;
270   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
271 
272   if (!args[0]->IsArrayBufferView()) {
273     return node::THROW_ERR_INVALID_ARG_TYPE(
274         ctx->env(), "source must be a TypedArray or a DataView");
275   }
276 
277   ArrayBufferViewContents<char> bytes(args[0]);
278   ctx->serializer_.WriteRawBytes(bytes.data(), bytes.length());
279 }
280 
DeserializerContext(Environment * env,Local<Object> wrap,Local<Value> buffer)281 DeserializerContext::DeserializerContext(Environment* env,
282                                          Local<Object> wrap,
283                                          Local<Value> buffer)
284   : BaseObject(env, wrap),
285     data_(reinterpret_cast<const uint8_t*>(Buffer::Data(buffer))),
286     length_(Buffer::Length(buffer)),
287     deserializer_(env->isolate(), data_, length_, this) {
288   object()->Set(env->context(), env->buffer_string(), buffer).Check();
289   deserializer_.SetExpectInlineWasm(true);
290 
291   MakeWeak();
292 }
293 
ReadHostObject(Isolate * isolate)294 MaybeLocal<Object> DeserializerContext::ReadHostObject(Isolate* isolate) {
295   Local<Value> read_host_object =
296       object()->Get(env()->context(),
297                     env()->read_host_object_string()).ToLocalChecked();
298 
299   if (!read_host_object->IsFunction()) {
300     return ValueDeserializer::Delegate::ReadHostObject(isolate);
301   }
302 
303   Isolate::AllowJavascriptExecutionScope allow_js(isolate);
304   MaybeLocal<Value> ret =
305       read_host_object.As<Function>()->Call(env()->context(),
306                                             object(),
307                                             0,
308                                             nullptr);
309 
310   if (ret.IsEmpty())
311     return MaybeLocal<Object>();
312 
313   Local<Value> return_value = ret.ToLocalChecked();
314   if (!return_value->IsObject()) {
315     env()->ThrowTypeError("readHostObject must return an object");
316     return MaybeLocal<Object>();
317   }
318 
319   return return_value.As<Object>();
320 }
321 
New(const FunctionCallbackInfo<Value> & args)322 void DeserializerContext::New(const FunctionCallbackInfo<Value>& args) {
323   Environment* env = Environment::GetCurrent(args);
324 
325   if (!args[0]->IsArrayBufferView()) {
326     return node::THROW_ERR_INVALID_ARG_TYPE(
327         env, "buffer must be a TypedArray or a DataView");
328   }
329 
330   new DeserializerContext(env, args.This(), args[0]);
331 }
332 
ReadHeader(const FunctionCallbackInfo<Value> & args)333 void DeserializerContext::ReadHeader(const FunctionCallbackInfo<Value>& args) {
334   DeserializerContext* ctx;
335   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
336 
337   Maybe<bool> ret = ctx->deserializer_.ReadHeader(ctx->env()->context());
338 
339   if (ret.IsJust()) args.GetReturnValue().Set(ret.FromJust());
340 }
341 
ReadValue(const FunctionCallbackInfo<Value> & args)342 void DeserializerContext::ReadValue(const FunctionCallbackInfo<Value>& args) {
343   DeserializerContext* ctx;
344   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
345 
346   MaybeLocal<Value> ret = ctx->deserializer_.ReadValue(ctx->env()->context());
347 
348   if (!ret.IsEmpty()) args.GetReturnValue().Set(ret.ToLocalChecked());
349 }
350 
TransferArrayBuffer(const FunctionCallbackInfo<Value> & args)351 void DeserializerContext::TransferArrayBuffer(
352     const FunctionCallbackInfo<Value>& args) {
353   DeserializerContext* ctx;
354   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
355 
356   Maybe<uint32_t> id = args[0]->Uint32Value(ctx->env()->context());
357   if (id.IsNothing()) return;
358 
359   if (args[1]->IsArrayBuffer()) {
360     Local<ArrayBuffer> ab = args[1].As<ArrayBuffer>();
361     ctx->deserializer_.TransferArrayBuffer(id.FromJust(), ab);
362     return;
363   }
364 
365   if (args[1]->IsSharedArrayBuffer()) {
366     Local<SharedArrayBuffer> sab = args[1].As<SharedArrayBuffer>();
367     ctx->deserializer_.TransferSharedArrayBuffer(id.FromJust(), sab);
368     return;
369   }
370 
371   return node::THROW_ERR_INVALID_ARG_TYPE(
372       ctx->env(), "arrayBuffer must be an ArrayBuffer or SharedArrayBuffer");
373 }
374 
GetWireFormatVersion(const FunctionCallbackInfo<Value> & args)375 void DeserializerContext::GetWireFormatVersion(
376     const FunctionCallbackInfo<Value>& args) {
377   DeserializerContext* ctx;
378   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
379 
380   args.GetReturnValue().Set(ctx->deserializer_.GetWireFormatVersion());
381 }
382 
ReadUint32(const FunctionCallbackInfo<Value> & args)383 void DeserializerContext::ReadUint32(const FunctionCallbackInfo<Value>& args) {
384   DeserializerContext* ctx;
385   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
386 
387   uint32_t value;
388   bool ok = ctx->deserializer_.ReadUint32(&value);
389   if (!ok) return ctx->env()->ThrowError("ReadUint32() failed");
390   return args.GetReturnValue().Set(value);
391 }
392 
ReadUint64(const FunctionCallbackInfo<Value> & args)393 void DeserializerContext::ReadUint64(const FunctionCallbackInfo<Value>& args) {
394   DeserializerContext* ctx;
395   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
396 
397   uint64_t value;
398   bool ok = ctx->deserializer_.ReadUint64(&value);
399   if (!ok) return ctx->env()->ThrowError("ReadUint64() failed");
400 
401   uint32_t hi = static_cast<uint32_t>(value >> 32);
402   uint32_t lo = static_cast<uint32_t>(value);
403 
404   Isolate* isolate = ctx->env()->isolate();
405 
406   Local<Value> ret[] = {
407     Integer::NewFromUnsigned(isolate, hi),
408     Integer::NewFromUnsigned(isolate, lo)
409   };
410   return args.GetReturnValue().Set(Array::New(isolate, ret, arraysize(ret)));
411 }
412 
ReadDouble(const FunctionCallbackInfo<Value> & args)413 void DeserializerContext::ReadDouble(const FunctionCallbackInfo<Value>& args) {
414   DeserializerContext* ctx;
415   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
416 
417   double value;
418   bool ok = ctx->deserializer_.ReadDouble(&value);
419   if (!ok) return ctx->env()->ThrowError("ReadDouble() failed");
420   return args.GetReturnValue().Set(value);
421 }
422 
ReadRawBytes(const FunctionCallbackInfo<Value> & args)423 void DeserializerContext::ReadRawBytes(
424     const FunctionCallbackInfo<Value>& args) {
425   DeserializerContext* ctx;
426   ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
427 
428   Maybe<int64_t> length_arg = args[0]->IntegerValue(ctx->env()->context());
429   if (length_arg.IsNothing()) return;
430   size_t length = length_arg.FromJust();
431 
432   const void* data;
433   bool ok = ctx->deserializer_.ReadRawBytes(length, &data);
434   if (!ok) return ctx->env()->ThrowError("ReadRawBytes() failed");
435 
436   const uint8_t* position = reinterpret_cast<const uint8_t*>(data);
437   CHECK_GE(position, ctx->data_);
438   CHECK_LE(position + length, ctx->data_ + ctx->length_);
439 
440   const uint32_t offset = position - ctx->data_;
441   CHECK_EQ(ctx->data_ + offset, position);
442 
443   args.GetReturnValue().Set(offset);
444 }
445 
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)446 void Initialize(Local<Object> target,
447                 Local<Value> unused,
448                 Local<Context> context,
449                 void* priv) {
450   Environment* env = Environment::GetCurrent(context);
451   Local<FunctionTemplate> ser =
452       env->NewFunctionTemplate(SerializerContext::New);
453 
454   ser->InstanceTemplate()->SetInternalFieldCount(
455       SerializerContext::kInternalFieldCount);
456   ser->Inherit(BaseObject::GetConstructorTemplate(env));
457 
458   env->SetProtoMethod(ser, "writeHeader", SerializerContext::WriteHeader);
459   env->SetProtoMethod(ser, "writeValue", SerializerContext::WriteValue);
460   env->SetProtoMethod(ser, "releaseBuffer", SerializerContext::ReleaseBuffer);
461   env->SetProtoMethod(ser,
462                       "transferArrayBuffer",
463                       SerializerContext::TransferArrayBuffer);
464   env->SetProtoMethod(ser, "writeUint32", SerializerContext::WriteUint32);
465   env->SetProtoMethod(ser, "writeUint64", SerializerContext::WriteUint64);
466   env->SetProtoMethod(ser, "writeDouble", SerializerContext::WriteDouble);
467   env->SetProtoMethod(ser, "writeRawBytes", SerializerContext::WriteRawBytes);
468   env->SetProtoMethod(ser,
469                       "_setTreatArrayBufferViewsAsHostObjects",
470                       SerializerContext::SetTreatArrayBufferViewsAsHostObjects);
471 
472   Local<String> serializerString =
473       FIXED_ONE_BYTE_STRING(env->isolate(), "Serializer");
474   ser->SetClassName(serializerString);
475   target->Set(env->context(),
476               serializerString,
477               ser->GetFunction(env->context()).ToLocalChecked()).Check();
478 
479   Local<FunctionTemplate> des =
480       env->NewFunctionTemplate(DeserializerContext::New);
481 
482   des->InstanceTemplate()->SetInternalFieldCount(
483       DeserializerContext::kInternalFieldCount);
484   des->Inherit(BaseObject::GetConstructorTemplate(env));
485 
486   env->SetProtoMethod(des, "readHeader", DeserializerContext::ReadHeader);
487   env->SetProtoMethod(des, "readValue", DeserializerContext::ReadValue);
488   env->SetProtoMethod(des,
489                       "getWireFormatVersion",
490                       DeserializerContext::GetWireFormatVersion);
491   env->SetProtoMethod(des,
492                       "transferArrayBuffer",
493                       DeserializerContext::TransferArrayBuffer);
494   env->SetProtoMethod(des, "readUint32", DeserializerContext::ReadUint32);
495   env->SetProtoMethod(des, "readUint64", DeserializerContext::ReadUint64);
496   env->SetProtoMethod(des, "readDouble", DeserializerContext::ReadDouble);
497   env->SetProtoMethod(des, "_readRawBytes", DeserializerContext::ReadRawBytes);
498 
499   Local<String> deserializerString =
500       FIXED_ONE_BYTE_STRING(env->isolate(), "Deserializer");
501   des->SetClassName(deserializerString);
502   target->Set(env->context(),
503               deserializerString,
504               des->GetFunction(env->context()).ToLocalChecked()).Check();
505 }
506 
507 }  // anonymous namespace
508 }  // namespace node
509 
510 NODE_MODULE_CONTEXT_AWARE_INTERNAL(serdes, node::Initialize)
511