/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
v24.16.0
src/node_serdes.cc
554 строки
18 KB
James M Snell
src: make even more improvements to error handling
02 май 2025, 23:04
Не верифицирован
02 май 2025, 23:04
823559e
Код
Авторство
О чём код?
#include "base_object-inl.h" #include "node_buffer.h" #include "node_errors.h" #include "node_external_reference.h" #include "node_internals.h" #include "util-inl.h" namespace node { using v8::Array; using v8::ArrayBuffer; using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Integer; using v8::Isolate; using v8::Just; using v8::Local; using v8::Maybe; using v8::MaybeLocal; using v8::Nothing; using v8::Object; using v8::SharedArrayBuffer; using v8::String; using v8::Value; using v8::ValueDeserializer; using v8::ValueSerializer; namespace serdes { class SerializerContext : public BaseObject, public ValueSerializer::Delegate { public: SerializerContext(Environment* env, Local<Object> wrap); ~SerializerContext() override = default; void ThrowDataCloneError(Local<String> message) override; Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object) override; Maybe<uint32_t> GetSharedArrayBufferId( Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) override; static void SetTreatArrayBufferViewsAsHostObjects( const FunctionCallbackInfo<Value>& args); static void New(const FunctionCallbackInfo<Value>& args); static void WriteHeader(const FunctionCallbackInfo<Value>& args); static void WriteValue(const FunctionCallbackInfo<Value>& args); static void ReleaseBuffer(const FunctionCallbackInfo<Value>& args); static void TransferArrayBuffer(const FunctionCallbackInfo<Value>& args); static void WriteUint32(const FunctionCallbackInfo<Value>& args); static void WriteUint64(const FunctionCallbackInfo<Value>& args); static void WriteDouble(const FunctionCallbackInfo<Value>& args); static void WriteRawBytes(const FunctionCallbackInfo<Value>& args); SET_NO_MEMORY_INFO() SET_MEMORY_INFO_NAME(SerializerContext) SET_SELF_SIZE(SerializerContext) private: ValueSerializer serializer_; }; class DeserializerContext : public BaseObject, public ValueDeserializer::Delegate { public: DeserializerContext(Environment* env, Local<Object> wrap, Local<Value> buffer); ~DeserializerContext() override = default; MaybeLocal<Object> ReadHostObject(Isolate* isolate) override; static void New(const FunctionCallbackInfo<Value>& args); static void ReadHeader(const FunctionCallbackInfo<Value>& args); static void ReadValue(const FunctionCallbackInfo<Value>& args); static void TransferArrayBuffer(const FunctionCallbackInfo<Value>& args); static void GetWireFormatVersion(const FunctionCallbackInfo<Value>& args); static void ReadUint32(const FunctionCallbackInfo<Value>& args); static void ReadUint64(const FunctionCallbackInfo<Value>& args); static void ReadDouble(const FunctionCallbackInfo<Value>& args); static void ReadRawBytes(const FunctionCallbackInfo<Value>& args); SET_NO_MEMORY_INFO() SET_MEMORY_INFO_NAME(DeserializerContext) SET_SELF_SIZE(DeserializerContext) private: const uint8_t* data_; const size_t length_; ValueDeserializer deserializer_; }; SerializerContext::SerializerContext(Environment* env, Local<Object> wrap) : BaseObject(env, wrap), serializer_(env->isolate(), this) { MakeWeak(); } void SerializerContext::ThrowDataCloneError(Local<String> message) { Local<Value> args[1] = { message }; Local<Value> get_data_clone_error; if (!object() ->Get(env()->context(), env()->get_data_clone_error_string()) .ToLocal(&get_data_clone_error)) { // A superseding error will have been thrown by v8. return; } CHECK(get_data_clone_error->IsFunction()); Local<Value> error; if (get_data_clone_error.As<Function>() ->Call(env()->context(), object(), arraysize(args), args) .ToLocal(&error)) { env()->isolate()->ThrowException(error); } } Maybe<uint32_t> SerializerContext::GetSharedArrayBufferId( Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) { Local<Value> args[1] = { shared_array_buffer }; Local<Value> get_shared_array_buffer_id; if (!object() ->Get(env()->context(), env()->get_shared_array_buffer_id_string()) .ToLocal(&get_shared_array_buffer_id)) { return Nothing<uint32_t>(); } if (!get_shared_array_buffer_id->IsFunction()) { return ValueSerializer::Delegate::GetSharedArrayBufferId( isolate, shared_array_buffer); } Local<Value> id; if (!get_shared_array_buffer_id.As<Function>() ->Call(env()->context(), object(), arraysize(args), args) .ToLocal(&id)) { return Nothing<uint32_t>(); } return id->Uint32Value(env()->context()); } Maybe<bool> SerializerContext::WriteHostObject(Isolate* isolate, Local<Object> input) { Local<Value> args[1] = { input }; Local<Value> write_host_object; if (!object() ->Get(env()->context(), env()->write_host_object_string()) .ToLocal(&write_host_object)) { return Nothing<bool>(); } if (!write_host_object->IsFunction()) { return ValueSerializer::Delegate::WriteHostObject(isolate, input); } Local<Value> ret; if (!write_host_object.As<Function>() ->Call(env()->context(), object(), arraysize(args), args) .ToLocal(&ret)) { return Nothing<bool>(); } return Just(true); } void SerializerContext::New(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); if (!args.IsConstructCall()) { return THROW_ERR_CONSTRUCT_CALL_REQUIRED( env, "Class constructor Serializer cannot be invoked without 'new'"); } new SerializerContext(env, args.This()); } void SerializerContext::WriteHeader(const FunctionCallbackInfo<Value>& args) { SerializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); ctx->serializer_.WriteHeader(); } void SerializerContext::WriteValue(const FunctionCallbackInfo<Value>& args) { SerializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); bool ret; if (ctx->serializer_.WriteValue(ctx->env()->context(), args[0]).To(&ret)) { args.GetReturnValue().Set(ret); } } void SerializerContext::SetTreatArrayBufferViewsAsHostObjects( const FunctionCallbackInfo<Value>& args) { SerializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); bool value = args[0]->BooleanValue(ctx->env()->isolate()); ctx->serializer_.SetTreatArrayBufferViewsAsHostObjects(value); } void SerializerContext::ReleaseBuffer(const FunctionCallbackInfo<Value>& args) { SerializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); // Note: Both ValueSerializer and this Buffer::New() variant use malloc() // as the underlying allocator. std::pair<uint8_t*, size_t> ret = ctx->serializer_.Release(); Local<Object> buf; if (Buffer::New(ctx->env(), reinterpret_cast<char*>(ret.first), ret.second) .ToLocal(&buf)) { args.GetReturnValue().Set(buf); } } void SerializerContext::TransferArrayBuffer( const FunctionCallbackInfo<Value>& args) { SerializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); uint32_t id; if (!args[0]->Uint32Value(ctx->env()->context()).To(&id)) { return; } if (!args[1]->IsArrayBuffer()) { return node::THROW_ERR_INVALID_ARG_TYPE( ctx->env(), "arrayBuffer must be an ArrayBuffer"); } Local<ArrayBuffer> ab = args[1].As<ArrayBuffer>(); ctx->serializer_.TransferArrayBuffer(id, ab); } void SerializerContext::WriteUint32(const FunctionCallbackInfo<Value>& args) { SerializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); uint32_t value; if (args[0]->Uint32Value(ctx->env()->context()).To(&value)) { ctx->serializer_.WriteUint32(value); } } void SerializerContext::WriteUint64(const FunctionCallbackInfo<Value>& args) { SerializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); uint32_t hi; uint32_t lo; if (!args[0]->Uint32Value(ctx->env()->context()).To(&hi) || !args[1]->Uint32Value(ctx->env()->context()).To(&lo)) { return; } uint64_t hiu64 = hi; uint64_t lou64 = lo; ctx->serializer_.WriteUint64((hiu64 << 32) | lou64); } void SerializerContext::WriteDouble(const FunctionCallbackInfo<Value>& args) { SerializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); double value; if (args[0]->NumberValue(ctx->env()->context()).To(&value)) { ctx->serializer_.WriteDouble(value); } } void SerializerContext::WriteRawBytes(const FunctionCallbackInfo<Value>& args) { SerializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); if (!args[0]->IsArrayBufferView()) { return node::THROW_ERR_INVALID_ARG_TYPE( ctx->env(), "source must be a TypedArray or a DataView"); } ArrayBufferViewContents<char> bytes(args[0]); ctx->serializer_.WriteRawBytes(bytes.data(), bytes.length()); } DeserializerContext::DeserializerContext(Environment* env, Local<Object> wrap, Local<Value> buffer) : BaseObject(env, wrap), data_(reinterpret_cast<const uint8_t*>(Buffer::Data(buffer))), length_(Buffer::Length(buffer)), deserializer_(env->isolate(), data_, length_, this) { object()->Set(env->context(), env->buffer_string(), buffer).Check(); MakeWeak(); } MaybeLocal<Object> DeserializerContext::ReadHostObject(Isolate* isolate) { Local<Value> read_host_object; if (!object() ->Get(env()->context(), env()->read_host_object_string()) .ToLocal(&read_host_object)) { return {}; } if (!read_host_object->IsFunction()) { return ValueDeserializer::Delegate::ReadHostObject(isolate); } Isolate::AllowJavascriptExecutionScope allow_js(isolate); Local<Value> ret; if (!read_host_object.As<Function>() ->Call(env()->context(), object(), 0, nullptr) .ToLocal(&ret)) { return {}; } if (!ret->IsObject()) { env()->ThrowTypeError("readHostObject must return an object"); return {}; } return ret.As<Object>(); } void DeserializerContext::New(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); if (!args.IsConstructCall()) { return THROW_ERR_CONSTRUCT_CALL_REQUIRED( env, "Class constructor Deserializer cannot be invoked without 'new'"); } if (!args[0]->IsArrayBufferView()) { return node::THROW_ERR_INVALID_ARG_TYPE( env, "buffer must be a TypedArray or a DataView"); } new DeserializerContext(env, args.This(), args[0]); } void DeserializerContext::ReadHeader(const FunctionCallbackInfo<Value>& args) { DeserializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); bool ret; if (ctx->deserializer_.ReadHeader(ctx->env()->context()).To(&ret)) { args.GetReturnValue().Set(ret); } } void DeserializerContext::ReadValue(const FunctionCallbackInfo<Value>& args) { DeserializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); Local<Value> ret; if (ctx->deserializer_.ReadValue(ctx->env()->context()).ToLocal(&ret)) { args.GetReturnValue().Set(ret); } } void DeserializerContext::TransferArrayBuffer( const FunctionCallbackInfo<Value>& args) { DeserializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); uint32_t id; if (!args[0]->Uint32Value(ctx->env()->context()).To(&id)) { return; } if (args[1]->IsArrayBuffer()) { Local<ArrayBuffer> ab = args[1].As<ArrayBuffer>(); ctx->deserializer_.TransferArrayBuffer(id, ab); return; } if (args[1]->IsSharedArrayBuffer()) { Local<SharedArrayBuffer> sab = args[1].As<SharedArrayBuffer>(); ctx->deserializer_.TransferSharedArrayBuffer(id, sab); return; } return node::THROW_ERR_INVALID_ARG_TYPE( ctx->env(), "arrayBuffer must be an ArrayBuffer or SharedArrayBuffer"); } void DeserializerContext::GetWireFormatVersion( const FunctionCallbackInfo<Value>& args) { DeserializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); args.GetReturnValue().Set(ctx->deserializer_.GetWireFormatVersion()); } void DeserializerContext::ReadUint32(const FunctionCallbackInfo<Value>& args) { DeserializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); uint32_t value; bool ok = ctx->deserializer_.ReadUint32(&value); if (!ok) return ctx->env()->ThrowError("ReadUint32() failed"); return args.GetReturnValue().Set(value); } void DeserializerContext::ReadUint64(const FunctionCallbackInfo<Value>& args) { DeserializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); uint64_t value; bool ok = ctx->deserializer_.ReadUint64(&value); if (!ok) return ctx->env()->ThrowError("ReadUint64() failed"); uint32_t hi = static_cast<uint32_t>(value >> 32); uint32_t lo = static_cast<uint32_t>(value); Isolate* isolate = ctx->env()->isolate(); Local<Value> ret[] = { Integer::NewFromUnsigned(isolate, hi), Integer::NewFromUnsigned(isolate, lo) }; return args.GetReturnValue().Set(Array::New(isolate, ret, arraysize(ret))); } void DeserializerContext::ReadDouble(const FunctionCallbackInfo<Value>& args) { DeserializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); double value; bool ok = ctx->deserializer_.ReadDouble(&value); if (!ok) return ctx->env()->ThrowError("ReadDouble() failed"); return args.GetReturnValue().Set(value); } void DeserializerContext::ReadRawBytes( const FunctionCallbackInfo<Value>& args) { DeserializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); int64_t length_arg; if (!args[0]->IntegerValue(ctx->env()->context()).To(&length_arg)) { return; } size_t length = length_arg; const void* data; bool ok = ctx->deserializer_.ReadRawBytes(length, &data); if (!ok) return ctx->env()->ThrowError("ReadRawBytes() failed"); const uint8_t* position = reinterpret_cast<const uint8_t*>(data); CHECK_GE(position, ctx->data_); CHECK_LE(position + length, ctx->data_ + ctx->length_); const uint32_t offset = static_cast<uint32_t>(position - ctx->data_); CHECK_EQ(ctx->data_ + offset, position); args.GetReturnValue().Set(offset); } void Initialize(Local<Object> target, Local<Value> unused, Local<Context> context, void* priv) { Environment* env = Environment::GetCurrent(context); Isolate* isolate = env->isolate(); Local<FunctionTemplate> ser = NewFunctionTemplate(isolate, SerializerContext::New); ser->InstanceTemplate()->SetInternalFieldCount( SerializerContext::kInternalFieldCount); SetProtoMethod(isolate, ser, "writeHeader", SerializerContext::WriteHeader); SetProtoMethod(isolate, ser, "writeValue", SerializerContext::WriteValue); SetProtoMethod( isolate, ser, "releaseBuffer", SerializerContext::ReleaseBuffer); SetProtoMethod(isolate, ser, "transferArrayBuffer", SerializerContext::TransferArrayBuffer); SetProtoMethod(isolate, ser, "writeUint32", SerializerContext::WriteUint32); SetProtoMethod(isolate, ser, "writeUint64", SerializerContext::WriteUint64); SetProtoMethod(isolate, ser, "writeDouble", SerializerContext::WriteDouble); SetProtoMethod( isolate, ser, "writeRawBytes", SerializerContext::WriteRawBytes); SetProtoMethod(isolate, ser, "_setTreatArrayBufferViewsAsHostObjects", SerializerContext::SetTreatArrayBufferViewsAsHostObjects); ser->ReadOnlyPrototype(); SetConstructorFunction(context, target, "Serializer", ser); Local<FunctionTemplate> des = NewFunctionTemplate(isolate, DeserializerContext::New); des->InstanceTemplate()->SetInternalFieldCount( DeserializerContext::kInternalFieldCount); SetProtoMethod(isolate, des, "readHeader", DeserializerContext::ReadHeader); SetProtoMethod(isolate, des, "readValue", DeserializerContext::ReadValue); SetProtoMethod(isolate, des, "getWireFormatVersion", DeserializerContext::GetWireFormatVersion); SetProtoMethod(isolate, des, "transferArrayBuffer", DeserializerContext::TransferArrayBuffer); SetProtoMethod(isolate, des, "readUint32", DeserializerContext::ReadUint32); SetProtoMethod(isolate, des, "readUint64", DeserializerContext::ReadUint64); SetProtoMethod(isolate, des, "readDouble", DeserializerContext::ReadDouble); SetProtoMethod( isolate, des, "_readRawBytes", DeserializerContext::ReadRawBytes); des->SetLength(1); des->ReadOnlyPrototype(); SetConstructorFunction(context, target, "Deserializer", des); } void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(SerializerContext::New); registry->Register(SerializerContext::WriteHeader); registry->Register(SerializerContext::WriteValue); registry->Register(SerializerContext::ReleaseBuffer); registry->Register(SerializerContext::TransferArrayBuffer); registry->Register(SerializerContext::WriteUint32); registry->Register(SerializerContext::WriteUint64); registry->Register(SerializerContext::WriteDouble); registry->Register(SerializerContext::WriteRawBytes); registry->Register(SerializerContext::SetTreatArrayBufferViewsAsHostObjects); registry->Register(DeserializerContext::New); registry->Register(DeserializerContext::ReadHeader); registry->Register(DeserializerContext::ReadValue); registry->Register(DeserializerContext::GetWireFormatVersion); registry->Register(DeserializerContext::TransferArrayBuffer); registry->Register(DeserializerContext::ReadUint32); registry->Register(DeserializerContext::ReadUint64); registry->Register(DeserializerContext::ReadDouble); registry->Register(DeserializerContext::ReadRawBytes); } } // namespace serdes } // namespace node NODE_BINDING_CONTEXT_AWARE_INTERNAL(serdes, node::serdes::Initialize) NODE_BINDING_EXTERNAL_REFERENCE(serdes, node::serdes::RegisterExternalReferences)