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