src: allocate Buffer memory using ArrayBuffer allocator
Always use the right allocator for memory that is turned into
an `ArrayBuffer` at a later point.
This enables embedders to use their own `ArrayBuffer::Allocator`s,
and is inspired by Electron’s electron/node@f61bae3440. It should
render their downstream patch unnecessary.
Refs: f61bae3440
PR-URL: https://github.com/nodejs/node/pull/26207
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
parent
6c257cdf27
commit
84e02b178a
@ -54,17 +54,6 @@
|
|||||||
size_t length = end - start;
|
size_t length = end - start;
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
inline void* BufferMalloc(size_t length) {
|
|
||||||
return per_process::cli_options->zero_fill_all_buffers ?
|
|
||||||
node::UncheckedCalloc(length) :
|
|
||||||
node::UncheckedMalloc(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace Buffer {
|
namespace Buffer {
|
||||||
|
|
||||||
using v8::ArrayBuffer;
|
using v8::ArrayBuffer;
|
||||||
@ -260,7 +249,7 @@ MaybeLocal<Object> New(Isolate* isolate,
|
|||||||
char* data = nullptr;
|
char* data = nullptr;
|
||||||
|
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
data = static_cast<char*>(BufferMalloc(length));
|
data = UncheckedMalloc(length);
|
||||||
|
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate);
|
THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate);
|
||||||
@ -278,13 +267,7 @@ MaybeLocal<Object> New(Isolate* isolate,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Object> buf;
|
return scope.EscapeMaybe(New(isolate, data, actual));
|
||||||
if (New(isolate, data, actual).ToLocal(&buf))
|
|
||||||
return scope.Escape(buf);
|
|
||||||
|
|
||||||
// Object failed to be created. Clean up resources.
|
|
||||||
free(data);
|
|
||||||
return Local<Object>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -311,26 +294,16 @@ MaybeLocal<Object> New(Environment* env, size_t length) {
|
|||||||
return Local<Object>();
|
return Local<Object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* data;
|
AllocatedBuffer ret(env);
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
data = BufferMalloc(length);
|
ret = env->AllocateManaged(length, false);
|
||||||
if (data == nullptr) {
|
if (ret.data() == nullptr) {
|
||||||
THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
|
THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
|
||||||
return Local<Object>();
|
return Local<Object>();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
data = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<ArrayBuffer> ab =
|
return scope.EscapeMaybe(ret.ToBuffer());
|
||||||
ArrayBuffer::New(env->isolate(),
|
|
||||||
data,
|
|
||||||
length,
|
|
||||||
ArrayBufferCreationMode::kInternalized);
|
|
||||||
Local<Object> obj;
|
|
||||||
if (Buffer::New(env, ab, 0, length).ToLocal(&obj))
|
|
||||||
return scope.Escape(obj);
|
|
||||||
return Local<Object>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -357,28 +330,18 @@ MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
|
|||||||
return Local<Object>();
|
return Local<Object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* new_data;
|
AllocatedBuffer ret(env);
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
CHECK_NOT_NULL(data);
|
CHECK_NOT_NULL(data);
|
||||||
new_data = node::UncheckedMalloc(length);
|
ret = env->AllocateManaged(length, false);
|
||||||
if (new_data == nullptr) {
|
if (ret.data() == nullptr) {
|
||||||
THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
|
THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
|
||||||
return Local<Object>();
|
return Local<Object>();
|
||||||
}
|
}
|
||||||
memcpy(new_data, data, length);
|
memcpy(ret.data(), data, length);
|
||||||
} else {
|
|
||||||
new_data = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<ArrayBuffer> ab =
|
return scope.EscapeMaybe(ret.ToBuffer());
|
||||||
ArrayBuffer::New(env->isolate(),
|
|
||||||
new_data,
|
|
||||||
length,
|
|
||||||
ArrayBufferCreationMode::kInternalized);
|
|
||||||
Local<Object> obj;
|
|
||||||
if (Buffer::New(env, ab, 0, length).ToLocal(&obj))
|
|
||||||
return scope.Escape(obj);
|
|
||||||
return Local<Object>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -425,7 +388,8 @@ MaybeLocal<Object> New(Environment* env,
|
|||||||
return scope.Escape(ui.ToLocalChecked());
|
return scope.Escape(ui.ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Warning: This function needs `data` to be allocated with malloc() and not
|
||||||
|
// necessarily isolate's ArrayBuffer::Allocator.
|
||||||
MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
|
MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
|
||||||
EscapableHandleScope handle_scope(isolate);
|
EscapableHandleScope handle_scope(isolate);
|
||||||
Environment* env = Environment::GetCurrent(isolate);
|
Environment* env = Environment::GetCurrent(isolate);
|
||||||
@ -435,18 +399,37 @@ MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
|
|||||||
return MaybeLocal<Object>();
|
return MaybeLocal<Object>();
|
||||||
}
|
}
|
||||||
Local<Object> obj;
|
Local<Object> obj;
|
||||||
if (Buffer::New(env, data, length).ToLocal(&obj))
|
if (Buffer::New(env, data, length, true).ToLocal(&obj))
|
||||||
return handle_scope.Escape(obj);
|
return handle_scope.Escape(obj);
|
||||||
return Local<Object>();
|
return Local<Object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Warning: If this call comes through the public node_buffer.h API,
|
||||||
MaybeLocal<Object> New(Environment* env, char* data, size_t length) {
|
// the contract for this function is that `data` is allocated with malloc()
|
||||||
|
// and not necessarily isolate's ArrayBuffer::Allocator.
|
||||||
|
MaybeLocal<Object> New(Environment* env,
|
||||||
|
char* data,
|
||||||
|
size_t length,
|
||||||
|
bool uses_malloc) {
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
CHECK_NOT_NULL(data);
|
CHECK_NOT_NULL(data);
|
||||||
CHECK(length <= kMaxLength);
|
CHECK(length <= kMaxLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (uses_malloc) {
|
||||||
|
if (env->isolate_data()->uses_node_allocator()) {
|
||||||
|
// We don't know for sure that the allocator is malloc()-based, so we need
|
||||||
|
// to fall back to the FreeCallback variant.
|
||||||
|
auto free_callback = [](char* data, void* hint) { free(data); };
|
||||||
|
return New(env, data, length, free_callback, nullptr);
|
||||||
|
} else {
|
||||||
|
// This is malloc()-based, so we can acquire it into our own
|
||||||
|
// ArrayBufferAllocator.
|
||||||
|
CHECK_NOT_NULL(env->isolate_data()->node_allocator());
|
||||||
|
env->isolate_data()->node_allocator()->RegisterPointer(data, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Local<ArrayBuffer> ab =
|
Local<ArrayBuffer> ab =
|
||||||
ArrayBuffer::New(env->isolate(),
|
ArrayBuffer::New(env->isolate(),
|
||||||
data,
|
data,
|
||||||
@ -1053,15 +1036,13 @@ static void EncodeUtf8String(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
Local<String> str = args[0].As<String>();
|
Local<String> str = args[0].As<String>();
|
||||||
size_t length = str->Utf8Length(isolate);
|
size_t length = str->Utf8Length(isolate);
|
||||||
char* data = node::UncheckedMalloc(length);
|
AllocatedBuffer buf = env->AllocateManaged(length);
|
||||||
str->WriteUtf8(isolate,
|
str->WriteUtf8(isolate,
|
||||||
data,
|
buf.data(),
|
||||||
-1, // We are certain that `data` is sufficiently large
|
-1, // We are certain that `data` is sufficiently large
|
||||||
nullptr,
|
nullptr,
|
||||||
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
|
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
|
||||||
auto array_buf = ArrayBuffer::New(
|
auto array = Uint8Array::New(buf.ToArrayBuffer(), 0, length);
|
||||||
isolate, data, length, ArrayBufferCreationMode::kInternalized);
|
|
||||||
auto array = Uint8Array::New(array_buf, 0, length);
|
|
||||||
args.GetReturnValue().Set(array);
|
args.GetReturnValue().Set(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1123,7 +1104,8 @@ void Initialize(Local<Object> target,
|
|||||||
|
|
||||||
// It can be a nullptr when running inside an isolate where we
|
// It can be a nullptr when running inside an isolate where we
|
||||||
// do not own the ArrayBuffer allocator.
|
// do not own the ArrayBuffer allocator.
|
||||||
if (uint32_t* zero_fill_field = env->isolate_data()->zero_fill_field()) {
|
if (ArrayBufferAllocator* allocator = env->isolate_data()->node_allocator()) {
|
||||||
|
uint32_t* zero_fill_field = allocator->zero_fill_field();
|
||||||
Local<ArrayBuffer> array_buffer = ArrayBuffer::New(
|
Local<ArrayBuffer> array_buffer = ArrayBuffer::New(
|
||||||
env->isolate(), zero_fill_field, sizeof(*zero_fill_field));
|
env->isolate(), zero_fill_field, sizeof(*zero_fill_field));
|
||||||
CHECK(target
|
CHECK(target
|
||||||
|
@ -52,15 +52,6 @@ static const int X509_NAME_FLAGS = ASN1_STRFLGS_ESC_CTRL
|
|||||||
| XN_FLAG_FN_SN;
|
| XN_FLAG_FN_SN;
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
namespace Buffer {
|
|
||||||
// OpenSSL uses `unsigned char*` for raw data, make this easier for us.
|
|
||||||
v8::MaybeLocal<v8::Object> New(Environment* env, unsigned char* udata,
|
|
||||||
size_t length) {
|
|
||||||
char* data = reinterpret_cast<char*>(udata);
|
|
||||||
return Buffer::New(env, data, length);
|
|
||||||
}
|
|
||||||
} // namespace Buffer
|
|
||||||
|
|
||||||
namespace crypto {
|
namespace crypto {
|
||||||
|
|
||||||
using node::THROW_ERR_TLS_INVALID_PROTOCOL_METHOD;
|
using node::THROW_ERR_TLS_INVALID_PROTOCOL_METHOD;
|
||||||
@ -1651,13 +1642,18 @@ static MaybeLocal<Object> ECPointToBuffer(Environment* env,
|
|||||||
if (error != nullptr) *error = "Failed to get public key length";
|
if (error != nullptr) *error = "Failed to get public key length";
|
||||||
return MaybeLocal<Object>();
|
return MaybeLocal<Object>();
|
||||||
}
|
}
|
||||||
MallocedBuffer<unsigned char> buf(len);
|
AllocatedBuffer buf = env->AllocateManaged(len);
|
||||||
len = EC_POINT_point2oct(group, point, form, buf.data, buf.size, nullptr);
|
len = EC_POINT_point2oct(group,
|
||||||
|
point,
|
||||||
|
form,
|
||||||
|
reinterpret_cast<unsigned char*>(buf.data()),
|
||||||
|
buf.size(),
|
||||||
|
nullptr);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
if (error != nullptr) *error = "Failed to get public key";
|
if (error != nullptr) *error = "Failed to get public key";
|
||||||
return MaybeLocal<Object>();
|
return MaybeLocal<Object>();
|
||||||
}
|
}
|
||||||
return Buffer::New(env, buf.release(), len);
|
return buf.ToBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2036,9 +2032,9 @@ void SSLWrap<Base>::GetFinished(const FunctionCallbackInfo<Value>& args) {
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char* buf = Malloc(len);
|
AllocatedBuffer buf = env->AllocateManaged(len);
|
||||||
CHECK_EQ(len, SSL_get_finished(w->ssl_.get(), buf, len));
|
CHECK_EQ(len, SSL_get_finished(w->ssl_.get(), buf.data(), len));
|
||||||
args.GetReturnValue().Set(Buffer::New(env, buf, len).ToLocalChecked());
|
args.GetReturnValue().Set(buf.ToBuffer().ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2059,9 +2055,9 @@ void SSLWrap<Base>::GetPeerFinished(const FunctionCallbackInfo<Value>& args) {
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char* buf = Malloc(len);
|
AllocatedBuffer buf = env->AllocateManaged(len);
|
||||||
CHECK_EQ(len, SSL_get_peer_finished(w->ssl_.get(), buf, len));
|
CHECK_EQ(len, SSL_get_peer_finished(w->ssl_.get(), buf.data(), len));
|
||||||
args.GetReturnValue().Set(Buffer::New(env, buf, len).ToLocalChecked());
|
args.GetReturnValue().Set(buf.ToBuffer().ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2079,10 +2075,10 @@ void SSLWrap<Base>::GetSession(const FunctionCallbackInfo<Value>& args) {
|
|||||||
int slen = i2d_SSL_SESSION(sess, nullptr);
|
int slen = i2d_SSL_SESSION(sess, nullptr);
|
||||||
CHECK_GT(slen, 0);
|
CHECK_GT(slen, 0);
|
||||||
|
|
||||||
char* sbuf = Malloc(slen);
|
AllocatedBuffer sbuf = env->AllocateManaged(slen);
|
||||||
unsigned char* p = reinterpret_cast<unsigned char*>(sbuf);
|
unsigned char* p = reinterpret_cast<unsigned char*>(sbuf.data());
|
||||||
i2d_SSL_SESSION(sess, &p);
|
i2d_SSL_SESSION(sess, &p);
|
||||||
args.GetReturnValue().Set(Buffer::New(env, sbuf, slen).ToLocalChecked());
|
args.GetReturnValue().Set(sbuf.ToBuffer().ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3963,11 +3959,9 @@ void CipherBase::SetAAD(const FunctionCallbackInfo<Value>& args) {
|
|||||||
args.GetReturnValue().Set(b); // Possibly report invalid state failure
|
args.GetReturnValue().Set(b); // Possibly report invalid state failure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CipherBase::UpdateResult CipherBase::Update(const char* data,
|
CipherBase::UpdateResult CipherBase::Update(const char* data,
|
||||||
int len,
|
int len,
|
||||||
unsigned char** out,
|
AllocatedBuffer* out) {
|
||||||
int* out_len) {
|
|
||||||
if (!ctx_)
|
if (!ctx_)
|
||||||
return kErrorState;
|
return kErrorState;
|
||||||
MarkPopErrorOnReturn mark_pop_error_on_return;
|
MarkPopErrorOnReturn mark_pop_error_on_return;
|
||||||
@ -3985,27 +3979,27 @@ CipherBase::UpdateResult CipherBase::Update(const char* data,
|
|||||||
CHECK(MaybePassAuthTagToOpenSSL());
|
CHECK(MaybePassAuthTagToOpenSSL());
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_len = 0;
|
int buf_len = len + EVP_CIPHER_CTX_block_size(ctx_.get());
|
||||||
int buff_len = len + EVP_CIPHER_CTX_block_size(ctx_.get());
|
|
||||||
// For key wrapping algorithms, get output size by calling
|
// For key wrapping algorithms, get output size by calling
|
||||||
// EVP_CipherUpdate() with null output.
|
// EVP_CipherUpdate() with null output.
|
||||||
if (kind_ == kCipher && mode == EVP_CIPH_WRAP_MODE &&
|
if (kind_ == kCipher && mode == EVP_CIPH_WRAP_MODE &&
|
||||||
EVP_CipherUpdate(ctx_.get(),
|
EVP_CipherUpdate(ctx_.get(),
|
||||||
nullptr,
|
nullptr,
|
||||||
&buff_len,
|
&buf_len,
|
||||||
reinterpret_cast<const unsigned char*>(data),
|
reinterpret_cast<const unsigned char*>(data),
|
||||||
len) != 1) {
|
len) != 1) {
|
||||||
return kErrorState;
|
return kErrorState;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = Malloc<unsigned char>(buff_len);
|
*out = env()->AllocateManaged(buf_len);
|
||||||
int r = EVP_CipherUpdate(ctx_.get(),
|
int r = EVP_CipherUpdate(ctx_.get(),
|
||||||
*out,
|
reinterpret_cast<unsigned char*>(out->data()),
|
||||||
out_len,
|
&buf_len,
|
||||||
reinterpret_cast<const unsigned char*>(data),
|
reinterpret_cast<const unsigned char*>(data),
|
||||||
len);
|
len);
|
||||||
|
|
||||||
CHECK_LE(*out_len, buff_len);
|
CHECK_LE(static_cast<size_t>(buf_len), out->size());
|
||||||
|
out->Resize(buf_len);
|
||||||
|
|
||||||
// When in CCM mode, EVP_CipherUpdate will fail if the authentication tag is
|
// When in CCM mode, EVP_CipherUpdate will fail if the authentication tag is
|
||||||
// invalid. In that case, remember the error and throw in final().
|
// invalid. In that case, remember the error and throw in final().
|
||||||
@ -4023,9 +4017,8 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
|
|||||||
CipherBase* cipher;
|
CipherBase* cipher;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
|
||||||
|
|
||||||
unsigned char* out = nullptr;
|
AllocatedBuffer out;
|
||||||
UpdateResult r;
|
UpdateResult r;
|
||||||
int out_len = 0;
|
|
||||||
|
|
||||||
// Only copy the data if we have to, because it's a string
|
// Only copy the data if we have to, because it's a string
|
||||||
if (args[0]->IsString()) {
|
if (args[0]->IsString()) {
|
||||||
@ -4033,15 +4026,14 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
|
|||||||
if (!decoder.Decode(env, args[0].As<String>(), args[1], UTF8)
|
if (!decoder.Decode(env, args[0].As<String>(), args[1], UTF8)
|
||||||
.FromMaybe(false))
|
.FromMaybe(false))
|
||||||
return;
|
return;
|
||||||
r = cipher->Update(decoder.out(), decoder.size(), &out, &out_len);
|
r = cipher->Update(decoder.out(), decoder.size(), &out);
|
||||||
} else {
|
} else {
|
||||||
char* buf = Buffer::Data(args[0]);
|
char* buf = Buffer::Data(args[0]);
|
||||||
size_t buflen = Buffer::Length(args[0]);
|
size_t buflen = Buffer::Length(args[0]);
|
||||||
r = cipher->Update(buf, buflen, &out, &out_len);
|
r = cipher->Update(buf, buflen, &out);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r != kSuccess) {
|
if (r != kSuccess) {
|
||||||
free(out);
|
|
||||||
if (r == kErrorState) {
|
if (r == kErrorState) {
|
||||||
ThrowCryptoError(env, ERR_get_error(),
|
ThrowCryptoError(env, ERR_get_error(),
|
||||||
"Trying to add data in unsupported state");
|
"Trying to add data in unsupported state");
|
||||||
@ -4049,11 +4041,9 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(out != nullptr || out_len == 0);
|
CHECK(out.data() != nullptr || out.size() == 0);
|
||||||
Local<Object> buf =
|
|
||||||
Buffer::New(env, reinterpret_cast<char*>(out), out_len).ToLocalChecked();
|
|
||||||
|
|
||||||
args.GetReturnValue().Set(buf);
|
args.GetReturnValue().Set(out.ToBuffer().ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4073,14 +4063,13 @@ void CipherBase::SetAutoPadding(const FunctionCallbackInfo<Value>& args) {
|
|||||||
args.GetReturnValue().Set(b); // Possibly report invalid state failure
|
args.GetReturnValue().Set(b); // Possibly report invalid state failure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CipherBase::Final(AllocatedBuffer* out) {
|
||||||
bool CipherBase::Final(unsigned char** out, int* out_len) {
|
|
||||||
if (!ctx_)
|
if (!ctx_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const int mode = EVP_CIPHER_CTX_mode(ctx_.get());
|
const int mode = EVP_CIPHER_CTX_mode(ctx_.get());
|
||||||
|
|
||||||
*out = Malloc<unsigned char>(
|
*out = env()->AllocateManaged(
|
||||||
static_cast<size_t>(EVP_CIPHER_CTX_block_size(ctx_.get())));
|
static_cast<size_t>(EVP_CIPHER_CTX_block_size(ctx_.get())));
|
||||||
|
|
||||||
if (kind_ == kDecipher && IsSupportedAuthenticatedMode(ctx_.get())) {
|
if (kind_ == kDecipher && IsSupportedAuthenticatedMode(ctx_.get())) {
|
||||||
@ -4092,8 +4081,17 @@ bool CipherBase::Final(unsigned char** out, int* out_len) {
|
|||||||
bool ok;
|
bool ok;
|
||||||
if (kind_ == kDecipher && mode == EVP_CIPH_CCM_MODE) {
|
if (kind_ == kDecipher && mode == EVP_CIPH_CCM_MODE) {
|
||||||
ok = !pending_auth_failed_;
|
ok = !pending_auth_failed_;
|
||||||
|
*out = AllocatedBuffer(env()); // Empty buffer.
|
||||||
} else {
|
} else {
|
||||||
ok = EVP_CipherFinal_ex(ctx_.get(), *out, out_len) == 1;
|
int out_len = out->size();
|
||||||
|
ok = EVP_CipherFinal_ex(ctx_.get(),
|
||||||
|
reinterpret_cast<unsigned char*>(out->data()),
|
||||||
|
&out_len) == 1;
|
||||||
|
|
||||||
|
if (out_len >= 0)
|
||||||
|
out->Resize(out_len);
|
||||||
|
else
|
||||||
|
*out = AllocatedBuffer(); // *out will not be used.
|
||||||
|
|
||||||
if (ok && kind_ == kCipher && IsAuthenticatedMode()) {
|
if (ok && kind_ == kCipher && IsAuthenticatedMode()) {
|
||||||
// In GCM mode, the authentication tag length can be specified in advance,
|
// In GCM mode, the authentication tag length can be specified in advance,
|
||||||
@ -4122,33 +4120,21 @@ void CipherBase::Final(const FunctionCallbackInfo<Value>& args) {
|
|||||||
ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder());
|
||||||
if (cipher->ctx_ == nullptr) return env->ThrowError("Unsupported state");
|
if (cipher->ctx_ == nullptr) return env->ThrowError("Unsupported state");
|
||||||
|
|
||||||
unsigned char* out_value = nullptr;
|
AllocatedBuffer out;
|
||||||
int out_len = -1;
|
|
||||||
|
|
||||||
// Check IsAuthenticatedMode() first, Final() destroys the EVP_CIPHER_CTX.
|
// Check IsAuthenticatedMode() first, Final() destroys the EVP_CIPHER_CTX.
|
||||||
const bool is_auth_mode = cipher->IsAuthenticatedMode();
|
const bool is_auth_mode = cipher->IsAuthenticatedMode();
|
||||||
bool r = cipher->Final(&out_value, &out_len);
|
bool r = cipher->Final(&out);
|
||||||
|
|
||||||
if (out_len <= 0 || !r) {
|
|
||||||
free(out_value);
|
|
||||||
out_value = nullptr;
|
|
||||||
out_len = 0;
|
|
||||||
if (!r) {
|
if (!r) {
|
||||||
const char* msg = is_auth_mode ?
|
const char* msg = is_auth_mode
|
||||||
"Unsupported state or unable to authenticate data" :
|
? "Unsupported state or unable to authenticate data"
|
||||||
"Unsupported state";
|
: "Unsupported state";
|
||||||
|
|
||||||
return ThrowCryptoError(env,
|
return ThrowCryptoError(env, ERR_get_error(), msg);
|
||||||
ERR_get_error(),
|
|
||||||
msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Object> buf = Buffer::New(
|
args.GetReturnValue().Set(out.ToBuffer().ToLocalChecked());
|
||||||
env,
|
|
||||||
reinterpret_cast<char*>(out_value),
|
|
||||||
out_len).ToLocalChecked();
|
|
||||||
args.GetReturnValue().Set(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4508,7 +4494,8 @@ void Sign::SignUpdate(const FunctionCallbackInfo<Value>& args) {
|
|||||||
sign->CheckThrow(err);
|
sign->CheckThrow(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MallocedBuffer<unsigned char> Node_SignFinal(EVPMDPointer&& mdctx,
|
static AllocatedBuffer Node_SignFinal(Environment* env,
|
||||||
|
EVPMDPointer&& mdctx,
|
||||||
const ManagedEVPPKey& pkey,
|
const ManagedEVPPKey& pkey,
|
||||||
int padding,
|
int padding,
|
||||||
int pss_salt_len) {
|
int pss_salt_len) {
|
||||||
@ -4516,12 +4503,12 @@ static MallocedBuffer<unsigned char> Node_SignFinal(EVPMDPointer&& mdctx,
|
|||||||
unsigned int m_len;
|
unsigned int m_len;
|
||||||
|
|
||||||
if (!EVP_DigestFinal_ex(mdctx.get(), m, &m_len))
|
if (!EVP_DigestFinal_ex(mdctx.get(), m, &m_len))
|
||||||
return MallocedBuffer<unsigned char>();
|
return AllocatedBuffer();
|
||||||
|
|
||||||
int signed_sig_len = EVP_PKEY_size(pkey.get());
|
int signed_sig_len = EVP_PKEY_size(pkey.get());
|
||||||
CHECK_GE(signed_sig_len, 0);
|
CHECK_GE(signed_sig_len, 0);
|
||||||
size_t sig_len = static_cast<size_t>(signed_sig_len);
|
size_t sig_len = static_cast<size_t>(signed_sig_len);
|
||||||
MallocedBuffer<unsigned char> sig(sig_len);
|
AllocatedBuffer sig = env->AllocateManaged(sig_len);
|
||||||
|
|
||||||
EVPKeyCtxPointer pkctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
|
EVPKeyCtxPointer pkctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
|
||||||
if (pkctx &&
|
if (pkctx &&
|
||||||
@ -4529,12 +4516,16 @@ static MallocedBuffer<unsigned char> Node_SignFinal(EVPMDPointer&& mdctx,
|
|||||||
ApplyRSAOptions(pkey, pkctx.get(), padding, pss_salt_len) &&
|
ApplyRSAOptions(pkey, pkctx.get(), padding, pss_salt_len) &&
|
||||||
EVP_PKEY_CTX_set_signature_md(pkctx.get(),
|
EVP_PKEY_CTX_set_signature_md(pkctx.get(),
|
||||||
EVP_MD_CTX_md(mdctx.get())) > 0 &&
|
EVP_MD_CTX_md(mdctx.get())) > 0 &&
|
||||||
EVP_PKEY_sign(pkctx.get(), sig.data, &sig_len, m, m_len) > 0) {
|
EVP_PKEY_sign(pkctx.get(),
|
||||||
sig.Truncate(sig_len);
|
reinterpret_cast<unsigned char*>(sig.data()),
|
||||||
|
&sig_len,
|
||||||
|
m,
|
||||||
|
m_len) > 0) {
|
||||||
|
sig.Resize(sig_len);
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MallocedBuffer<unsigned char>();
|
return AllocatedBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
Sign::SignResult Sign::SignFinal(
|
Sign::SignResult Sign::SignFinal(
|
||||||
@ -4573,16 +4564,14 @@ Sign::SignResult Sign::SignFinal(
|
|||||||
}
|
}
|
||||||
#endif // NODE_FIPS_MODE
|
#endif // NODE_FIPS_MODE
|
||||||
|
|
||||||
MallocedBuffer<unsigned char> buffer =
|
AllocatedBuffer buffer =
|
||||||
Node_SignFinal(std::move(mdctx), pkey, padding, salt_len);
|
Node_SignFinal(env(), std::move(mdctx), pkey, padding, salt_len);
|
||||||
Error error = buffer.is_empty() ? kSignPrivateKey : kSignOk;
|
Error error = buffer.data() == nullptr ? kSignPrivateKey : kSignOk;
|
||||||
return SignResult(error, std::move(buffer));
|
return SignResult(error, std::move(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Sign::SignFinal(const FunctionCallbackInfo<Value>& args) {
|
void Sign::SignFinal(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
|
||||||
|
|
||||||
Sign* sign;
|
Sign* sign;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&sign, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&sign, args.Holder());
|
||||||
|
|
||||||
@ -4607,13 +4596,7 @@ void Sign::SignFinal(const FunctionCallbackInfo<Value>& args) {
|
|||||||
if (ret.error != kSignOk)
|
if (ret.error != kSignOk)
|
||||||
return sign->CheckThrow(ret.error);
|
return sign->CheckThrow(ret.error);
|
||||||
|
|
||||||
MallocedBuffer<unsigned char> sig =
|
args.GetReturnValue().Set(ret.signature.ToBuffer().ToLocalChecked());
|
||||||
std::move(ret.signature);
|
|
||||||
|
|
||||||
Local<Object> rc =
|
|
||||||
Buffer::New(env, reinterpret_cast<char*>(sig.release()), sig.size)
|
|
||||||
.ToLocalChecked();
|
|
||||||
args.GetReturnValue().Set(rc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Verify::Initialize(Environment* env, Local<Object> target) {
|
void Verify::Initialize(Environment* env, Local<Object> target) {
|
||||||
@ -4722,16 +4705,15 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) {
|
|||||||
args.GetReturnValue().Set(verify_result);
|
args.GetReturnValue().Set(verify_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <PublicKeyCipher::Operation operation,
|
template <PublicKeyCipher::Operation operation,
|
||||||
PublicKeyCipher::EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
PublicKeyCipher::EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
||||||
PublicKeyCipher::EVP_PKEY_cipher_t EVP_PKEY_cipher>
|
PublicKeyCipher::EVP_PKEY_cipher_t EVP_PKEY_cipher>
|
||||||
bool PublicKeyCipher::Cipher(const ManagedEVPPKey& pkey,
|
bool PublicKeyCipher::Cipher(Environment* env,
|
||||||
|
const ManagedEVPPKey& pkey,
|
||||||
int padding,
|
int padding,
|
||||||
const unsigned char* data,
|
const unsigned char* data,
|
||||||
int len,
|
int len,
|
||||||
unsigned char** out,
|
AllocatedBuffer* out) {
|
||||||
size_t* out_len) {
|
|
||||||
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
|
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return false;
|
return false;
|
||||||
@ -4740,14 +4722,21 @@ bool PublicKeyCipher::Cipher(const ManagedEVPPKey& pkey,
|
|||||||
if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), padding) <= 0)
|
if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), padding) <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (EVP_PKEY_cipher(ctx.get(), nullptr, out_len, data, len) <= 0)
|
size_t out_len = 0;
|
||||||
|
if (EVP_PKEY_cipher(ctx.get(), nullptr, &out_len, data, len) <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*out = Malloc<unsigned char>(*out_len);
|
*out = env->AllocateManaged(out_len);
|
||||||
|
|
||||||
if (EVP_PKEY_cipher(ctx.get(), *out, out_len, data, len) <= 0)
|
if (EVP_PKEY_cipher(ctx.get(),
|
||||||
|
reinterpret_cast<unsigned char*>(out->data()),
|
||||||
|
&out_len,
|
||||||
|
data,
|
||||||
|
len) <= 0) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->Resize(out_len);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4770,33 +4759,22 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
|
|||||||
uint32_t padding;
|
uint32_t padding;
|
||||||
if (!args[offset + 1]->Uint32Value(env->context()).To(&padding)) return;
|
if (!args[offset + 1]->Uint32Value(env->context()).To(&padding)) return;
|
||||||
|
|
||||||
unsigned char* out_value = nullptr;
|
AllocatedBuffer out;
|
||||||
size_t out_len = 0;
|
|
||||||
|
|
||||||
ClearErrorOnReturn clear_error_on_return;
|
ClearErrorOnReturn clear_error_on_return;
|
||||||
|
|
||||||
bool r = Cipher<operation, EVP_PKEY_cipher_init, EVP_PKEY_cipher>(
|
bool r = Cipher<operation, EVP_PKEY_cipher_init, EVP_PKEY_cipher>(
|
||||||
|
env,
|
||||||
pkey,
|
pkey,
|
||||||
padding,
|
padding,
|
||||||
reinterpret_cast<const unsigned char*>(buf),
|
reinterpret_cast<const unsigned char*>(buf),
|
||||||
len,
|
len,
|
||||||
&out_value,
|
&out);
|
||||||
&out_len);
|
|
||||||
|
|
||||||
if (out_len == 0 || !r) {
|
if (!r)
|
||||||
free(out_value);
|
return ThrowCryptoError(env, ERR_get_error());
|
||||||
out_value = nullptr;
|
|
||||||
out_len = 0;
|
|
||||||
if (!r) {
|
|
||||||
return ThrowCryptoError(env,
|
|
||||||
ERR_get_error());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Local<Object> vbuf =
|
args.GetReturnValue().Set(out.ToBuffer().ToLocalChecked());
|
||||||
Buffer::New(env, reinterpret_cast<char*>(out_value), out_len)
|
|
||||||
.ToLocalChecked();
|
|
||||||
args.GetReturnValue().Set(vbuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4961,10 +4939,11 @@ void DiffieHellman::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
|
|||||||
DH_get0_key(diffieHellman->dh_.get(), &pub_key, nullptr);
|
DH_get0_key(diffieHellman->dh_.get(), &pub_key, nullptr);
|
||||||
const int size = BN_num_bytes(pub_key);
|
const int size = BN_num_bytes(pub_key);
|
||||||
CHECK_GE(size, 0);
|
CHECK_GE(size, 0);
|
||||||
char* data = Malloc(size);
|
AllocatedBuffer data = env->AllocateManaged(size);
|
||||||
CHECK_EQ(size,
|
CHECK_EQ(size,
|
||||||
BN_bn2binpad(pub_key, reinterpret_cast<unsigned char*>(data), size));
|
BN_bn2binpad(
|
||||||
args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked());
|
pub_key, reinterpret_cast<unsigned char*>(data.data()), size));
|
||||||
|
args.GetReturnValue().Set(data.ToBuffer().ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -4981,10 +4960,11 @@ void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
|
|||||||
|
|
||||||
const int size = BN_num_bytes(num);
|
const int size = BN_num_bytes(num);
|
||||||
CHECK_GE(size, 0);
|
CHECK_GE(size, 0);
|
||||||
char* data = Malloc(size);
|
AllocatedBuffer data = env->AllocateManaged(size);
|
||||||
CHECK_EQ(size,
|
CHECK_EQ(
|
||||||
BN_bn2binpad(num, reinterpret_cast<unsigned char*>(data), size));
|
size,
|
||||||
args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked());
|
BN_bn2binpad(num, reinterpret_cast<unsigned char*>(data.data()), size));
|
||||||
|
args.GetReturnValue().Set(data.ToBuffer().ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiffieHellman::GetPrime(const FunctionCallbackInfo<Value>& args) {
|
void DiffieHellman::GetPrime(const FunctionCallbackInfo<Value>& args) {
|
||||||
@ -5042,9 +5022,9 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
|
|||||||
Buffer::Length(args[0]),
|
Buffer::Length(args[0]),
|
||||||
nullptr));
|
nullptr));
|
||||||
|
|
||||||
MallocedBuffer<char> data(DH_size(diffieHellman->dh_.get()));
|
AllocatedBuffer ret = env->AllocateManaged(DH_size(diffieHellman->dh_.get()));
|
||||||
|
|
||||||
int size = DH_compute_key(reinterpret_cast<unsigned char*>(data.data),
|
int size = DH_compute_key(reinterpret_cast<unsigned char*>(ret.data()),
|
||||||
key.get(),
|
key.get(),
|
||||||
diffieHellman->dh_.get());
|
diffieHellman->dh_.get());
|
||||||
|
|
||||||
@ -5079,14 +5059,13 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
|
|||||||
// DH_compute_key returns number of bytes in a remainder of exponent, which
|
// DH_compute_key returns number of bytes in a remainder of exponent, which
|
||||||
// may have less bytes than a prime number. Therefore add 0-padding to the
|
// may have less bytes than a prime number. Therefore add 0-padding to the
|
||||||
// allocated buffer.
|
// allocated buffer.
|
||||||
if (static_cast<size_t>(size) != data.size) {
|
if (static_cast<size_t>(size) != ret.size()) {
|
||||||
CHECK_GT(data.size, static_cast<size_t>(size));
|
CHECK_GT(ret.size(), static_cast<size_t>(size));
|
||||||
memmove(data.data + data.size - size, data.data, size);
|
memmove(ret.data() + ret.size() - size, ret.data(), size);
|
||||||
memset(data.data, 0, data.size - size);
|
memset(ret.data(), 0, ret.size() - size);
|
||||||
}
|
}
|
||||||
|
|
||||||
args.GetReturnValue().Set(
|
args.GetReturnValue().Set(ret.ToBuffer().ToLocalChecked());
|
||||||
Buffer::New(env->isolate(), data.release(), data.size).ToLocalChecked());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiffieHellman::SetKey(const FunctionCallbackInfo<Value>& args,
|
void DiffieHellman::SetKey(const FunctionCallbackInfo<Value>& args,
|
||||||
@ -5260,15 +5239,14 @@ void ECDH::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
|
|||||||
// NOTE: field_size is in bits
|
// NOTE: field_size is in bits
|
||||||
int field_size = EC_GROUP_get_degree(ecdh->group_);
|
int field_size = EC_GROUP_get_degree(ecdh->group_);
|
||||||
size_t out_len = (field_size + 7) / 8;
|
size_t out_len = (field_size + 7) / 8;
|
||||||
char* out = node::Malloc(out_len);
|
AllocatedBuffer out = env->AllocateManaged(out_len);
|
||||||
|
|
||||||
int r = ECDH_compute_key(out, out_len, pub.get(), ecdh->key_.get(), nullptr);
|
int r = ECDH_compute_key(
|
||||||
if (!r) {
|
out.data(), out_len, pub.get(), ecdh->key_.get(), nullptr);
|
||||||
free(out);
|
if (!r)
|
||||||
return env->ThrowError("Failed to compute ECDH key");
|
return env->ThrowError("Failed to compute ECDH key");
|
||||||
}
|
|
||||||
|
|
||||||
Local<Object> buf = Buffer::New(env, out, out_len).ToLocalChecked();
|
Local<Object> buf = out.ToBuffer().ToLocalChecked();
|
||||||
args.GetReturnValue().Set(buf);
|
args.GetReturnValue().Set(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5310,11 +5288,12 @@ void ECDH::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return env->ThrowError("Failed to get ECDH private key");
|
return env->ThrowError("Failed to get ECDH private key");
|
||||||
|
|
||||||
const int size = BN_num_bytes(b);
|
const int size = BN_num_bytes(b);
|
||||||
unsigned char* out = node::Malloc<unsigned char>(size);
|
AllocatedBuffer out = env->AllocateManaged(size);
|
||||||
CHECK_EQ(size, BN_bn2binpad(b, out, size));
|
CHECK_EQ(size, BN_bn2binpad(b,
|
||||||
|
reinterpret_cast<unsigned char*>(out.data()),
|
||||||
|
size));
|
||||||
|
|
||||||
Local<Object> buf =
|
Local<Object> buf = out.ToBuffer().ToLocalChecked();
|
||||||
Buffer::New(env, reinterpret_cast<char*>(out), size).ToLocalChecked();
|
|
||||||
args.GetReturnValue().Set(buf);
|
args.GetReturnValue().Set(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6066,31 +6045,28 @@ void VerifySpkac(const FunctionCallbackInfo<Value>& args) {
|
|||||||
args.GetReturnValue().Set(verify_result);
|
args.GetReturnValue().Set(verify_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AllocatedBuffer ExportPublicKey(Environment* env,
|
||||||
char* ExportPublicKey(const char* data, int len, size_t* size) {
|
const char* data,
|
||||||
char* buf = nullptr;
|
int len,
|
||||||
|
size_t* size) {
|
||||||
BIOPointer bio(BIO_new(BIO_s_mem()));
|
BIOPointer bio(BIO_new(BIO_s_mem()));
|
||||||
if (!bio)
|
if (!bio) return AllocatedBuffer();
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
NetscapeSPKIPointer spki(NETSCAPE_SPKI_b64_decode(data, len));
|
NetscapeSPKIPointer spki(NETSCAPE_SPKI_b64_decode(data, len));
|
||||||
if (!spki)
|
if (!spki) return AllocatedBuffer();
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
EVPKeyPointer pkey(NETSCAPE_SPKI_get_pubkey(spki.get()));
|
EVPKeyPointer pkey(NETSCAPE_SPKI_get_pubkey(spki.get()));
|
||||||
if (!pkey)
|
if (!pkey) return AllocatedBuffer();
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (PEM_write_bio_PUBKEY(bio.get(), pkey.get()) <= 0)
|
if (PEM_write_bio_PUBKEY(bio.get(), pkey.get()) <= 0)
|
||||||
return nullptr;
|
return AllocatedBuffer();
|
||||||
|
|
||||||
BUF_MEM* ptr;
|
BUF_MEM* ptr;
|
||||||
BIO_get_mem_ptr(bio.get(), &ptr);
|
BIO_get_mem_ptr(bio.get(), &ptr);
|
||||||
|
|
||||||
*size = ptr->length;
|
*size = ptr->length;
|
||||||
buf = Malloc(*size);
|
AllocatedBuffer buf = env->AllocateManaged(*size);
|
||||||
memcpy(buf, ptr->data, *size);
|
memcpy(buf.data(), ptr->data, *size);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
@ -6107,12 +6083,11 @@ void ExportPublicKey(const FunctionCallbackInfo<Value>& args) {
|
|||||||
CHECK_NOT_NULL(data);
|
CHECK_NOT_NULL(data);
|
||||||
|
|
||||||
size_t pkey_size;
|
size_t pkey_size;
|
||||||
char* pkey = ExportPublicKey(data, length, &pkey_size);
|
AllocatedBuffer pkey = ExportPublicKey(env, data, length, &pkey_size);
|
||||||
if (pkey == nullptr)
|
if (pkey.data() == nullptr)
|
||||||
return args.GetReturnValue().SetEmptyString();
|
return args.GetReturnValue().SetEmptyString();
|
||||||
|
|
||||||
Local<Value> out = Buffer::New(env, pkey, pkey_size).ToLocalChecked();
|
args.GetReturnValue().Set(pkey.ToBuffer().ToLocalChecked());
|
||||||
args.GetReturnValue().Set(out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -544,9 +544,8 @@ class CipherBase : public BaseObject {
|
|||||||
bool InitAuthenticated(const char* cipher_type, int iv_len,
|
bool InitAuthenticated(const char* cipher_type, int iv_len,
|
||||||
unsigned int auth_tag_len);
|
unsigned int auth_tag_len);
|
||||||
bool CheckCCMMessageLength(int message_len);
|
bool CheckCCMMessageLength(int message_len);
|
||||||
UpdateResult Update(const char* data, int len, unsigned char** out,
|
UpdateResult Update(const char* data, int len, AllocatedBuffer* out);
|
||||||
int* out_len);
|
bool Final(AllocatedBuffer* out);
|
||||||
bool Final(unsigned char** out, int* out_len);
|
|
||||||
bool SetAutoPadding(bool auto_padding);
|
bool SetAutoPadding(bool auto_padding);
|
||||||
|
|
||||||
bool IsAuthenticatedMode() const;
|
bool IsAuthenticatedMode() const;
|
||||||
@ -677,11 +676,11 @@ class Sign : public SignBase {
|
|||||||
|
|
||||||
struct SignResult {
|
struct SignResult {
|
||||||
Error error;
|
Error error;
|
||||||
MallocedBuffer<unsigned char> signature;
|
AllocatedBuffer signature;
|
||||||
|
|
||||||
explicit SignResult(
|
explicit SignResult(
|
||||||
Error err,
|
Error err,
|
||||||
MallocedBuffer<unsigned char>&& sig = MallocedBuffer<unsigned char>())
|
AllocatedBuffer&& sig = AllocatedBuffer())
|
||||||
: error(err), signature(std::move(sig)) {}
|
: error(err), signature(std::move(sig)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -738,12 +737,12 @@ class PublicKeyCipher {
|
|||||||
template <Operation operation,
|
template <Operation operation,
|
||||||
EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
||||||
EVP_PKEY_cipher_t EVP_PKEY_cipher>
|
EVP_PKEY_cipher_t EVP_PKEY_cipher>
|
||||||
static bool Cipher(const ManagedEVPPKey& pkey,
|
static bool Cipher(Environment* env,
|
||||||
|
const ManagedEVPPKey& pkey,
|
||||||
int padding,
|
int padding,
|
||||||
const unsigned char* data,
|
const unsigned char* data,
|
||||||
int len,
|
int len,
|
||||||
unsigned char** out,
|
AllocatedBuffer* out);
|
||||||
size_t* out_len);
|
|
||||||
|
|
||||||
template <Operation operation,
|
template <Operation operation,
|
||||||
EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
using v8::ArrayBuffer;
|
using v8::ArrayBuffer;
|
||||||
using v8::ArrayBufferCreationMode;
|
|
||||||
using v8::Boolean;
|
using v8::Boolean;
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::Float64Array;
|
using v8::Float64Array;
|
||||||
@ -1767,18 +1766,22 @@ Http2Stream* Http2Session::SubmitRequest(
|
|||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uv_buf_t Http2Session::OnStreamAlloc(size_t suggested_size) {
|
||||||
|
return env()->AllocateManaged(suggested_size).release();
|
||||||
|
}
|
||||||
|
|
||||||
// Callback used to receive inbound data from the i/o stream
|
// Callback used to receive inbound data from the i/o stream
|
||||||
void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf) {
|
void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) {
|
||||||
HandleScope handle_scope(env()->isolate());
|
HandleScope handle_scope(env()->isolate());
|
||||||
Context::Scope context_scope(env()->context());
|
Context::Scope context_scope(env()->context());
|
||||||
Http2Scope h2scope(this);
|
Http2Scope h2scope(this);
|
||||||
CHECK_NOT_NULL(stream_);
|
CHECK_NOT_NULL(stream_);
|
||||||
Debug(this, "receiving %d bytes", nread);
|
Debug(this, "receiving %d bytes", nread);
|
||||||
CHECK(stream_buf_ab_.IsEmpty());
|
CHECK(stream_buf_ab_.IsEmpty());
|
||||||
|
AllocatedBuffer buf(env(), buf_);
|
||||||
|
|
||||||
// Only pass data on if nread > 0
|
// Only pass data on if nread > 0
|
||||||
if (nread <= 0) {
|
if (nread <= 0) {
|
||||||
free(buf.base);
|
|
||||||
if (nread < 0) {
|
if (nread < 0) {
|
||||||
PassReadErrorToPreviousListener(nread);
|
PassReadErrorToPreviousListener(nread);
|
||||||
}
|
}
|
||||||
@ -1786,13 +1789,13 @@ void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Shrink to the actual amount of used data.
|
// Shrink to the actual amount of used data.
|
||||||
char* base = Realloc(buf.base, nread);
|
buf.Resize(nread);
|
||||||
|
|
||||||
IncrementCurrentSessionMemory(nread);
|
IncrementCurrentSessionMemory(buf.size());
|
||||||
OnScopeLeave on_scope_leave([&]() {
|
OnScopeLeave on_scope_leave([&]() {
|
||||||
// Once finished handling this write, reset the stream buffer.
|
// Once finished handling this write, reset the stream buffer.
|
||||||
// The memory has either been free()d or was handed over to V8.
|
// The memory has either been free()d or was handed over to V8.
|
||||||
DecrementCurrentSessionMemory(nread);
|
DecrementCurrentSessionMemory(buf.size());
|
||||||
stream_buf_ab_ = Local<ArrayBuffer>();
|
stream_buf_ab_ = Local<ArrayBuffer>();
|
||||||
stream_buf_ = uv_buf_init(nullptr, 0);
|
stream_buf_ = uv_buf_init(nullptr, 0);
|
||||||
});
|
});
|
||||||
@ -1803,17 +1806,13 @@ void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf) {
|
|||||||
|
|
||||||
// Remember the current buffer, so that OnDataChunkReceived knows the
|
// Remember the current buffer, so that OnDataChunkReceived knows the
|
||||||
// offset of a DATA frame's data into the socket read buffer.
|
// offset of a DATA frame's data into the socket read buffer.
|
||||||
stream_buf_ = uv_buf_init(base, nread);
|
stream_buf_ = uv_buf_init(buf.data(), nread);
|
||||||
|
|
||||||
Isolate* isolate = env()->isolate();
|
Isolate* isolate = env()->isolate();
|
||||||
|
|
||||||
// Create an array buffer for the read data. DATA frames will be emitted
|
// Create an array buffer for the read data. DATA frames will be emitted
|
||||||
// as slices of this array buffer to avoid having to copy memory.
|
// as slices of this array buffer to avoid having to copy memory.
|
||||||
stream_buf_ab_ =
|
stream_buf_ab_ = buf.ToArrayBuffer();
|
||||||
ArrayBuffer::New(isolate,
|
|
||||||
base,
|
|
||||||
nread,
|
|
||||||
ArrayBufferCreationMode::kInternalized);
|
|
||||||
|
|
||||||
statistics_.data_received += nread;
|
statistics_.data_received += nread;
|
||||||
ssize_t ret = Write(&stream_buf_, 1);
|
ssize_t ret = Write(&stream_buf_, 1);
|
||||||
|
@ -783,6 +783,7 @@ class Http2Session : public AsyncWrap, public StreamListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle reads/writes from the underlying network transport.
|
// Handle reads/writes from the underlying network transport.
|
||||||
|
uv_buf_t OnStreamAlloc(size_t suggested_size) override;
|
||||||
void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;
|
void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;
|
||||||
void OnStreamAfterWrite(WriteWrap* w, int status) override;
|
void OnStreamAfterWrite(WriteWrap* w, int status) override;
|
||||||
|
|
||||||
|
@ -594,10 +594,9 @@ class Parser : public AsyncWrap, public StreamListener {
|
|||||||
uv_buf_t OnStreamAlloc(size_t suggested_size) override {
|
uv_buf_t OnStreamAlloc(size_t suggested_size) override {
|
||||||
// For most types of streams, OnStreamRead will be immediately after
|
// For most types of streams, OnStreamRead will be immediately after
|
||||||
// OnStreamAlloc, and will consume all data, so using a static buffer for
|
// OnStreamAlloc, and will consume all data, so using a static buffer for
|
||||||
// reading is more efficient. For other streams, just use the default
|
// reading is more efficient. For other streams, just use Malloc() directly.
|
||||||
// allocator, which uses Malloc().
|
|
||||||
if (env()->http_parser_buffer_in_use())
|
if (env()->http_parser_buffer_in_use())
|
||||||
return StreamListener::OnStreamAlloc(suggested_size);
|
return uv_buf_init(Malloc(suggested_size), suggested_size);
|
||||||
env()->set_http_parser_buffer_in_use(true);
|
env()->set_http_parser_buffer_in_use(true);
|
||||||
|
|
||||||
if (env()->http_parser_buffer() == nullptr)
|
if (env()->http_parser_buffer() == nullptr)
|
||||||
|
@ -146,10 +146,12 @@ v8::MaybeLocal<v8::Object> New(Environment* env,
|
|||||||
size_t length,
|
size_t length,
|
||||||
void (*callback)(char* data, void* hint),
|
void (*callback)(char* data, void* hint),
|
||||||
void* hint);
|
void* hint);
|
||||||
// Takes ownership of |data|. Must allocate |data| with malloc() or realloc()
|
// Takes ownership of |data|. Must allocate |data| with the current Isolate's
|
||||||
// because ArrayBufferAllocator::Free() deallocates it again with free().
|
// ArrayBuffer::Allocator().
|
||||||
// Mixing operator new and free() is undefined behavior so don't do that.
|
v8::MaybeLocal<v8::Object> New(Environment* env,
|
||||||
v8::MaybeLocal<v8::Object> New(Environment* env, char* data, size_t length);
|
char* data,
|
||||||
|
size_t length,
|
||||||
|
bool uses_malloc);
|
||||||
|
|
||||||
// Construct a Buffer from a MaybeStackBuffer (and also its subclasses like
|
// Construct a Buffer from a MaybeStackBuffer (and also its subclasses like
|
||||||
// Utf8Value and TwoByteValue).
|
// Utf8Value and TwoByteValue).
|
||||||
@ -167,7 +169,7 @@ static v8::MaybeLocal<v8::Object> New(Environment* env,
|
|||||||
const size_t len_in_bytes = buf->length() * sizeof(buf->out()[0]);
|
const size_t len_in_bytes = buf->length() * sizeof(buf->out()[0]);
|
||||||
|
|
||||||
if (buf->IsAllocated())
|
if (buf->IsAllocated())
|
||||||
ret = New(env, src, len_in_bytes);
|
ret = New(env, src, len_in_bytes, true);
|
||||||
else if (!buf->IsInvalidated())
|
else if (!buf->IsInvalidated())
|
||||||
ret = Copy(env, src, len_in_bytes);
|
ret = Copy(env, src, len_in_bytes);
|
||||||
|
|
||||||
|
@ -144,6 +144,9 @@ MaybeLocal<Value> Message::Deserialize(Environment* env,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
env->isolate_data()->node_allocator()->RegisterPointer(
|
||||||
|
array_buffer_contents_[i].data, array_buffer_contents_[i].size);
|
||||||
|
|
||||||
Local<ArrayBuffer> ab =
|
Local<ArrayBuffer> ab =
|
||||||
ArrayBuffer::New(env->isolate(),
|
ArrayBuffer::New(env->isolate(),
|
||||||
array_buffer_contents_[i].release(),
|
array_buffer_contents_[i].release(),
|
||||||
@ -367,6 +370,11 @@ Maybe<bool> Message::Serialize(Environment* env,
|
|||||||
// it inaccessible in this Isolate.
|
// it inaccessible in this Isolate.
|
||||||
ArrayBuffer::Contents contents = ab->Externalize();
|
ArrayBuffer::Contents contents = ab->Externalize();
|
||||||
ab->Neuter();
|
ab->Neuter();
|
||||||
|
|
||||||
|
CHECK(env->isolate_data()->uses_node_allocator());
|
||||||
|
env->isolate_data()->node_allocator()->UnregisterPointer(
|
||||||
|
contents.Data(), contents.ByteLength());
|
||||||
|
|
||||||
array_buffer_contents_.push_back(
|
array_buffer_contents_.push_back(
|
||||||
MallocedBuffer<char> { static_cast<char*>(contents.Data()),
|
MallocedBuffer<char> { static_cast<char*>(contents.Data()),
|
||||||
contents.ByteLength() });
|
contents.ByteLength() });
|
||||||
|
@ -11,7 +11,6 @@ namespace native_module {
|
|||||||
|
|
||||||
using v8::Array;
|
using v8::Array;
|
||||||
using v8::ArrayBuffer;
|
using v8::ArrayBuffer;
|
||||||
using v8::ArrayBufferCreationMode;
|
|
||||||
using v8::Context;
|
using v8::Context;
|
||||||
using v8::DEFAULT;
|
using v8::DEFAULT;
|
||||||
using v8::EscapableHandleScope;
|
using v8::EscapableHandleScope;
|
||||||
@ -153,13 +152,8 @@ MaybeLocal<Uint8Array> NativeModuleLoader::GetCodeCache(Isolate* isolate,
|
|||||||
|
|
||||||
cached_data = it->second.get();
|
cached_data = it->second.get();
|
||||||
|
|
||||||
MallocedBuffer<uint8_t> copied(cached_data->length);
|
Local<ArrayBuffer> buf = ArrayBuffer::New(isolate, cached_data->length);
|
||||||
memcpy(copied.data, cached_data->data, cached_data->length);
|
memcpy(buf->GetContents().Data(), cached_data->data, cached_data->length);
|
||||||
Local<ArrayBuffer> buf =
|
|
||||||
ArrayBuffer::New(isolate,
|
|
||||||
copied.release(),
|
|
||||||
cached_data->length,
|
|
||||||
ArrayBufferCreationMode::kInternalized);
|
|
||||||
return scope.Escape(Uint8Array::New(buf, 0, cached_data->length));
|
return scope.Escape(Uint8Array::New(buf, 0, cached_data->length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,10 +200,13 @@ void SerializerContext::ReleaseBuffer(const FunctionCallbackInfo<Value>& args) {
|
|||||||
SerializerContext* ctx;
|
SerializerContext* ctx;
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
|
ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
|
||||||
|
|
||||||
|
// Note: Both ValueSerializer and this Buffer::New() variant use malloc()
|
||||||
|
// as the underlying allocator.
|
||||||
std::pair<uint8_t*, size_t> ret = ctx->serializer_.Release();
|
std::pair<uint8_t*, size_t> ret = ctx->serializer_.Release();
|
||||||
auto buf = Buffer::New(ctx->env(),
|
auto buf = Buffer::New(ctx->env(),
|
||||||
reinterpret_cast<char*>(ret.first),
|
reinterpret_cast<char*>(ret.first),
|
||||||
ret.second);
|
ret.second,
|
||||||
|
true /* uses_malloc */);
|
||||||
|
|
||||||
if (!buf.IsEmpty()) {
|
if (!buf.IsEmpty()) {
|
||||||
args.GetReturnValue().Set(buf.ToLocalChecked());
|
args.GetReturnValue().Set(buf.ToLocalChecked());
|
||||||
|
@ -419,18 +419,9 @@ inline void ShutdownWrap::OnDone(int status) {
|
|||||||
Dispose();
|
Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WriteWrap::SetAllocatedStorage(char* data, size_t size) {
|
inline void WriteWrap::SetAllocatedStorage(AllocatedBuffer&& storage) {
|
||||||
CHECK_NULL(storage_);
|
CHECK_NULL(storage_.data());
|
||||||
storage_ = data;
|
storage_ = std::move(storage);
|
||||||
storage_size_ = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline char* WriteWrap::Storage() {
|
|
||||||
return storage_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline size_t WriteWrap::StorageSize() const {
|
|
||||||
return storage_size_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WriteWrap::OnDone(int status) {
|
inline void WriteWrap::OnDone(int status) {
|
||||||
|
@ -111,9 +111,9 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MallocedBuffer<char> storage;
|
AllocatedBuffer storage;
|
||||||
if (storage_size > 0)
|
if (storage_size > 0)
|
||||||
storage = MallocedBuffer<char>(storage_size);
|
storage = env->AllocateManaged(storage_size);
|
||||||
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
if (!all_buffers) {
|
if (!all_buffers) {
|
||||||
@ -129,8 +129,8 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
// Write string
|
// Write string
|
||||||
CHECK_LE(offset, storage_size);
|
CHECK_LE(offset, storage_size);
|
||||||
char* str_storage = storage.data + offset;
|
char* str_storage = storage.data() + offset;
|
||||||
size_t str_size = storage_size - offset;
|
size_t str_size = storage.size() - offset;
|
||||||
|
|
||||||
Local<String> string = chunk->ToString(env->context()).ToLocalChecked();
|
Local<String> string = chunk->ToString(env->context()).ToLocalChecked();
|
||||||
enum encoding encoding = ParseEncoding(env->isolate(),
|
enum encoding encoding = ParseEncoding(env->isolate(),
|
||||||
@ -149,7 +149,7 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
|
|||||||
StreamWriteResult res = Write(*bufs, count, nullptr, req_wrap_obj);
|
StreamWriteResult res = Write(*bufs, count, nullptr, req_wrap_obj);
|
||||||
SetWriteResult(res);
|
SetWriteResult(res);
|
||||||
if (res.wrap != nullptr && storage_size > 0) {
|
if (res.wrap != nullptr && storage_size > 0) {
|
||||||
res.wrap->SetAllocatedStorage(storage.release(), storage_size);
|
res.wrap->SetAllocatedStorage(std::move(storage));
|
||||||
}
|
}
|
||||||
return res.err;
|
return res.err;
|
||||||
}
|
}
|
||||||
@ -239,18 +239,18 @@ int StreamBase::WriteString(const FunctionCallbackInfo<Value>& args) {
|
|||||||
CHECK_EQ(count, 1);
|
CHECK_EQ(count, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
MallocedBuffer<char> data;
|
AllocatedBuffer data;
|
||||||
|
|
||||||
if (try_write) {
|
if (try_write) {
|
||||||
// Copy partial data
|
// Copy partial data
|
||||||
data = MallocedBuffer<char>(buf.len);
|
data = env->AllocateManaged(buf.len);
|
||||||
memcpy(data.data, buf.base, buf.len);
|
memcpy(data.data(), buf.base, buf.len);
|
||||||
data_size = buf.len;
|
data_size = buf.len;
|
||||||
} else {
|
} else {
|
||||||
// Write it
|
// Write it
|
||||||
data = MallocedBuffer<char>(storage_size);
|
data = env->AllocateManaged(storage_size);
|
||||||
data_size = StringBytes::Write(env->isolate(),
|
data_size = StringBytes::Write(env->isolate(),
|
||||||
data.data,
|
data.data(),
|
||||||
storage_size,
|
storage_size,
|
||||||
string,
|
string,
|
||||||
enc);
|
enc);
|
||||||
@ -258,7 +258,7 @@ int StreamBase::WriteString(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
CHECK_LE(data_size, storage_size);
|
CHECK_LE(data_size, storage_size);
|
||||||
|
|
||||||
buf = uv_buf_init(data.data, data_size);
|
buf = uv_buf_init(data.data(), data_size);
|
||||||
|
|
||||||
uv_stream_t* send_handle = nullptr;
|
uv_stream_t* send_handle = nullptr;
|
||||||
|
|
||||||
@ -278,7 +278,7 @@ int StreamBase::WriteString(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
SetWriteResult(res);
|
SetWriteResult(res);
|
||||||
if (res.wrap != nullptr) {
|
if (res.wrap != nullptr) {
|
||||||
res.wrap->SetAllocatedStorage(data.release(), data_size);
|
res.wrap->SetAllocatedStorage(std::move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.err;
|
return res.err;
|
||||||
@ -343,35 +343,30 @@ void StreamResource::ClearError() {
|
|||||||
// No-op
|
// No-op
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uv_buf_t EmitToJSStreamListener::OnStreamAlloc(size_t suggested_size) {
|
||||||
uv_buf_t StreamListener::OnStreamAlloc(size_t suggested_size) {
|
CHECK_NOT_NULL(stream_);
|
||||||
return uv_buf_init(Malloc(suggested_size), suggested_size);
|
Environment* env = static_cast<StreamBase*>(stream_)->stream_env();
|
||||||
|
return env->AllocateManaged(suggested_size).release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitToJSStreamListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) {
|
||||||
void EmitToJSStreamListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf) {
|
|
||||||
CHECK_NOT_NULL(stream_);
|
CHECK_NOT_NULL(stream_);
|
||||||
StreamBase* stream = static_cast<StreamBase*>(stream_);
|
StreamBase* stream = static_cast<StreamBase*>(stream_);
|
||||||
Environment* env = stream->stream_env();
|
Environment* env = stream->stream_env();
|
||||||
HandleScope handle_scope(env->isolate());
|
HandleScope handle_scope(env->isolate());
|
||||||
Context::Scope context_scope(env->context());
|
Context::Scope context_scope(env->context());
|
||||||
|
AllocatedBuffer buf(env, buf_);
|
||||||
|
|
||||||
if (nread <= 0) {
|
if (nread <= 0) {
|
||||||
free(buf.base);
|
|
||||||
if (nread < 0)
|
if (nread < 0)
|
||||||
stream->CallJSOnreadMethod(nread, Local<ArrayBuffer>());
|
stream->CallJSOnreadMethod(nread, Local<ArrayBuffer>());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK_LE(static_cast<size_t>(nread), buf.len);
|
CHECK_LE(static_cast<size_t>(nread), buf.size());
|
||||||
char* base = Realloc(buf.base, nread);
|
buf.Resize(nread);
|
||||||
|
|
||||||
Local<ArrayBuffer> obj = ArrayBuffer::New(
|
stream->CallJSOnreadMethod(nread, buf.ToArrayBuffer());
|
||||||
env->isolate(),
|
|
||||||
base,
|
|
||||||
nread,
|
|
||||||
v8::ArrayBufferCreationMode::kInternalized); // Transfer ownership to V8.
|
|
||||||
stream->CallJSOnreadMethod(nread, obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,24 +74,17 @@ class ShutdownWrap : public StreamReq {
|
|||||||
|
|
||||||
class WriteWrap : public StreamReq {
|
class WriteWrap : public StreamReq {
|
||||||
public:
|
public:
|
||||||
char* Storage();
|
void SetAllocatedStorage(AllocatedBuffer&& storage);
|
||||||
size_t StorageSize() const;
|
|
||||||
void SetAllocatedStorage(char* data, size_t size);
|
|
||||||
|
|
||||||
WriteWrap(StreamBase* stream,
|
WriteWrap(StreamBase* stream,
|
||||||
v8::Local<v8::Object> req_wrap_obj)
|
v8::Local<v8::Object> req_wrap_obj)
|
||||||
: StreamReq(stream, req_wrap_obj) { }
|
: StreamReq(stream, req_wrap_obj) { }
|
||||||
|
|
||||||
~WriteWrap() override {
|
|
||||||
free(storage_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call stream()->EmitAfterWrite() and dispose of this request wrap.
|
// Call stream()->EmitAfterWrite() and dispose of this request wrap.
|
||||||
void OnDone(int status) override;
|
void OnDone(int status) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* storage_ = nullptr;
|
AllocatedBuffer storage_;
|
||||||
size_t storage_size_ = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -115,7 +108,7 @@ class StreamListener {
|
|||||||
// It is not valid to return a zero-length buffer from this method.
|
// It is not valid to return a zero-length buffer from this method.
|
||||||
// It is not guaranteed that the corresponding `OnStreamRead()` call
|
// It is not guaranteed that the corresponding `OnStreamRead()` call
|
||||||
// happens in the same event loop turn as this call.
|
// happens in the same event loop turn as this call.
|
||||||
virtual uv_buf_t OnStreamAlloc(size_t suggested_size);
|
virtual uv_buf_t OnStreamAlloc(size_t suggested_size) = 0;
|
||||||
|
|
||||||
// `OnStreamRead()` is called when data is available on the socket and has
|
// `OnStreamRead()` is called when data is available on the socket and has
|
||||||
// been read into the buffer provided by `OnStreamAlloc()`.
|
// been read into the buffer provided by `OnStreamAlloc()`.
|
||||||
@ -181,6 +174,7 @@ class ReportWritesToJSStreamListener : public StreamListener {
|
|||||||
// JS land via the handle’s .ondata method.
|
// JS land via the handle’s .ondata method.
|
||||||
class EmitToJSStreamListener : public ReportWritesToJSStreamListener {
|
class EmitToJSStreamListener : public ReportWritesToJSStreamListener {
|
||||||
public:
|
public:
|
||||||
|
uv_buf_t OnStreamAlloc(size_t suggested_size) override;
|
||||||
void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;
|
void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,17 +114,17 @@ uv_buf_t StreamPipe::ReadableListener::OnStreamAlloc(size_t suggested_size) {
|
|||||||
StreamPipe* pipe = ContainerOf(&StreamPipe::readable_listener_, this);
|
StreamPipe* pipe = ContainerOf(&StreamPipe::readable_listener_, this);
|
||||||
size_t size = std::min(suggested_size, pipe->wanted_data_);
|
size_t size = std::min(suggested_size, pipe->wanted_data_);
|
||||||
CHECK_GT(size, 0);
|
CHECK_GT(size, 0);
|
||||||
return uv_buf_init(Malloc(size), size);
|
return pipe->env()->AllocateManaged(size).release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamPipe::ReadableListener::OnStreamRead(ssize_t nread,
|
void StreamPipe::ReadableListener::OnStreamRead(ssize_t nread,
|
||||||
const uv_buf_t& buf) {
|
const uv_buf_t& buf_) {
|
||||||
StreamPipe* pipe = ContainerOf(&StreamPipe::readable_listener_, this);
|
StreamPipe* pipe = ContainerOf(&StreamPipe::readable_listener_, this);
|
||||||
|
AllocatedBuffer buf(pipe->env(), buf_);
|
||||||
AsyncScope async_scope(pipe);
|
AsyncScope async_scope(pipe);
|
||||||
if (nread < 0) {
|
if (nread < 0) {
|
||||||
// EOF or error; stop reading and pass the error to the previous listener
|
// EOF or error; stop reading and pass the error to the previous listener
|
||||||
// (which might end up in JS).
|
// (which might end up in JS).
|
||||||
free(buf.base);
|
|
||||||
pipe->is_eof_ = true;
|
pipe->is_eof_ = true;
|
||||||
stream()->ReadStop();
|
stream()->ReadStop();
|
||||||
CHECK_NOT_NULL(previous_listener_);
|
CHECK_NOT_NULL(previous_listener_);
|
||||||
@ -138,19 +138,18 @@ void StreamPipe::ReadableListener::OnStreamRead(ssize_t nread,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipe->ProcessData(nread, buf);
|
pipe->ProcessData(nread, std::move(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamPipe::ProcessData(size_t nread, const uv_buf_t& buf) {
|
void StreamPipe::ProcessData(size_t nread, AllocatedBuffer&& buf) {
|
||||||
uv_buf_t buffer = uv_buf_init(buf.base, nread);
|
uv_buf_t buffer = uv_buf_init(buf.data(), nread);
|
||||||
StreamWriteResult res = sink()->Write(&buffer, 1);
|
StreamWriteResult res = sink()->Write(&buffer, 1);
|
||||||
if (!res.async) {
|
if (!res.async) {
|
||||||
free(buf.base);
|
|
||||||
writable_listener_.OnStreamAfterWrite(nullptr, res.err);
|
writable_listener_.OnStreamAfterWrite(nullptr, res.err);
|
||||||
} else {
|
} else {
|
||||||
is_writing_ = true;
|
is_writing_ = true;
|
||||||
is_reading_ = false;
|
is_reading_ = false;
|
||||||
res.wrap->SetAllocatedStorage(buf.base, buf.len);
|
res.wrap->SetAllocatedStorage(std::move(buf));
|
||||||
if (source() != nullptr)
|
if (source() != nullptr)
|
||||||
source()->ReadStop();
|
source()->ReadStop();
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ class StreamPipe : public AsyncWrap {
|
|||||||
// `OnStreamWantsWrite()` support.
|
// `OnStreamWantsWrite()` support.
|
||||||
size_t wanted_data_ = 0;
|
size_t wanted_data_ = 0;
|
||||||
|
|
||||||
void ProcessData(size_t nread, const uv_buf_t& buf);
|
void ProcessData(size_t nread, AllocatedBuffer&& buf);
|
||||||
|
|
||||||
class ReadableListener : public StreamListener {
|
class ReadableListener : public StreamListener {
|
||||||
public:
|
public:
|
||||||
|
@ -462,25 +462,23 @@ void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
|
|||||||
void UDPWrap::OnAlloc(uv_handle_t* handle,
|
void UDPWrap::OnAlloc(uv_handle_t* handle,
|
||||||
size_t suggested_size,
|
size_t suggested_size,
|
||||||
uv_buf_t* buf) {
|
uv_buf_t* buf) {
|
||||||
buf->base = node::Malloc(suggested_size);
|
UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
|
||||||
buf->len = suggested_size;
|
*buf = wrap->env()->AllocateManaged(suggested_size).release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UDPWrap::OnRecv(uv_udp_t* handle,
|
void UDPWrap::OnRecv(uv_udp_t* handle,
|
||||||
ssize_t nread,
|
ssize_t nread,
|
||||||
const uv_buf_t* buf,
|
const uv_buf_t* buf_,
|
||||||
const struct sockaddr* addr,
|
const struct sockaddr* addr,
|
||||||
unsigned int flags) {
|
unsigned int flags) {
|
||||||
if (nread == 0 && addr == nullptr) {
|
|
||||||
if (buf->base != nullptr)
|
|
||||||
free(buf->base);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
|
UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
|
||||||
Environment* env = wrap->env();
|
Environment* env = wrap->env();
|
||||||
|
|
||||||
|
AllocatedBuffer buf(env, *buf_);
|
||||||
|
if (nread == 0 && addr == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
HandleScope handle_scope(env->isolate());
|
HandleScope handle_scope(env->isolate());
|
||||||
Context::Scope context_scope(env->context());
|
Context::Scope context_scope(env->context());
|
||||||
|
|
||||||
@ -493,14 +491,12 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (nread < 0) {
|
if (nread < 0) {
|
||||||
if (buf->base != nullptr)
|
|
||||||
free(buf->base);
|
|
||||||
wrap->MakeCallback(env->onmessage_string(), arraysize(argv), argv);
|
wrap->MakeCallback(env->onmessage_string(), arraysize(argv), argv);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* base = node::UncheckedRealloc(buf->base, nread);
|
buf.Resize(nread);
|
||||||
argv[2] = Buffer::New(env, base, nread).ToLocalChecked();
|
argv[2] = buf.ToBuffer().ToLocalChecked();
|
||||||
argv[3] = AddressToJS(env, addr);
|
argv[3] = AddressToJS(env, addr);
|
||||||
wrap->MakeCallback(env->onmessage_string(), arraysize(argv), argv);
|
wrap->MakeCallback(env->onmessage_string(), arraysize(argv), argv);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user