diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown
index 2a4c312b50..372bbd990f 100644
--- a/doc/api/tls.markdown
+++ b/doc/api/tls.markdown
@@ -484,10 +484,11 @@ established - it will be forwarded here.
### Event: 'newSession'
-`function (sessionId, sessionData) { }`
+`function (sessionId, sessionData, callback) { }`
Emitted on creation of TLS session. May be used to store sessions in external
-storage.
+storage. `callback` must be invoked eventually, otherwise no data will be
+sent or received from secure connection.
NOTE: adding this event listener will have an effect only on connections
established after addition of event listener.
diff --git a/lib/_tls_legacy.js b/lib/_tls_legacy.js
index be3c8aff55..6916c1e0d7 100644
--- a/lib/_tls_legacy.js
+++ b/lib/_tls_legacy.js
@@ -653,7 +653,27 @@ function onclienthello(hello) {
function onnewsession(key, session) {
if (!this.server) return;
- this.server.emit('newSession', key, session);
+
+ var self = this;
+ var once = false;
+
+ self.server.emit('newSession', key, session, function() {
+ if (once)
+ return;
+ once = true;
+
+ if (self.ssl)
+ self.ssl.newSessionDone();
+ });
+}
+
+
+function onnewsessiondone() {
+ if (!this.server) return;
+
+ // Cycle through data
+ this.cleartext.read(0);
+ this.encrypted.read(0);
}
diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js
index 3cda50d2d5..c0af83a7ef 100644
--- a/lib/_tls_wrap.js
+++ b/lib/_tls_wrap.js
@@ -138,8 +138,25 @@ function onclienthello(hello) {
function onnewsession(key, session) {
- if (this.server)
- this.server.emit('newSession', key, session);
+ if (!this.server)
+ return;
+
+ var self = this;
+ var once = false;
+
+ this._newSessionPending = true;
+ this.server.emit('newSession', key, session, function() {
+ if (once)
+ return;
+ once = true;
+
+ self.ssl.newSessionDone();
+
+ self._newSessionPending = false;
+ if (self._securePending)
+ self._finishInit();
+ self._securePending = false;
+ });
}
@@ -164,6 +181,8 @@ function TLSSocket(socket, options) {
this._tlsOptions = options;
this._secureEstablished = false;
+ this._securePending = false;
+ this._newSessionPending = false;
this._controlReleased = false;
this._SNICallback = null;
this.ssl = null;
@@ -347,6 +366,12 @@ TLSSocket.prototype._releaseControl = function() {
};
TLSSocket.prototype._finishInit = function() {
+ // `newSession` callback wasn't called yet
+ if (this._newSessionPending) {
+ this._securePending = true;
+ return;
+ }
+
if (process.features.tls_npn) {
this.npnProtocol = this.ssl.getNegotiatedProtocol();
}
diff --git a/src/env.h b/src/env.h
index f1cd4a125f..99f0e2092b 100644
--- a/src/env.h
+++ b/src/env.h
@@ -121,6 +121,7 @@ namespace node {
V(onhandshakestart_string, "onhandshakestart") \
V(onmessage_string, "onmessage") \
V(onnewsession_string, "onnewsession") \
+ V(onnewsessiondone_string, "onnewsessiondone") \
V(onread_string, "onread") \
V(onselect_string, "onselect") \
V(onsignal_string, "onsignal") \
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index 1d5fd25c08..d0a26a605c 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -857,6 +857,7 @@ void SSLWrap::AddMethods(Handle t) {
NODE_SET_PROTOTYPE_METHOD(t, "renegotiate", Renegotiate);
NODE_SET_PROTOTYPE_METHOD(t, "shutdown", Shutdown);
NODE_SET_PROTOTYPE_METHOD(t, "getTLSTicket", GetTLSTicket);
+ NODE_SET_PROTOTYPE_METHOD(t, "newSessionDone", NewSessionDone);
#ifdef SSL_set_max_send_fragment
NODE_SET_PROTOTYPE_METHOD(t, "setMaxSendFragment", SetMaxSendFragment);
@@ -929,6 +930,7 @@ int SSLWrap::NewSessionCallback(SSL* s, SSL_SESSION* sess) {
reinterpret_cast(sess->session_id),
sess->session_id_length);
Local argv[] = { session, buff };
+ w->new_session_wait_ = true;
w->MakeCallback(env->onnewsession_string(), ARRAY_SIZE(argv), argv);
return 0;
@@ -1267,6 +1269,16 @@ void SSLWrap::GetTLSTicket(const FunctionCallbackInfo& args) {
}
+template
+void SSLWrap::NewSessionDone(const FunctionCallbackInfo& args) {
+ HandleScope scope(args.GetIsolate());
+
+ Base* w = Unwrap(args.This());
+ w->new_session_wait_ = false;
+ w->NewSessionDoneCb();
+}
+
+
#ifdef SSL_set_max_send_fragment
template
void SSLWrap::SetMaxSendFragment(
@@ -1651,6 +1663,13 @@ void Connection::SetShutdownFlags() {
}
+void Connection::NewSessionDoneCb() {
+ HandleScope scope(env()->isolate());
+
+ MakeCallback(env()->onnewsessiondone_string(), 0, NULL);
+}
+
+
void Connection::Initialize(Environment* env, Handle