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