// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
-#ifndef NODE_BUFFER_H_
-#define NODE_BUFFER_H_
+#ifndef SRC_NODE_BUFFER_H_
+#define SRC_NODE_BUFFER_H_
#include "node.h"
-#include "node_object_wrap.h"
+#include "smalloc.h"
#include "v8.h"
-#include <assert.h>
-namespace node {
-
-/* A buffer is a chunk of memory stored outside the V8 heap, mirrored by an
- * object in javascript. The object is not totally opaque, one can access
- * individual bytes with [] and slice it into substrings or sub-buffers
- * without copying memory.
- */
-
-/*
- The C++ API for Buffer changed radically between v0.2 and v0.3, in fact
- it was the reason for bumping the version. In v0.2 JavaScript Buffers and
- C++ Buffers were in one-to-one correspondence via ObjectWrap. We found
- that it was faster to expose the C++ Buffers to JavaScript as a
- "SlowBuffer" which is used as a private backend to pure JavaScript
- "Buffer" objects - a 'Buffer' in v0.3 might look like this:
-
- { _parent: s,
- _offset: 520,
- length: 5 }
-
- Migrating code C++ Buffer code from v0.2 to v0.3 is difficult. Here are
- some tips:
- - buffer->data() calls should become Buffer::Data(buffer) calls.
- - buffer->length() calls should become Buffer::Length(buffer) calls.
- - There should not be any ObjectWrap::Unwrap<Buffer>() calls. You should
- not be storing pointers to Buffer objects at all - as they are
- now considered internal structures. Instead consider making a
- JavaScript reference to the buffer.
-
- See the source code node-png as an example of a module which successfully
- compiles on both v0.2 and v0.3 while making heavy use of the C++ Buffer
- API.
-
- */
-
-
-class NODE_EXTERN Buffer: public ObjectWrap {
- public:
- // mirrors deps/v8/src/objects.h
- static const unsigned int kMaxLength = 0x3fffffff;
-
- static v8::Persistent<v8::FunctionTemplate> constructor_template;
-
- static bool HasInstance(v8::Handle<v8::Value> val);
-
- static inline char* Data(v8::Handle<v8::Value> val) {
- assert(val->IsObject());
- void* data = val.As<v8::Object>()->GetIndexedPropertiesExternalArrayData();
- return static_cast<char*>(data);
- }
-
- static inline char* Data(Buffer *b) {
- return Buffer::Data(b->handle_);
- }
-
- static inline size_t Length(v8::Handle<v8::Value> val) {
- assert(val->IsObject());
- int len = val.As<v8::Object>()
- ->GetIndexedPropertiesExternalArrayDataLength();
- return static_cast<size_t>(len);
- }
-
- static inline size_t Length(Buffer *b) {
- return Buffer::Length(b->handle_);
- }
-
- // This is verbose to be explicit with inline commenting
- static inline bool IsWithinBounds(size_t off, size_t len, size_t max) {
- // Asking to seek too far into the buffer
- // check to avoid wrapping in subsequent subtraction
- if (off > max)
- return false;
+#if defined(NODE_WANT_INTERNALS)
+#include "env.h"
+#endif // defined(NODE_WANT_INTERNALS)
- // Asking for more than is left over in the buffer
- if (max - off < len)
- return false;
-
- // Otherwise we're in bounds
- return true;
- }
-
- ~Buffer();
-
- typedef void (*free_callback)(char *data, void *hint);
-
- // C++ API for constructing fast buffer
- static v8::Handle<v8::Object> New(v8::Handle<v8::String> string);
-
- static void Initialize(v8::Handle<v8::Object> target);
-
- // public constructor
- static Buffer* New(size_t length);
- // public constructor - data is copied
- static Buffer* New(const char *data, size_t len);
- // public constructor
- static Buffer* New(char *data, size_t length,
- free_callback callback, void *hint);
-
- private:
- static v8::Handle<v8::Value> New(const v8::Arguments &args);
-
- template <encoding encoding>
- static v8::Handle<v8::Value> StringSlice(const v8::Arguments &args);
- static v8::Handle<v8::Value> BinarySlice(const v8::Arguments &args);
- static v8::Handle<v8::Value> AsciiSlice(const v8::Arguments &args);
- static v8::Handle<v8::Value> Base64Slice(const v8::Arguments &args);
- static v8::Handle<v8::Value> Utf8Slice(const v8::Arguments &args);
- static v8::Handle<v8::Value> Ucs2Slice(const v8::Arguments &args);
- static v8::Handle<v8::Value> HexSlice(const v8::Arguments &args);
-
- template <encoding encoding>
- static v8::Handle<v8::Value> StringWrite(const v8::Arguments &args);
- static v8::Handle<v8::Value> BinaryWrite(const v8::Arguments &args);
- static v8::Handle<v8::Value> Base64Write(const v8::Arguments &args);
- static v8::Handle<v8::Value> AsciiWrite(const v8::Arguments &args);
- static v8::Handle<v8::Value> Utf8Write(const v8::Arguments &args);
- static v8::Handle<v8::Value> Ucs2Write(const v8::Arguments &args);
- static v8::Handle<v8::Value> HexWrite(const v8::Arguments &args);
- static v8::Handle<v8::Value> ReadFloatLE(const v8::Arguments &args);
- static v8::Handle<v8::Value> ReadFloatBE(const v8::Arguments &args);
- static v8::Handle<v8::Value> ReadDoubleLE(const v8::Arguments &args);
- static v8::Handle<v8::Value> ReadDoubleBE(const v8::Arguments &args);
- static v8::Handle<v8::Value> WriteFloatLE(const v8::Arguments &args);
- static v8::Handle<v8::Value> WriteFloatBE(const v8::Arguments &args);
- static v8::Handle<v8::Value> WriteDoubleLE(const v8::Arguments &args);
- static v8::Handle<v8::Value> WriteDoubleBE(const v8::Arguments &args);
- static v8::Handle<v8::Value> ByteLength(const v8::Arguments &args);
- static v8::Handle<v8::Value> MakeFastBuffer(const v8::Arguments &args);
- static v8::Handle<v8::Value> Fill(const v8::Arguments &args);
- static v8::Handle<v8::Value> Copy(const v8::Arguments &args);
-
- Buffer(v8::Handle<v8::Object> wrapper, size_t length);
- void Replace(char *data, size_t length, free_callback callback, void *hint);
-
- size_t length_;
- char* data_;
- free_callback callback_;
- void* callback_hint_;
-};
-
-
-} // namespace node buffer
-
-#endif // NODE_BUFFER_H_
+namespace node {
+namespace Buffer {
+
+static const unsigned int kMaxLength = smalloc::kMaxLength;
+
+NODE_EXTERN bool HasInstance(v8::Handle<v8::Value> val);
+NODE_EXTERN bool HasInstance(v8::Handle<v8::Object> val);
+NODE_EXTERN char* Data(v8::Handle<v8::Value> val);
+NODE_EXTERN char* Data(v8::Handle<v8::Object> val);
+NODE_EXTERN size_t Length(v8::Handle<v8::Value> val);
+NODE_EXTERN size_t Length(v8::Handle<v8::Object> val);
+
+// public constructor
+NODE_EXTERN v8::Local<v8::Object> New(size_t length);
+// public constructor from string
+NODE_EXTERN v8::Local<v8::Object> New(v8::Handle<v8::String> string,
+ enum encoding enc = UTF8);
+// public constructor - data is copied
+// TODO(trevnorris): should be something like Copy()
+NODE_EXTERN v8::Local<v8::Object> New(const char* data, size_t len);
+// public constructor - data is used, callback is passed data on object gc
+NODE_EXTERN v8::Local<v8::Object> New(char* data,
+ size_t length,
+ smalloc::FreeCallback callback,
+ void* hint);
+
+// public constructor - data is used.
+// TODO(trevnorris): should be New() for consistency
+NODE_EXTERN v8::Local<v8::Object> Use(char* data, uint32_t len);
+
++// This is verbose to be explicit with inline commenting
++static inline bool IsWithinBounds(size_t off, size_t len, size_t max) {
++ // Asking to seek too far into the buffer
++ // check to avoid wrapping in subsequent subtraction
++ if (off > max)
++ return false;
++
++ // Asking for more than is left over in the buffer
++ if (max - off < len)
++ return false;
++
++ // Otherwise we're in bounds
++ return true;
++}
++
+// Internal. Not for public consumption. We can't define these in
+// src/node_internals.h due to a circular dependency issue with
+// the smalloc.h and node_internals.h headers.
+#if defined(NODE_WANT_INTERNALS)
+v8::Local<v8::Object> New(Environment* env, size_t size);
+v8::Local<v8::Object> New(Environment* env, const char* data, size_t len);
+v8::Local<v8::Object> New(Environment* env,
+ char* data,
+ size_t length,
+ smalloc::FreeCallback callback,
+ void* hint);
+v8::Local<v8::Object> Use(Environment* env, char* data, uint32_t length);
+#endif // defined(NODE_WANT_INTERNALS)
+
+} // namespace Buffer
+} // namespace node
+
+#endif // SRC_NODE_BUFFER_H_
#endif
-class Cipher : public ObjectWrap {
- public:
- static void Initialize (v8::Handle<v8::Object> target) {
- HandleScope scope;
-
- Local<FunctionTemplate> t = FunctionTemplate::New(New);
+ int verify_mode;
+ if (is_server) {
+ bool request_cert = args[2]->BooleanValue();
+ if (!request_cert) {
+ // Note reject_unauthorized ignored.
+ verify_mode = SSL_VERIFY_NONE;
+ } else {
+ bool reject_unauthorized = args[3]->BooleanValue();
+ verify_mode = SSL_VERIFY_PEER;
+ if (reject_unauthorized)
+ verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ }
+ } else {
+ // Note request_cert and reject_unauthorized are ignored for clients.
+ verify_mode = SSL_VERIFY_NONE;
+ }
- t->InstanceTemplate()->SetInternalFieldCount(1);
- NODE_SET_PROTOTYPE_METHOD(t, "init", CipherInit);
- NODE_SET_PROTOTYPE_METHOD(t, "initiv", CipherInitIv);
- NODE_SET_PROTOTYPE_METHOD(t, "update", CipherUpdate);
- NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding);
- NODE_SET_PROTOTYPE_METHOD(t, "final", CipherFinal);
+ // Always allow a connection. We'll reject in javascript.
+ SSL_set_verify(conn->ssl_, verify_mode, VerifyCallback);
- target->Set(String::NewSymbol("Cipher"), t->GetFunction());
+ if (is_server) {
+ SSL_set_accept_state(conn->ssl_);
+ } else {
+ SSL_set_connect_state(conn->ssl_);
}
+}
- bool CipherInit(char* cipherType, char* key_buf, int key_buf_len) {
- cipher = EVP_get_cipherbyname(cipherType);
- if(!cipher) {
- fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType);
- return false;
- }
-
- unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH];
- int key_len = EVP_BytesToKey(cipher, EVP_md5(), NULL,
- (unsigned char*) key_buf, key_buf_len, 1, key, iv);
+void Connection::SSLInfoCallback(const SSL *ssl_, int where, int ret) {
+ if (!(where & (SSL_CB_HANDSHAKE_START | SSL_CB_HANDSHAKE_DONE)))
+ return;
- EVP_CIPHER_CTX_init(&ctx);
- EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, true);
- if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
- fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
- EVP_CIPHER_CTX_cleanup(&ctx);
- return false;
- }
- EVP_CipherInit_ex(&ctx, NULL, NULL,
- (unsigned char*)key,
- (unsigned char*)iv, true);
- initialised_ = true;
- return true;
- }
-
-
- bool CipherInitIv(char* cipherType,
- char* key,
- int key_len,
- char* iv,
- int iv_len) {
- cipher = EVP_get_cipherbyname(cipherType);
- if(!cipher) {
- fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType);
- return false;
- }
- /* OpenSSL versions up to 0.9.8l failed to return the correct
- iv_length (0) for ECB ciphers */
- if (EVP_CIPHER_iv_length(cipher) != iv_len &&
- !(EVP_CIPHER_mode(cipher) == EVP_CIPH_ECB_MODE && iv_len == 0)) {
- fprintf(stderr, "node-crypto : Invalid IV length %d\n", iv_len);
- return false;
- }
- EVP_CIPHER_CTX_init(&ctx);
- EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, true);
- if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) {
- fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len);
- EVP_CIPHER_CTX_cleanup(&ctx);
- return false;
- }
- EVP_CipherInit_ex(&ctx, NULL, NULL,
- (unsigned char*)key,
- (unsigned char*)iv, true);
- initialised_ = true;
- return true;
- }
+ // Be compatible with older versions of OpenSSL. SSL_get_app_data() wants
+ // a non-const SSL* in OpenSSL <= 0.9.7e.
+ SSL* ssl = const_cast<SSL*>(ssl_);
+ Connection* conn = static_cast<Connection*>(SSL_get_app_data(ssl));
+ Environment* env = conn->env();
+ HandleScope handle_scope(env->isolate());
+ Context::Scope context_scope(env->context());
- int CipherUpdate(char* data, int len, unsigned char** out, int* out_len) {
- if (!initialised_) return 0;
- *out_len = len+EVP_CIPHER_CTX_block_size(&ctx);
- *out = new unsigned char[*out_len];
- return EVP_CipherUpdate(&ctx, *out, out_len, (unsigned char*)data, len);
+ if (where & SSL_CB_HANDSHAKE_START) {
+ conn->MakeCallback(env->onhandshakestart_string(), 0, NULL);
}
- int SetAutoPadding(bool auto_padding) {
- if (!initialised_) return 0;
- return EVP_CIPHER_CTX_set_padding(&ctx, auto_padding ? 1 : 0);
+ if (where & SSL_CB_HANDSHAKE_DONE) {
+ conn->MakeCallback(env->onhandshakedone_string(), 0, NULL);
}
+}
- int CipherFinal(unsigned char** out, int *out_len) {
- if (!initialised_) return 0;
- *out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx)];
- int r = EVP_CipherFinal_ex(&ctx,*out, out_len);
- EVP_CIPHER_CTX_cleanup(&ctx);
- initialised_ = false;
- return r;
- }
+void Connection::EncIn(const FunctionCallbackInfo<Value>& args) {
+ HandleScope scope(args.GetIsolate());
- protected:
+ Connection* conn = Unwrap<Connection>(args.This());
- static Handle<Value> New(const Arguments& args) {
- HandleScope scope;
+ if (args.Length() < 3) {
+ return ThrowTypeError("Takes 3 parameters");
+ }
- Cipher *cipher = new Cipher();
- cipher->Wrap(args.This());
- return args.This();
+ if (!Buffer::HasInstance(args[0])) {
+ return ThrowTypeError("Second argument should be a buffer");
}
- static Handle<Value> CipherInit(const Arguments& args) {
- HandleScope scope;
+ char* buffer_data = Buffer::Data(args[0]);
+ size_t buffer_length = Buffer::Length(args[0]);
- Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
+ size_t off = args[1]->Int32Value();
+ size_t len = args[2]->Int32Value();
- if (off + len > buffer_length) {
+
- if (args.Length() <= 1
- || !args[0]->IsString()
- || !(args[1]->IsString() || Buffer::HasInstance(args[1])))
- {
- return ThrowException(Exception::Error(String::New(
- "Must give cipher-type, key")));
- }
++ if (!Buffer::IsWithinBounds(off, len, buffer_length))
+ return ThrowError("off + len > buffer.length");
- }
- ASSERT_IS_BUFFER(args[1]);
- ssize_t key_buf_len = Buffer::Length(args[1]);
+ int bytes_written;
+ char* data = buffer_data + off;
+
+ if (conn->is_server() && !conn->hello_parser_.IsEnded()) {
+ // Just accumulate data, everything will be pushed to BIO later
+ if (conn->hello_parser_.IsPaused()) {
+ bytes_written = 0;
+ } else {
+ // Copy incoming data to the internal buffer
+ // (which has a size of the biggest possible TLS frame)
+ size_t available = sizeof(conn->hello_data_) - conn->hello_offset_;
+ size_t copied = len < available ? len : available;
+ memcpy(conn->hello_data_ + conn->hello_offset_, data, copied);
+ conn->hello_offset_ += copied;
- if (key_buf_len < 0) {
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
+ conn->hello_parser_.Parse(conn->hello_data_, conn->hello_offset_);
+ bytes_written = copied;
}
+ } else {
+ bytes_written = BIO_write(conn->bio_read_, data, len);
+ conn->HandleBIOError(conn->bio_read_, "BIO_write", bytes_written);
+ conn->SetShutdownFlags();
+ }
- char* key_buf = new char[key_buf_len];
- ssize_t key_written = DecodeWrite(key_buf, key_buf_len, args[1], BINARY);
- assert(key_written == key_buf_len);
+ args.GetReturnValue().Set(bytes_written);
+}
- String::Utf8Value cipherType(args[0]);
- bool r = cipher->CipherInit(*cipherType, key_buf, key_buf_len);
+void Connection::ClearOut(const FunctionCallbackInfo<Value>& args) {
+ HandleScope scope(args.GetIsolate());
- delete [] key_buf;
+ Connection* conn = Unwrap<Connection>(args.This());
- if (!r) return ThrowCryptoError(ERR_get_error());
+ if (args.Length() < 3) {
+ return ThrowTypeError("Takes 3 parameters");
+ }
- return args.This();
+ if (!Buffer::HasInstance(args[0])) {
+ return ThrowTypeError("Second argument should be a buffer");
}
+ char* buffer_data = Buffer::Data(args[0]);
+ size_t buffer_length = Buffer::Length(args[0]);
- static Handle<Value> CipherInitIv(const Arguments& args) {
- Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
+ size_t off = args[1]->Int32Value();
+ size_t len = args[2]->Int32Value();
- if (off + len > buffer_length) {
+
- HandleScope scope;
++ if (!Buffer::IsWithinBounds(off, len, buffer_length))
+ return ThrowError("off + len > buffer.length");
- }
+ if (!SSL_is_init_finished(conn->ssl_)) {
+ int rv;
- if (args.Length() <= 2
- || !args[0]->IsString()
- || !(args[1]->IsString() || Buffer::HasInstance(args[1]))
- || !(args[2]->IsString() || Buffer::HasInstance(args[2])))
- {
- return ThrowException(Exception::Error(String::New(
- "Must give cipher-type, key, and iv as argument")));
+ if (conn->is_server()) {
+ rv = SSL_accept(conn->ssl_);
+ conn->HandleSSLError("SSL_accept:ClearOut",
+ rv,
+ kZeroIsAnError,
+ kSyscallError);
+ } else {
+ rv = SSL_connect(conn->ssl_);
+ conn->HandleSSLError("SSL_connect:ClearOut",
+ rv,
+ kZeroIsAnError,
+ kSyscallError);
}
- ASSERT_IS_BUFFER(args[1]);
- ssize_t key_len = Buffer::Length(args[1]);
-
- if (key_len < 0) {
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
+ if (rv < 0) {
+ return args.GetReturnValue().Set(rv);
}
+ }
- ASSERT_IS_BUFFER(args[2]);
- ssize_t iv_len = Buffer::Length(args[2]);
+ int bytes_read = SSL_read(conn->ssl_, buffer_data + off, len);
+ conn->HandleSSLError("SSL_read:ClearOut",
+ bytes_read,
+ kZeroIsNotAnError,
+ kSyscallError);
+ conn->SetShutdownFlags();
- if (iv_len < 0) {
- Local<Value> exception = Exception::TypeError(String::New("Bad argument"));
- return ThrowException(exception);
- }
+ args.GetReturnValue().Set(bytes_read);
+}
- char* key_buf = new char[key_len];
- ssize_t key_written = DecodeWrite(key_buf, key_len, args[1], BINARY);
- assert(key_written == key_len);
- char* iv_buf = new char[iv_len];
- ssize_t iv_written = DecodeWrite(iv_buf, iv_len, args[2], BINARY);
- assert(iv_written == iv_len);
+void Connection::ClearPending(const FunctionCallbackInfo<Value>& args) {
+ HandleScope scope(args.GetIsolate());
+ Connection* conn = Unwrap<Connection>(args.This());
+ int bytes_pending = BIO_pending(conn->bio_read_);
+ args.GetReturnValue().Set(bytes_pending);
+}
+
- String::Utf8Value cipherType(args[0]);
+void Connection::EncPending(const FunctionCallbackInfo<Value>& args) {
+ HandleScope scope(args.GetIsolate());
+ Connection* conn = Unwrap<Connection>(args.This());
+ int bytes_pending = BIO_pending(conn->bio_write_);
+ args.GetReturnValue().Set(bytes_pending);
+}
- bool r = cipher->CipherInitIv(*cipherType, key_buf,key_len,iv_buf,iv_len);
- delete [] key_buf;
- delete [] iv_buf;
+void Connection::EncOut(const FunctionCallbackInfo<Value>& args) {
+ HandleScope scope(args.GetIsolate());
- if (!r) return ThrowCryptoError(ERR_get_error());
+ Connection* conn = Unwrap<Connection>(args.This());
- return args.This();
+ if (args.Length() < 3) {
+ return ThrowTypeError("Takes 3 parameters");
}
- static Handle<Value> CipherUpdate(const Arguments& args) {
- Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
+ if (!Buffer::HasInstance(args[0])) {
+ return ThrowTypeError("Second argument should be a buffer");
+ }
- HandleScope scope;
+ char* buffer_data = Buffer::Data(args[0]);
+ size_t buffer_length = Buffer::Length(args[0]);
- ASSERT_IS_STRING_OR_BUFFER(args[0]);
+ size_t off = args[1]->Int32Value();
+ size_t len = args[2]->Int32Value();
- if (off + len > buffer_length) {
+
- // Only copy the data if we have to, because it's a string
- unsigned char* out = 0;
- int out_len = 0, r;
- if (args[0]->IsString()) {
- Local<String> string = args[0].As<String>();
- enum encoding encoding = ParseEncoding(args[1], BINARY);
- if (!StringBytes::IsValidString(string, encoding))
- return ThrowTypeError("Bad input string");
- size_t buflen = StringBytes::StorageSize(string, encoding);
- char* buf = new char[buflen];
- size_t written = StringBytes::Write(buf, buflen, string, encoding);
- r = cipher->CipherUpdate(buf, written, &out, &out_len);
- delete[] buf;
- } else {
- char* buf = Buffer::Data(args[0]);
- size_t buflen = Buffer::Length(args[0]);
- r = cipher->CipherUpdate(buf, buflen, &out, &out_len);
- }
++ if (!Buffer::IsWithinBounds(off, len, buffer_length))
+ return ThrowError("off + len > buffer.length");
- }
- if (r == 0) {
- delete[] out;
- return ThrowCryptoTypeError(ERR_get_error());
- }
+ int bytes_read = BIO_read(conn->bio_write_, buffer_data + off, len);
- Local<Value> outString;
- outString = Encode(out, out_len, BUFFER);
+ conn->HandleBIOError(conn->bio_write_, "BIO_read:EncOut", bytes_read);
+ conn->SetShutdownFlags();
- if (out) delete[] out;
+ args.GetReturnValue().Set(bytes_read);
+}
- return scope.Close(outString);
- }
- static Handle<Value> SetAutoPadding(const Arguments& args) {
- HandleScope scope;
- Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
+void Connection::ClearIn(const FunctionCallbackInfo<Value>& args) {
+ HandleScope scope(args.GetIsolate());
- cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue());
+ Connection* conn = Unwrap<Connection>(args.This());
- return Undefined();
+ if (args.Length() < 3) {
+ return ThrowTypeError("Takes 3 parameters");
}
- static Handle<Value> CipherFinal(const Arguments& args) {
- Cipher *cipher = ObjectWrap::Unwrap<Cipher>(args.This());
+ if (!Buffer::HasInstance(args[0])) {
+ return ThrowTypeError("Second argument should be a buffer");
+ }
- HandleScope scope;
+ char* buffer_data = Buffer::Data(args[0]);
+ size_t buffer_length = Buffer::Length(args[0]);
- unsigned char* out_value = NULL;
- int out_len = -1;
- Local<Value> outString ;
+ size_t off = args[1]->Int32Value();
+ size_t len = args[2]->Int32Value();
- if (off + len > buffer_length) {
+
- int r = cipher->CipherFinal(&out_value, &out_len);
++ if (!Buffer::IsWithinBounds(off, len, buffer_length))
+ return ThrowError("off + len > buffer.length");
- }
- if (out_len <= 0 || r == 0) {
- delete[] out_value;
- out_value = NULL;
- if (r == 0) return ThrowCryptoTypeError(ERR_get_error());
+ if (!SSL_is_init_finished(conn->ssl_)) {
+ int rv;
+ if (conn->is_server()) {
+ rv = SSL_accept(conn->ssl_);
+ conn->HandleSSLError("SSL_accept:ClearIn",
+ rv,
+ kZeroIsAnError,
+ kSyscallError);
+ } else {
+ rv = SSL_connect(conn->ssl_);
+ conn->HandleSSLError("SSL_connect:ClearIn",
+ rv,
+ kZeroIsAnError,
+ kSyscallError);
}
- outString = Encode(out_value, out_len, BUFFER);
-
- delete [] out_value;
- return scope.Close(outString);
- }
-
- Cipher () : ObjectWrap ()
- {
- initialised_ = false;
- }
-
- ~Cipher () {
- if (initialised_) {
- EVP_CIPHER_CTX_cleanup(&ctx);
+ if (rv < 0) {
+ return args.GetReturnValue().Set(rv);
}
}
// 3 length how much to write
// 4 position if integer, position to write at in the file.
// if null, write from the current position
-static Handle<Value> Write(const Arguments& args) {
- HandleScope scope;
+static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
+ HandleScope scope(node_isolate);
- if (!args[0]->IsInt32()) {
- return THROW_BAD_ARGS;
- }
+ assert(args[0]->IsInt32());
+ assert(Buffer::HasInstance(args[1]));
int fd = args[0]->Int32Value();
+ Local<Object> obj = args[1].As<Object>();
+ const char* buf = Buffer::Data(obj);
+ size_t buffer_length = Buffer::Length(obj);
+ size_t off = args[2]->Uint32Value();
+ size_t len = args[3]->Uint32Value();
+ int64_t pos = GET_OFFSET(args[4]);
+ Local<Value> cb = args[5];
- if (!Buffer::HasInstance(args[1])) {
- return ThrowException(Exception::Error(
- String::New("Second argument needs to be a buffer")));
- }
+ if (off > buffer_length)
+ return ThrowRangeError("offset out of bounds");
+ if (len > buffer_length)
+ return ThrowRangeError("length out of bounds");
+ if (off + len < off)
+ return ThrowRangeError("off + len overflow");
- if (off + len > buffer_length)
++ if (!Buffer::IsWithinBounds(off, len, buffer_length))
+ return ThrowRangeError("off + len > buffer.length");
- Local<Object> buffer_obj = args[1]->ToObject();
- char *buffer_data = Buffer::Data(buffer_obj);
- size_t buffer_length = Buffer::Length(buffer_obj);
+ buf += off;
- size_t off = args[2]->Int32Value();
- if (off >= buffer_length) {
- return ThrowException(Exception::Error(
- String::New("Offset is out of bounds")));
+ if (cb->IsFunction()) {
+ ASYNC_CALL(write, cb, fd, buf, len, pos)
+ return;
}
- ssize_t len = args[3]->Int32Value();
- if (!Buffer::IsWithinBounds(off, len, buffer_length)) {
- return ThrowException(Exception::Error(
- String::New("off + len > buffer.length")));
- }
+ SYNC_CALL(write, NULL, fd, buf, len, pos)
+ args.GetReturnValue().Set(SYNC_RESULT);
+}
- ASSERT_OFFSET(args[4]);
- int64_t pos = GET_OFFSET(args[4]);
- char * buf = (char*)buffer_data + off;
- Local<Value> cb = args[5];
+// Wrapper for write(2).
+//
+// bytesWritten = write(fd, string, position, enc, callback)
+// 0 fd integer. file descriptor
+// 1 string non-buffer values are converted to strings
+// 2 position if integer, position to write at in the file.
+// if null, write from the current position
+// 3 enc encoding of string
+static void WriteString(const FunctionCallbackInfo<Value>& args) {
+ HandleScope handle_scope(args.GetIsolate());
+ Environment* env = Environment::GetCurrent(args.GetIsolate());
- if (cb->IsFunction()) {
- ASYNC_CALL(write, cb, fd, buf, len, pos)
- } else {
- SYNC_CALL(write, 0, fd, buf, len, pos)
- return scope.Close(Integer::New(SYNC_RESULT));
+ if (!args[0]->IsInt32())
+ return ThrowTypeError("First argument must be file descriptor");
+
+ Local<Value> cb;
+ Local<Value> string = args[1];
+ int fd = args[0]->Int32Value();
+ char* buf = NULL;
+ int64_t pos;
+ size_t len;
+ bool must_free = false;
+
+ // will assign buf and len if string was external
+ if (!StringBytes::GetExternalParts(string,
+ const_cast<const char**>(&buf),
+ &len)) {
+ enum encoding enc = ParseEncoding(args[3], UTF8);
+ len = StringBytes::StorageSize(string, enc);
+ buf = new char[len];
+ // StorageSize may return too large a char, so correct the actual length
+ // by the write size
+ len = StringBytes::Write(buf, len, args[1], enc);
+ must_free = true;
+ }
+ pos = GET_OFFSET(args[2]);
+ cb = args[4];
+
+ if (!cb->IsFunction()) {
+ SYNC_CALL(write, NULL, fd, buf, len, pos)
+ if (must_free)
+ delete[] buf;
+ return args.GetReturnValue().Set(SYNC_RESULT);
}
+
+ FSReqWrap* req_wrap = new FSReqWrap(env, "write", must_free ? buf : NULL);
+ int err = uv_fs_write(env->event_loop(),
+ &req_wrap->req_,
+ fd,
+ buf,
+ len,
+ pos,
+ After);
+ req_wrap->object()->Set(env->oncomplete_string(), cb);
+ req_wrap->Dispatched();
+ if (err < 0) {
+ uv_fs_t* req = &req_wrap->req_;
+ req->result = err;
+ req->path = NULL;
+ After(req);
+ }
+
+ return args.GetReturnValue().Set(req_wrap->persistent());
}
+
/*
* Wrapper for read(2).
*
}
len = args[3]->Int32Value();
- if (off + len > buffer_length) {
- return ThrowError("Length extends beyond buffer");
- if (!Buffer::IsWithinBounds(off, len, buffer_length)) {
- return ThrowException(Exception::Error(
- String::New("Length extends beyond buffer")));
-- }
++ if (!Buffer::IsWithinBounds(off, len, buffer_length))
++ return ThrowRangeError("Length extends beyond buffer");
pos = GET_OFFSET(args[4]);