summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-02-25 04:12:19 +0100
committerAnna Henningsen <anna@addaleax.net>2019-03-01 21:57:54 +0100
commit31975bbc88d353cf2eecc93c9d2cde62dba67b2c (patch)
tree7a91545cfd50182e50addd1aa3a6468d74f65474 /src
parentb42dcb0eeb2d2c302b0ecabbc1092605a54213d6 (diff)
downloadandroid-node-v8-31975bbc88d353cf2eecc93c9d2cde62dba67b2c.tar.gz
android-node-v8-31975bbc88d353cf2eecc93c9d2cde62dba67b2c.tar.bz2
android-node-v8-31975bbc88d353cf2eecc93c9d2cde62dba67b2c.zip
src: allow not materializing ArrayBuffers from C++
Where appropriate, use a helper that wraps around `ArrayBufferView::Buffer()` or `ArrayBufferView::CopyContents()` rather than `Buffer::Data()`, as that may help to avoid materializing the underlying `ArrayBuffer` when reading small typed arrays from C++. This allows keeping the performance benefits of the faster creation of heap-allocated small typed arrays in many cases. PR-URL: https://github.com/nodejs/node/pull/26301 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/node_crypto.cc227
-rw-r--r--src/node_crypto.h7
-rw-r--r--src/node_http2.cc26
-rw-r--r--src/node_http2.h5
-rw-r--r--src/string_decoder.cc9
-rw-r--r--src/util-inl.h26
-rw-r--r--src/util.cc7
-rw-r--r--src/util.h21
8 files changed, 183 insertions, 145 deletions
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index dcdecb5064..aca5df298c 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -57,6 +57,7 @@ namespace crypto {
using node::THROW_ERR_TLS_INVALID_PROTOCOL_METHOD;
using v8::Array;
+using v8::ArrayBufferView;
using v8::Boolean;
using v8::ConstructorBehavior;
using v8::Context;
@@ -539,8 +540,9 @@ static BIOPointer LoadBIO(Environment* env, Local<Value> v) {
return NodeBIO::NewFixed(*s, s.length());
}
- if (Buffer::HasInstance(v)) {
- return NodeBIO::NewFixed(Buffer::Data(v), Buffer::Length(v));
+ if (v->IsArrayBufferView()) {
+ ArrayBufferViewContents<char> buf(v.As<ArrayBufferView>());
+ return NodeBIO::NewFixed(buf.data(), buf.length());
}
return nullptr;
@@ -1135,9 +1137,10 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) {
if (args.Length() >= 2) {
THROW_AND_RETURN_IF_NOT_BUFFER(env, args[1], "Pass phrase");
- size_t passlen = Buffer::Length(args[1]);
+ Local<ArrayBufferView> abv = args[1].As<ArrayBufferView>();
+ size_t passlen = abv->ByteLength();
pass.resize(passlen + 1);
- memcpy(pass.data(), Buffer::Data(args[1]), passlen);
+ abv->CopyContents(pass.data(), passlen);
pass[passlen] = '\0';
}
@@ -1261,15 +1264,16 @@ void SecureContext::SetTicketKeys(const FunctionCallbackInfo<Value>& args) {
}
THROW_AND_RETURN_IF_NOT_BUFFER(env, args[0], "Ticket keys");
+ ArrayBufferViewContents<char> buf(args[0].As<ArrayBufferView>());
- if (Buffer::Length(args[0]) != 48) {
+ if (buf.length() != 48) {
return THROW_ERR_INVALID_ARG_VALUE(
env, "Ticket keys length must be 48 bytes");
}
- memcpy(wrap->ticket_key_name_, Buffer::Data(args[0]), 16);
- memcpy(wrap->ticket_key_hmac_, Buffer::Data(args[0]) + 16, 16);
- memcpy(wrap->ticket_key_aes_, Buffer::Data(args[0]) + 32, 16);
+ memcpy(wrap->ticket_key_name_, buf.data(), 16);
+ memcpy(wrap->ticket_key_hmac_, buf.data() + 16, 16);
+ memcpy(wrap->ticket_key_aes_, buf.data() + 32, 16);
args.GetReturnValue().Set(true);
#endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys)
@@ -1349,29 +1353,29 @@ int SecureContext::TicketKeyCallback(SSL* ssl,
return -1;
}
- memcpy(name, Buffer::Data(name_val), kTicketPartSize);
- memcpy(iv, Buffer::Data(iv_val), kTicketPartSize);
+ name_val.As<ArrayBufferView>()->CopyContents(name, kTicketPartSize);
+ iv_val.As<ArrayBufferView>()->CopyContents(iv, kTicketPartSize);
}
+ ArrayBufferViewContents<unsigned char> hmac_buf(hmac);
HMAC_Init_ex(hctx,
- Buffer::Data(hmac),
- Buffer::Length(hmac),
+ hmac_buf.data(),
+ hmac_buf.length(),
EVP_sha256(),
nullptr);
- const unsigned char* aes_key =
- reinterpret_cast<unsigned char*>(Buffer::Data(aes));
+ ArrayBufferViewContents<unsigned char> aes_key(aes.As<ArrayBufferView>());
if (enc) {
EVP_EncryptInit_ex(ectx,
EVP_aes_128_cbc(),
nullptr,
- aes_key,
+ aes_key.data(),
iv);
} else {
EVP_DecryptInit_ex(ectx,
EVP_aes_128_cbc(),
nullptr,
- aes_key,
+ aes_key.data(),
iv);
}
@@ -2094,13 +2098,10 @@ void SSLWrap<Base>::SetSession(const FunctionCallbackInfo<Value>& args) {
}
THROW_AND_RETURN_IF_NOT_BUFFER(env, args[0], "Session");
- size_t slen = Buffer::Length(args[0]);
- std::vector<char> sbuf(slen);
- if (char* p = Buffer::Data(args[0]))
- sbuf.assign(p, p + slen);
+ ArrayBufferViewContents<unsigned char> sbuf(args[0].As<ArrayBufferView>());
- const unsigned char* p = reinterpret_cast<const unsigned char*>(sbuf.data());
- SSLSessionPointer sess(d2i_SSL_SESSION(nullptr, &p, slen));
+ const unsigned char* p = sbuf.data();
+ SSLSessionPointer sess(d2i_SSL_SESSION(nullptr, &p, sbuf.length()));
if (sess == nullptr)
return;
@@ -2118,11 +2119,10 @@ void SSLWrap<Base>::LoadSession(const FunctionCallbackInfo<Value>& args) {
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder());
if (args.Length() >= 1 && Buffer::HasInstance(args[0])) {
- ssize_t slen = Buffer::Length(args[0]);
- char* sbuf = Buffer::Data(args[0]);
+ ArrayBufferViewContents<unsigned char> sbuf(args[0]);
- const unsigned char* p = reinterpret_cast<unsigned char*>(sbuf);
- SSL_SESSION* sess = d2i_SSL_SESSION(nullptr, &p, slen);
+ const unsigned char* p = sbuf.data();
+ SSL_SESSION* sess = d2i_SSL_SESSION(nullptr, &p, sbuf.length());
// Setup next session and move hello to the BIO buffer
w->next_sess_.reset(sess);
@@ -2204,7 +2204,7 @@ void SSLWrap<Base>::SetOCSPResponse(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_IF_NOT_BUFFER(env, args[0], "OCSP response");
- w->ocsp_response_.Reset(args.GetIsolate(), args[0].As<Object>());
+ w->ocsp_response_.Reset(args.GetIsolate(), args[0].As<ArrayBufferView>());
}
@@ -2403,12 +2403,10 @@ int SSLWrap<Base>::SelectALPNCallback(SSL* s,
w->object()->GetPrivate(
env->context(),
env->alpn_buffer_private_symbol()).ToLocalChecked();
- CHECK(Buffer::HasInstance(alpn_buffer));
- const unsigned char* alpn_protos =
- reinterpret_cast<const unsigned char*>(Buffer::Data(alpn_buffer));
- unsigned alpn_protos_len = Buffer::Length(alpn_buffer);
+ ArrayBufferViewContents<unsigned char> alpn_protos(alpn_buffer);
int status = SSL_select_next_proto(const_cast<unsigned char**>(out), outlen,
- alpn_protos, alpn_protos_len, in, inlen);
+ alpn_protos.data(), alpn_protos.length(),
+ in, inlen);
// According to 3.2. Protocol Selection of RFC7301, fatal
// no_application_protocol alert shall be sent but OpenSSL 1.0.2 does not
// support it yet. See
@@ -2446,10 +2444,9 @@ void SSLWrap<Base>::SetALPNProtocols(const FunctionCallbackInfo<Value>& args) {
return env->ThrowTypeError("Must give a Buffer as first argument");
if (w->is_client()) {
- const unsigned char* alpn_protos =
- reinterpret_cast<const unsigned char*>(Buffer::Data(args[0]));
- unsigned alpn_protos_len = Buffer::Length(args[0]);
- int r = SSL_set_alpn_protos(w->ssl_.get(), alpn_protos, alpn_protos_len);
+ ArrayBufferViewContents<unsigned char> alpn_protos(args[0]);
+ int r = SSL_set_alpn_protos(
+ w->ssl_.get(), alpn_protos.data(), alpn_protos.length());
CHECK_EQ(r, 0);
} else {
CHECK(
@@ -2493,14 +2490,13 @@ int SSLWrap<Base>::TLSExtStatusCallback(SSL* s, void* arg) {
if (w->ocsp_response_.IsEmpty())
return SSL_TLSEXT_ERR_NOACK;
- Local<Object> obj = PersistentToLocal::Default(env->isolate(),
- w->ocsp_response_);
- char* resp = Buffer::Data(obj);
- size_t len = Buffer::Length(obj);
+ Local<ArrayBufferView> obj = PersistentToLocal::Default(env->isolate(),
+ w->ocsp_response_);
+ size_t len = obj->ByteLength();
// OpenSSL takes control of the pointer after accepting it
unsigned char* data = MallocOpenSSL<unsigned char>(len);
- memcpy(data, resp, len);
+ obj->CopyContents(data, len);
if (!SSL_set_tlsext_status_ocsp_resp(s, data, len))
OPENSSL_free(data);
@@ -2998,10 +2994,12 @@ ByteSource ByteSource::FromString(Environment* env, Local<String> str,
}
ByteSource ByteSource::FromBuffer(Local<Value> buffer, bool ntc) {
- size_t size = Buffer::Length(buffer);
+ CHECK(buffer->IsArrayBufferView());
+ Local<ArrayBufferView> abv = buffer.As<ArrayBufferView>();
+ size_t size = abv->ByteLength();
if (ntc) {
char* data = MallocOpenSSL<char>(size + 1);
- memcpy(data, Buffer::Data(buffer), size);
+ abv->CopyContents(data, size);
data[size] = 0;
return Allocated(data, size);
}
@@ -3404,7 +3402,8 @@ void KeyObject::Init(const FunctionCallbackInfo<Value>& args) {
switch (key->key_type_) {
case kKeyTypeSecret:
CHECK_EQ(args.Length(), 1);
- key->InitSecret(Buffer::Data(args[0]), Buffer::Length(args[0]));
+ CHECK(args[0]->IsArrayBufferView());
+ key->InitSecret(args[0].As<ArrayBufferView>());
break;
case kKeyTypePublic:
CHECK_EQ(args.Length(), 3);
@@ -3429,11 +3428,12 @@ void KeyObject::Init(const FunctionCallbackInfo<Value>& args) {
}
}
-void KeyObject::InitSecret(const char* key, size_t key_len) {
+void KeyObject::InitSecret(v8::Local<v8::ArrayBufferView> abv) {
CHECK_EQ(this->key_type_, kKeyTypeSecret);
+ size_t key_len = abv->ByteLength();
char* mem = MallocOpenSSL<char>(key_len);
- memcpy(mem, key, key_len);
+ abv->CopyContents(mem, key_len);
this->symmetric_key_ = std::unique_ptr<char, std::function<void(char*)>>(mem,
[key_len](char* p) {
OPENSSL_clear_free(p, key_len);
@@ -3643,8 +3643,7 @@ void CipherBase::Init(const FunctionCallbackInfo<Value>& args) {
CHECK_GE(args.Length(), 3);
const node::Utf8Value cipher_type(args.GetIsolate(), args[0]);
- const char* key_buf = Buffer::Data(args[1]);
- ssize_t key_buf_len = Buffer::Length(args[1]);
+ ArrayBufferViewContents<char> key_buf(args[1]);
// Don't assign to cipher->auth_tag_len_ directly; the value might not
// represent a valid length at this point.
@@ -3656,7 +3655,7 @@ void CipherBase::Init(const FunctionCallbackInfo<Value>& args) {
auth_tag_len = kNoAuthTagLength;
}
- cipher->Init(*cipher_type, key_buf, key_buf_len, auth_tag_len);
+ cipher->Init(*cipher_type, key_buf.data(), key_buf.length(), auth_tag_len);
}
void CipherBase::InitIv(const char* cipher_type,
@@ -3712,14 +3711,12 @@ void CipherBase::InitIv(const FunctionCallbackInfo<Value>& args) {
const node::Utf8Value cipher_type(env->isolate(), args[0]);
const ByteSource key = GetSecretKeyBytes(env, args[1]);
- ssize_t iv_len;
- const unsigned char* iv_buf;
- if (args[2]->IsNull()) {
- iv_buf = nullptr;
- iv_len = -1;
- } else {
- iv_buf = reinterpret_cast<unsigned char*>(Buffer::Data(args[2]));
- iv_len = Buffer::Length(args[2]);
+ ArrayBufferViewContents<unsigned char> iv_buf;
+ ssize_t iv_len = -1;
+ if (!args[2]->IsNull()) {
+ CHECK(args[2]->IsArrayBufferView());
+ iv_buf.Read(args[2].As<ArrayBufferView>());
+ iv_len = iv_buf.length();
}
// Don't assign to cipher->auth_tag_len_ directly; the value might not
@@ -3735,7 +3732,7 @@ void CipherBase::InitIv(const FunctionCallbackInfo<Value>& args) {
cipher->InitIv(*cipher_type,
reinterpret_cast<const unsigned char*>(key.get()),
key.size(),
- iv_buf,
+ iv_buf.data(),
iv_len,
auth_tag_len);
}
@@ -3889,7 +3886,8 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo<Value>& args) {
CHECK_LE(cipher->auth_tag_len_, sizeof(cipher->auth_tag_));
memset(cipher->auth_tag_, 0, sizeof(cipher->auth_tag_));
- memcpy(cipher->auth_tag_, Buffer::Data(args[0]), cipher->auth_tag_len_);
+ args[0].As<ArrayBufferView>()->CopyContents(
+ cipher->auth_tag_, cipher->auth_tag_len_);
args.GetReturnValue().Set(true);
}
@@ -3953,9 +3951,9 @@ void CipherBase::SetAAD(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(args.Length(), 2);
CHECK(args[1]->IsInt32());
int plaintext_len = args[1].As<Int32>()->Value();
+ ArrayBufferViewContents<char> buf(args[0]);
- bool b = cipher->SetAAD(Buffer::Data(args[0]), Buffer::Length(args[0]),
- plaintext_len);
+ bool b = cipher->SetAAD(buf.data(), buf.length(), plaintext_len);
args.GetReturnValue().Set(b); // Possibly report invalid state failure
}
@@ -4028,9 +4026,8 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
return;
r = cipher->Update(decoder.out(), decoder.size(), &out);
} else {
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- r = cipher->Update(buf, buflen, &out);
+ ArrayBufferViewContents<char> buf(args[0]);
+ r = cipher->Update(buf.data(), buf.length(), &out);
}
if (r != kSuccess) {
@@ -4213,10 +4210,8 @@ void Hmac::HmacUpdate(const FunctionCallbackInfo<Value>& args) {
r = hmac->HmacUpdate(decoder.out(), decoder.size());
}
} else {
- CHECK(args[0]->IsArrayBufferView());
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- r = hmac->HmacUpdate(buf, buflen);
+ ArrayBufferViewContents<char> buf(args[0]);
+ r = hmac->HmacUpdate(buf.data(), buf.length());
}
args.GetReturnValue().Set(r);
@@ -4324,9 +4319,8 @@ void Hash::HashUpdate(const FunctionCallbackInfo<Value>& args) {
}
r = hash->HashUpdate(decoder.out(), decoder.size());
} else if (args[0]->IsArrayBufferView()) {
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- r = hash->HashUpdate(buf, buflen);
+ ArrayBufferViewContents<char> buf(args[0].As<ArrayBufferView>());
+ r = hash->HashUpdate(buf.data(), buf.length());
}
args.GetReturnValue().Set(r);
@@ -4487,9 +4481,8 @@ void Sign::SignUpdate(const FunctionCallbackInfo<Value>& args) {
ASSIGN_OR_RETURN_UNWRAP(&sign, args.Holder());
Error err;
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- err = sign->Update(buf, buflen);
+ ArrayBufferViewContents<char> buf(args[0]);
+ err = sign->Update(buf.data(), buf.length());
sign->CheckThrow(err);
}
@@ -4634,9 +4627,8 @@ void Verify::VerifyUpdate(const FunctionCallbackInfo<Value>& args) {
ASSIGN_OR_RETURN_UNWRAP(&verify, args.Holder());
Error err;
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- err = verify->Update(buf, buflen);
+ ArrayBufferViewContents<char> buf(args[0]);
+ err = verify->Update(buf.data(), buf.length());
verify->CheckThrow(err);
}
@@ -4688,8 +4680,7 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) {
if (!pkey)
return;
- char* hbuf = Buffer::Data(args[offset]);
- ssize_t hlen = Buffer::Length(args[offset]);
+ ArrayBufferViewContents<char> hbuf(args[offset]);
CHECK(args[offset + 1]->IsInt32());
int padding = args[offset + 1].As<Int32>()->Value();
@@ -4698,8 +4689,8 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) {
int salt_len = args[offset + 2].As<Int32>()->Value();
bool verify_result;
- Error err = verify->VerifyFinal(pkey, hbuf, hlen, padding, salt_len,
- &verify_result);
+ Error err = verify->VerifyFinal(pkey, hbuf.data(), hbuf.length(), padding,
+ salt_len, &verify_result);
if (err != kSignOk)
return verify->CheckThrow(err);
args.GetReturnValue().Set(verify_result);
@@ -4753,8 +4744,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
return;
THROW_AND_RETURN_IF_NOT_BUFFER(env, args[offset], "Data");
- char* buf = Buffer::Data(args[offset]);
- ssize_t len = Buffer::Length(args[offset]);
+ ArrayBufferViewContents<unsigned char> buf(args[offset]);
uint32_t padding;
if (!args[offset + 1]->Uint32Value(env->context()).To(&padding)) return;
@@ -4767,8 +4757,8 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
env,
pkey,
padding,
- reinterpret_cast<const unsigned char*>(buf),
- len,
+ buf.data(),
+ buf.length(),
&out);
if (!r)
@@ -4906,15 +4896,15 @@ void DiffieHellman::New(const FunctionCallbackInfo<Value>& args) {
args[1].As<Int32>()->Value());
}
} else {
+ ArrayBufferViewContents<char> arg0(args[0]);
if (args[1]->IsInt32()) {
- initialized = diffieHellman->Init(Buffer::Data(args[0]),
- Buffer::Length(args[0]),
+ initialized = diffieHellman->Init(arg0.data(),
+ arg0.length(),
args[1].As<Int32>()->Value());
} else {
- initialized = diffieHellman->Init(Buffer::Data(args[0]),
- Buffer::Length(args[0]),
- Buffer::Data(args[1]),
- Buffer::Length(args[1]));
+ ArrayBufferViewContents<char> arg1(args[1]);
+ initialized = diffieHellman->Init(arg0.data(), arg0.length(),
+ arg1.data(), arg1.length());
}
}
}
@@ -5017,10 +5007,8 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
}
THROW_AND_RETURN_IF_NOT_BUFFER(env, args[0], "Other party's public key");
- BignumPointer key(BN_bin2bn(
- reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
- Buffer::Length(args[0]),
- nullptr));
+ ArrayBufferViewContents<unsigned char> key_buf(args[0].As<ArrayBufferView>());
+ BignumPointer key(BN_bin2bn(key_buf.data(), key_buf.length(), nullptr));
AllocatedBuffer ret = env->AllocateManaged(DH_size(diffieHellman->dh_.get()));
@@ -5087,9 +5075,9 @@ void DiffieHellman::SetKey(const FunctionCallbackInfo<Value>& args,
return THROW_ERR_INVALID_ARG_TYPE(env, errmsg);
}
+ ArrayBufferViewContents<unsigned char> buf(args[0].As<ArrayBufferView>());
BIGNUM* num =
- BN_bin2bn(reinterpret_cast<unsigned char*>(Buffer::Data(args[0])),
- Buffer::Length(args[0]), nullptr);
+ BN_bin2bn(buf.data(), buf.length(), nullptr);
CHECK_NOT_NULL(num);
CHECK_EQ(1, set_field(dh->dh_.get(), num));
}
@@ -5188,8 +5176,7 @@ void ECDH::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
ECPointPointer ECDH::BufferToPoint(Environment* env,
const EC_GROUP* group,
- char* data,
- size_t len) {
+ Local<Value> buf) {
int r;
ECPointPointer pub(EC_POINT_new(group));
@@ -5198,11 +5185,12 @@ ECPointPointer ECDH::BufferToPoint(Environment* env,
return pub;
}
+ ArrayBufferViewContents<unsigned char> input(buf);
r = EC_POINT_oct2point(
group,
pub.get(),
- reinterpret_cast<unsigned char*>(data),
- len,
+ input.data(),
+ input.length(),
nullptr);
if (!r)
return ECPointPointer();
@@ -5227,8 +5215,7 @@ void ECDH::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
ECPointPointer pub(
ECDH::BufferToPoint(env,
ecdh->group_,
- Buffer::Data(args[0]),
- Buffer::Length(args[0])));
+ args[0]));
if (!pub) {
args.GetReturnValue().Set(
FIXED_ONE_BYTE_STRING(env->isolate(),
@@ -5360,8 +5347,7 @@ void ECDH::SetPublicKey(const FunctionCallbackInfo<Value>& args) {
ECPointPointer pub(
ECDH::BufferToPoint(env,
ecdh->group_,
- Buffer::Data(args[0].As<Object>()),
- Buffer::Length(args[0].As<Object>())));
+ args[0]));
if (!pub)
return env->ThrowError("Failed to convert Buffer to EC_POINT");
@@ -5427,8 +5413,10 @@ void CryptoJob::Run(std::unique_ptr<CryptoJob> job, Local<Value> wrap) {
inline void CopyBuffer(Local<Value> buf, std::vector<char>* vec) {
+ CHECK(buf->IsArrayBufferView());
vec->clear();
- if (auto p = Buffer::Data(buf)) vec->assign(p, p + Buffer::Length(buf));
+ vec->resize(buf.As<ArrayBufferView>()->ByteLength());
+ buf.As<ArrayBufferView>()->CopyContents(vec->data(), vec->size());
}
@@ -6033,14 +6021,13 @@ bool VerifySpkac(const char* data, unsigned int len) {
void VerifySpkac(const FunctionCallbackInfo<Value>& args) {
bool verify_result = false;
- size_t length = Buffer::Length(args[0]);
- if (length == 0)
- return args.GetReturnValue().Set(verify_result);
+ ArrayBufferViewContents<char> input(args[0]);
+ if (input.length() == 0)
+ return args.GetReturnValue().SetEmptyString();
- char* data = Buffer::Data(args[0]);
- CHECK_NOT_NULL(data);
+ CHECK_NOT_NULL(input.data());
- verify_result = VerifySpkac(data, length);
+ verify_result = VerifySpkac(input.data(), input.length());
args.GetReturnValue().Set(verify_result);
}
@@ -6075,15 +6062,15 @@ AllocatedBuffer ExportPublicKey(Environment* env,
void ExportPublicKey(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
- size_t length = Buffer::Length(args[0]);
- if (length == 0)
+ ArrayBufferViewContents<char> input(args[0]);
+ if (input.length() == 0)
return args.GetReturnValue().SetEmptyString();
- char* data = Buffer::Data(args[0]);
- CHECK_NOT_NULL(data);
+ CHECK_NOT_NULL(input.data());
size_t pkey_size;
- AllocatedBuffer pkey = ExportPublicKey(env, data, length, &pkey_size);
+ AllocatedBuffer pkey =
+ ExportPublicKey(env, input.data(), input.length(), &pkey_size);
if (pkey.data() == nullptr)
return args.GetReturnValue().SetEmptyString();
@@ -6130,8 +6117,9 @@ void ConvertKey(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK_EQ(args.Length(), 3);
+ CHECK(args[0]->IsArrayBufferView());
- size_t len = Buffer::Length(args[0]);
+ size_t len = args[0].As<ArrayBufferView>()->ByteLength();
if (len == 0)
return args.GetReturnValue().SetEmptyString();
@@ -6149,8 +6137,7 @@ void ConvertKey(const FunctionCallbackInfo<Value>& args) {
ECPointPointer pub(
ECDH::BufferToPoint(env,
group.get(),
- Buffer::Data(args[0]),
- len));
+ args[0]));
if (pub == nullptr)
return env->ThrowError("Failed to convert Buffer to EC_POINT");
diff --git a/src/node_crypto.h b/src/node_crypto.h
index ce93412830..982fc70543 100644
--- a/src/node_crypto.h
+++ b/src/node_crypto.h
@@ -333,7 +333,7 @@ class SSLWrap {
ClientHelloParser hello_parser_;
- Persistent<v8::Object> ocsp_response_;
+ Persistent<v8::ArrayBufferView> ocsp_response_;
Persistent<v8::Value> sni_context_;
friend class SecureContext;
@@ -462,7 +462,7 @@ class KeyObject : public BaseObject {
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
- void InitSecret(const char* key, size_t key_len);
+ void InitSecret(v8::Local<v8::ArrayBufferView> abv);
void InitPublic(const ManagedEVPPKey& pkey);
void InitPrivate(const ManagedEVPPKey& pkey);
@@ -803,8 +803,7 @@ class ECDH : public BaseObject {
static void Initialize(Environment* env, v8::Local<v8::Object> target);
static ECPointPointer BufferToPoint(Environment* env,
const EC_GROUP* group,
- char* data,
- size_t len);
+ v8::Local<v8::Value> buf);
// TODO(joyeecheung): track the memory used by OpenSSL types
SET_NO_MEMORY_INFO()
diff --git a/src/node_http2.cc b/src/node_http2.cc
index 7fc21c9cae..8946c71fc3 100644
--- a/src/node_http2.cc
+++ b/src/node_http2.cc
@@ -12,6 +12,7 @@
namespace node {
using v8::ArrayBuffer;
+using v8::ArrayBufferView;
using v8::Boolean;
using v8::Context;
using v8::Float64Array;
@@ -2483,7 +2484,7 @@ void Http2Session::Request(const FunctionCallbackInfo<Value>& args) {
// state of the Http2Session, it's simply a notification.
void Http2Session::Goaway(uint32_t code,
int32_t lastStreamID,
- uint8_t* data,
+ const uint8_t* data,
size_t len) {
if (IsDestroyed())
return;
@@ -2508,16 +2509,13 @@ void Http2Session::Goaway(const FunctionCallbackInfo<Value>& args) {
uint32_t code = args[0]->Uint32Value(context).ToChecked();
int32_t lastStreamID = args[1]->Int32Value(context).ToChecked();
- Local<Value> opaqueData = args[2];
- uint8_t* data = nullptr;
- size_t length = 0;
+ ArrayBufferViewContents<uint8_t> opaque_data;
- if (Buffer::HasInstance(opaqueData)) {
- data = reinterpret_cast<uint8_t*>(Buffer::Data(opaqueData));
- length = Buffer::Length(opaqueData);
+ if (args[2]->IsArrayBufferView()) {
+ opaque_data.Read(args[2].As<ArrayBufferView>());
}
- session->Goaway(code, lastStreamID, data, length);
+ session->Goaway(code, lastStreamID, opaque_data.data(), opaque_data.length());
}
// Update accounting of data chunks. This is used primarily to manage timeout
@@ -2771,10 +2769,10 @@ void Http2Session::Ping(const FunctionCallbackInfo<Value>& args) {
// A PING frame may have exactly 8 bytes of payload data. If not provided,
// then the current hrtime will be used as the payload.
- uint8_t* payload = nullptr;
- if (Buffer::HasInstance(args[0])) {
- payload = reinterpret_cast<uint8_t*>(Buffer::Data(args[0]));
- CHECK_EQ(Buffer::Length(args[0]), 8);
+ ArrayBufferViewContents<uint8_t, 8> payload;
+ if (args[0]->IsArrayBufferView()) {
+ payload.Read(args[0].As<ArrayBufferView>());
+ CHECK_EQ(payload.length(), 8);
}
Local<Object> obj;
@@ -2799,7 +2797,7 @@ void Http2Session::Ping(const FunctionCallbackInfo<Value>& args) {
// the callback will be invoked and a notification sent out to JS land. The
// notification will include the duration of the ping, allowing the round
// trip to be measured.
- ping->Send(payload);
+ ping->Send(payload.data());
args.GetReturnValue().Set(true);
}
@@ -2871,7 +2869,7 @@ Http2Session::Http2Ping::Http2Ping(Http2Session* session, Local<Object> obj)
session_(session),
startTime_(uv_hrtime()) {}
-void Http2Session::Http2Ping::Send(uint8_t* payload) {
+void Http2Session::Http2Ping::Send(const uint8_t* payload) {
uint8_t data[8];
if (payload == nullptr) {
memcpy(&data, &startTime_, arraysize(data));
diff --git a/src/node_http2.h b/src/node_http2.h
index 9065718c60..8a8ef74af9 100644
--- a/src/node_http2.h
+++ b/src/node_http2.h
@@ -699,7 +699,8 @@ class Http2Session : public AsyncWrap, public StreamListener {
void Close(uint32_t code = NGHTTP2_NO_ERROR,
bool socket_closed = false);
void Consume(Local<External> external);
- void Goaway(uint32_t code, int32_t lastStreamID, uint8_t* data, size_t len);
+ void Goaway(uint32_t code, int32_t lastStreamID,
+ const uint8_t* data, size_t len);
void AltSvc(int32_t id,
uint8_t* origin,
size_t origin_len,
@@ -1089,7 +1090,7 @@ class Http2Session::Http2Ping : public AsyncWrap {
SET_MEMORY_INFO_NAME(Http2Ping)
SET_SELF_SIZE(Http2Ping)
- void Send(uint8_t* payload);
+ void Send(const uint8_t* payload);
void Done(bool ack, const uint8_t* payload = nullptr);
private:
diff --git a/src/string_decoder.cc b/src/string_decoder.cc
index 9cf1bd671b..1441ca8693 100644
--- a/src/string_decoder.cc
+++ b/src/string_decoder.cc
@@ -4,6 +4,7 @@
#include "string_decoder-inl.h"
using v8::Array;
+using v8::ArrayBufferView;
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Integer;
@@ -252,9 +253,13 @@ void DecodeData(const FunctionCallbackInfo<Value>& args) {
StringDecoder* decoder =
reinterpret_cast<StringDecoder*>(Buffer::Data(args[0]));
CHECK_NOT_NULL(decoder);
- size_t nread = Buffer::Length(args[1]);
+
+ CHECK(args[1]->IsArrayBufferView());
+ ArrayBufferViewContents<char> content(args[1].As<ArrayBufferView>());
+ size_t length = content.length();
+
MaybeLocal<String> ret =
- decoder->DecodeData(args.GetIsolate(), Buffer::Data(args[1]), &nread);
+ decoder->DecodeData(args.GetIsolate(), content.data(), &length);
if (!ret.IsEmpty())
args.GetReturnValue().Set(ret.ToLocalChecked());
}
diff --git a/src/util-inl.h b/src/util-inl.h
index 9f57b635db..0b174170ca 100644
--- a/src/util-inl.h
+++ b/src/util-inl.h
@@ -466,6 +466,32 @@ SlicedArguments::SlicedArguments(
(*this)[i] = args[i + start];
}
+template <typename T, size_t S>
+ArrayBufferViewContents<T, S>::ArrayBufferViewContents(
+ v8::Local<v8::Value> value) {
+ CHECK(value->IsArrayBufferView());
+ Read(value.As<v8::ArrayBufferView>());
+}
+
+template <typename T, size_t S>
+ArrayBufferViewContents<T, S>::ArrayBufferViewContents(
+ v8::Local<v8::ArrayBufferView> abv) {
+ Read(abv);
+}
+
+template <typename T, size_t S>
+void ArrayBufferViewContents<T, S>::Read(v8::Local<v8::ArrayBufferView> abv) {
+ static_assert(sizeof(T) == 1, "Only supports one-byte data at the moment");
+ length_ = abv->ByteLength();
+ if (length_ > sizeof(stack_storage_) || abv->HasBuffer()) {
+ data_ = static_cast<T*>(abv->Buffer()->GetContents().Data()) +
+ abv->ByteOffset();
+ } else {
+ abv->CopyContents(stack_storage_, sizeof(stack_storage_));
+ data_ = stack_storage_;
+ }
+}
+
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
diff --git a/src/util.cc b/src/util.cc
index 3cdc222a96..223e0e8772 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -29,6 +29,7 @@
namespace node {
+using v8::ArrayBufferView;
using v8::Isolate;
using v8::Local;
using v8::String;
@@ -89,11 +90,11 @@ BufferValue::BufferValue(Isolate* isolate, Local<Value> value) {
if (value->IsString()) {
MakeUtf8String(isolate, value, this);
- } else if (Buffer::HasInstance(value)) {
- const size_t len = Buffer::Length(value);
+ } else if (value->IsArrayBufferView()) {
+ const size_t len = value.As<ArrayBufferView>()->ByteLength();
// Leave place for the terminating '\0' byte.
AllocateSufficientStorage(len + 1);
- memcpy(out(), Buffer::Data(value), len);
+ value.As<ArrayBufferView>()->CopyContents(out(), len);
SetLengthAndZeroTerminate(len);
} else {
Invalidate();
diff --git a/src/util.h b/src/util.h
index 4cd04dc6af..4c930e637c 100644
--- a/src/util.h
+++ b/src/util.h
@@ -417,6 +417,27 @@ class MaybeStackBuffer {
T buf_st_[kStackStorageSize];
};
+// Provides access to an ArrayBufferView's storage, either the original,
+// or for small data, a copy of it. This object's lifetime is bound to the
+// original ArrayBufferView's lifetime.
+template <typename T, size_t kStackStorageSize = 64>
+class ArrayBufferViewContents {
+ public:
+ ArrayBufferViewContents() {}
+
+ explicit inline ArrayBufferViewContents(v8::Local<v8::Value> value);
+ explicit inline ArrayBufferViewContents(v8::Local<v8::ArrayBufferView> abv);
+ inline void Read(v8::Local<v8::ArrayBufferView> abv);
+
+ inline const T* data() const { return data_; }
+ inline size_t length() const { return length_; }
+
+ private:
+ T stack_storage_[kStackStorageSize];
+ T* data_ = nullptr;
+ size_t length_ = 0;
+};
+
class Utf8Value : public MaybeStackBuffer<char> {
public:
explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);