Skip to content

Commit 1e066e4

Browse files
committed
Merge branch 'v0.10'
Conflicts: lib/tls.js src/node_crypto.cc src/node_crypto.h
2 parents c17449d + 4a2792c commit 1e066e4

File tree

7 files changed

+103
-36
lines changed

7 files changed

+103
-36
lines changed

lib/_tls_legacy.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -314,16 +314,21 @@ CryptoStream.prototype._read = function read(size) {
314314

315315
if (bytesRead === 0) {
316316
// EOF when cleartext has finished and we have nothing to read
317-
if (this._opposite._finished && this._internallyPendingBytes() === 0) {
317+
if (this._opposite._finished && this._internallyPendingBytes() === 0 ||
318+
this.pair.ssl && this.pair.ssl.receivedShutdown) {
318319
// Perform graceful shutdown
319320
this._done();
320321

321322
// No half-open, sorry!
322-
if (this === this.pair.cleartext)
323+
if (this === this.pair.cleartext) {
323324
this._opposite._done();
324325

325-
// EOF
326-
this.push(null);
326+
// EOF
327+
this.push(null);
328+
} else if (!this.pair.ssl || !this.pair.ssl.receivedShutdown) {
329+
// EOF
330+
this.push(null);
331+
}
327332
} else {
328333
// Bail out
329334
this.push('');

node.gyp

+1-1
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@
320320
],
321321
}],
322322
[
323-
'OS=="linux"', {
323+
'OS=="linux" and node_shared_v8=="false"', {
324324
'ldflags': [
325325
'-Wl,--whole-archive <(PRODUCT_DIR)/obj.target/deps/v8/tools/gyp/libv8_base.<(target_arch).a -Wl,--no-whole-archive',
326326
],

src/node_crypto.cc

+12-27
Original file line numberDiff line numberDiff line change
@@ -852,9 +852,9 @@ void SSLWrap<Base>::AddMethods(Handle<FunctionTemplate> t) {
852852
NODE_SET_PROTOTYPE_METHOD(t, "isInitFinished", IsInitFinished);
853853
NODE_SET_PROTOTYPE_METHOD(t, "verifyError", VerifyError);
854854
NODE_SET_PROTOTYPE_METHOD(t, "getCurrentCipher", GetCurrentCipher);
855-
NODE_SET_PROTOTYPE_METHOD(t, "receivedShutdown", ReceivedShutdown);
856855
NODE_SET_PROTOTYPE_METHOD(t, "endParser", EndParser);
857856
NODE_SET_PROTOTYPE_METHOD(t, "renegotiate", Renegotiate);
857+
NODE_SET_PROTOTYPE_METHOD(t, "shutdown", Shutdown);
858858

859859
#ifdef OPENSSL_NPN_NEGOTIATED
860860
NODE_SET_PROTOTYPE_METHOD(t, "getNegotiatedProtocol", GetNegotiatedProto);
@@ -1206,15 +1206,6 @@ void SSLWrap<Base>::IsSessionReused(const FunctionCallbackInfo<Value>& args) {
12061206
}
12071207

12081208

1209-
template <class Base>
1210-
void SSLWrap<Base>::ReceivedShutdown(const FunctionCallbackInfo<Value>& args) {
1211-
HandleScope scope(node_isolate);
1212-
Base* w = Unwrap<Base>(args.This());
1213-
bool yes = SSL_get_shutdown(w->ssl_) == SSL_RECEIVED_SHUTDOWN;
1214-
args.GetReturnValue().Set(yes);
1215-
}
1216-
1217-
12181209
template <class Base>
12191210
void SSLWrap<Base>::EndParser(const FunctionCallbackInfo<Value>& args) {
12201211
HandleScope scope(node_isolate);
@@ -1237,6 +1228,17 @@ void SSLWrap<Base>::Renegotiate(const FunctionCallbackInfo<Value>& args) {
12371228
}
12381229

12391230

1231+
template <class Base>
1232+
void SSLWrap<Base>::Shutdown(const FunctionCallbackInfo<Value>& args) {
1233+
HandleScope scope(node_isolate);
1234+
1235+
Base* w = Unwrap<Base>(args.This());
1236+
1237+
int rv = SSL_shutdown(w->ssl_);
1238+
args.GetReturnValue().Set(rv);
1239+
}
1240+
1241+
12401242
template <class Base>
12411243
void SSLWrap<Base>::IsInitFinished(const FunctionCallbackInfo<Value>& args) {
12421244
HandleScope scope(node_isolate);
@@ -1619,7 +1621,6 @@ void Connection::Initialize(Environment* env, Handle<Object> target) {
16191621
NODE_SET_PROTOTYPE_METHOD(t, "clearPending", Connection::ClearPending);
16201622
NODE_SET_PROTOTYPE_METHOD(t, "encPending", Connection::EncPending);
16211623
NODE_SET_PROTOTYPE_METHOD(t, "start", Connection::Start);
1622-
NODE_SET_PROTOTYPE_METHOD(t, "shutdown", Connection::Shutdown);
16231624
NODE_SET_PROTOTYPE_METHOD(t, "close", Connection::Close);
16241625

16251626
SSLWrap<Connection>::AddMethods(t);
@@ -2054,22 +2055,6 @@ void Connection::Start(const FunctionCallbackInfo<Value>& args) {
20542055
}
20552056

20562057

2057-
void Connection::Shutdown(const FunctionCallbackInfo<Value>& args) {
2058-
HandleScope scope(node_isolate);
2059-
2060-
Connection* conn = Unwrap<Connection>(args.This());
2061-
2062-
if (conn->ssl_ == NULL) {
2063-
return args.GetReturnValue().Set(false);
2064-
}
2065-
2066-
int rv = SSL_shutdown(conn->ssl_);
2067-
conn->HandleSSLError("SSL_shutdown", rv, kZeroIsNotAnError, kIgnoreSyscall);
2068-
conn->SetShutdownFlags();
2069-
args.GetReturnValue().Set(rv);
2070-
}
2071-
2072-
20732058
void Connection::Close(const FunctionCallbackInfo<Value>& args) {
20742059
HandleScope scope(node_isolate);
20752060

src/node_crypto.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,9 @@ class SSLWrap {
181181
static void IsInitFinished(const v8::FunctionCallbackInfo<v8::Value>& args);
182182
static void VerifyError(const v8::FunctionCallbackInfo<v8::Value>& args);
183183
static void GetCurrentCipher(const v8::FunctionCallbackInfo<v8::Value>& args);
184-
static void ReceivedShutdown(const v8::FunctionCallbackInfo<v8::Value>& args);
185184
static void EndParser(const v8::FunctionCallbackInfo<v8::Value>& args);
186185
static void Renegotiate(const v8::FunctionCallbackInfo<v8::Value>& args);
186+
static void Shutdown(const v8::FunctionCallbackInfo<v8::Value>& args);
187187

188188
#ifdef OPENSSL_NPN_NEGOTIATED
189189
static void GetNegotiatedProto(
@@ -254,7 +254,6 @@ class Connection : public SSLWrap<Connection>, public AsyncWrap {
254254
static void EncPending(const v8::FunctionCallbackInfo<v8::Value>& args);
255255
static void EncOut(const v8::FunctionCallbackInfo<v8::Value>& args);
256256
static void ClearIn(const v8::FunctionCallbackInfo<v8::Value>& args);
257-
static void Shutdown(const v8::FunctionCallbackInfo<v8::Value>& args);
258257
static void Start(const v8::FunctionCallbackInfo<v8::Value>& args);
259258
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
260259

src/tls_wrap.cc

+17-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ TLSCallbacks::TLSCallbacks(Environment* env,
7474
pending_write_item_(NULL),
7575
started_(false),
7676
established_(false),
77-
shutdown_(false) {
77+
shutdown_(false),
78+
eof_(false) {
7879
node::Wrap<TLSCallbacks>(object(), this);
7980

8081
// Initialize queue for clearIn writes
@@ -374,6 +375,13 @@ void TLSCallbacks::ClearOut() {
374375
}
375376
} while (read > 0);
376377

378+
int flags = SSL_get_shutdown(ssl_);
379+
if (!eof_ && flags & SSL_RECEIVED_SHUTDOWN) {
380+
eof_ = true;
381+
Local<Value> arg = Integer::New(UV_EOF, node_isolate);
382+
wrap()->MakeCallback(env()->onread_string(), 1, &arg);
383+
}
384+
377385
if (read == -1) {
378386
int err;
379387
Handle<Value> arg = GetSSLError(read, &err);
@@ -513,6 +521,14 @@ void TLSCallbacks::DoRead(uv_stream_t* handle,
513521
if (nread < 0) {
514522
// Error should be emitted only after all data was read
515523
ClearOut();
524+
525+
// Ignore EOF if received close_notify
526+
if (nread == UV_EOF) {
527+
if (eof_)
528+
return;
529+
eof_ = true;
530+
}
531+
516532
HandleScope handle_scope(env()->isolate());
517533
Context::Scope context_scope(env()->context());
518534
Local<Value> arg = Integer::New(nread, node_isolate);

src/tls_wrap.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
6666
int DoShutdown(ShutdownWrap* req_wrap, uv_shutdown_cb cb);
6767

6868
protected:
69-
static const int kClearOutChunkSize = 16384; // 16kb
69+
static const int kClearOutChunkSize = 1024;
7070

7171
// Maximum number of buffers passed to uv_write()
7272
static const int kSimultaneousBufferCount = 10;
@@ -137,6 +137,10 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
137137
bool established_;
138138
bool shutdown_;
139139

140+
// If true - delivered EOF to the js-land, either after `close_notify`, or
141+
// after the `UV_EOF` on socket.
142+
bool eof_;
143+
140144
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
141145
v8::Persistent<v8::Value> sni_context_;
142146
#endif // SSL_CTRL_SET_TLSEXT_SERVERNAME_CB

test/simple/test-tls-close-notify.js

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright Joyent, Inc. and other Node contributors.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the
5+
// "Software"), to deal in the Software without restriction, including
6+
// without limitation the rights to use, copy, modify, merge, publish,
7+
// distribute, sublicense, and/or sell copies of the Software, and to permit
8+
// persons to whom the Software is furnished to do so, subject to the
9+
// following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included
12+
// in all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
if (!process.versions.openssl) {
23+
console.error('Skipping because node compiled without OpenSSL.');
24+
process.exit(0);
25+
}
26+
27+
var assert = require('assert');
28+
var fs = require('fs');
29+
var net = require('net');
30+
var tls = require('tls');
31+
32+
var common = require('../common');
33+
34+
var ended = 0;
35+
36+
var server = tls.createServer({
37+
key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'),
38+
cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem')
39+
}, function(c) {
40+
// Send close-notify without shutting down TCP socket
41+
if (c.ssl.shutdown() !== 1)
42+
c.ssl.shutdown();
43+
}).listen(common.PORT, function() {
44+
var c = tls.connect(common.PORT, {
45+
rejectUnauthorized: false
46+
}, function() {
47+
// Ensure that we receive 'end' event anyway
48+
c.on('end', function() {
49+
ended++;
50+
c.destroy();
51+
server.close();
52+
});
53+
});
54+
});
55+
56+
process.on('exit', function() {
57+
assert.equal(ended, 1);
58+
});

0 commit comments

Comments
 (0)