Skip to content
This repository was archived by the owner on Apr 22, 2023. It is now read-only.

Commit 7f9b015

Browse files
committed
lib: introduce .setMaxSendFragment(size)
fix #6889
1 parent 023f0a3 commit 7f9b015

File tree

5 files changed

+112
-0
lines changed

5 files changed

+112
-0
lines changed

doc/api/tls.markdown

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,18 @@ has been established.
634634
ANOTHER NOTE: When running as the server, socket will be destroyed
635635
with an error after `handshakeTimeout` timeout.
636636

637+
### tlsSocket.setMaxSendFragment(size)
638+
639+
Set maximum TLS fragment size (default and maximum value is: `16384`, minimum
640+
is: `512`). Returns `true` on success, `false` otherwise.
641+
642+
Smaller fragment size decreases buffering latency on the client: large
643+
fragments are buffered by the TLS layer until the entire fragment is received
644+
and its integrity is verified; large fragments can span multiple roundtrips,
645+
and their processing can be delayed due to packet loss or reordering. However,
646+
smaller fragments add extra TLS framing bytes and CPU overhead, which may
647+
decrease overall server throughput.
648+
637649
### tlsSocket.address()
638650

639651
Returns the bound address, the address family name and port of the

lib/_tls_wrap.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ TLSSocket.prototype.renegotiate = function(options, callback) {
303303
return true;
304304
};
305305

306+
TLSSocket.prototype.setMaxSendFragment = function setMaxSendFragment(size) {
307+
return this.ssl.setMaxSendFragment(size) == 1;
308+
};
309+
306310
TLSSocket.prototype._handleTimeout = function() {
307311
this._tlsError(new Error('TLS handshake timeout'));
308312
};

src/node_crypto.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,10 @@ void SSLWrap<Base>::AddMethods(Handle<FunctionTemplate> t) {
857857
NODE_SET_PROTOTYPE_METHOD(t, "renegotiate", Renegotiate);
858858
NODE_SET_PROTOTYPE_METHOD(t, "shutdown", Shutdown);
859859

860+
#ifdef SSL_set_max_send_fragment
861+
NODE_SET_PROTOTYPE_METHOD(t, "setMaxSendFragment", SetMaxSendFragment);
862+
#endif // SSL_set_max_send_fragment
863+
860864
#ifdef OPENSSL_NPN_NEGOTIATED
861865
NODE_SET_PROTOTYPE_METHOD(t, "getNegotiatedProtocol", GetNegotiatedProto);
862866
NODE_SET_PROTOTYPE_METHOD(t, "setNPNProtocols", SetNPNProtocols);
@@ -1240,6 +1244,21 @@ void SSLWrap<Base>::Shutdown(const FunctionCallbackInfo<Value>& args) {
12401244
}
12411245

12421246

1247+
#ifdef SSL_set_max_send_fragment
1248+
template <class Base>
1249+
void SSLWrap<Base>::SetMaxSendFragment(
1250+
const v8::FunctionCallbackInfo<v8::Value>& args) {
1251+
HandleScope scope(node_isolate);
1252+
CHECK(args.Length() >= 1 && args[0]->IsNumber());
1253+
1254+
Base* w = Unwrap<Base>(args.This());
1255+
1256+
int rv = SSL_set_max_send_fragment(w->ssl_, args[0]->Int32Value());
1257+
args.GetReturnValue().Set(rv);
1258+
}
1259+
#endif // SSL_set_max_send_fragment
1260+
1261+
12431262
template <class Base>
12441263
void SSLWrap<Base>::IsInitFinished(const FunctionCallbackInfo<Value>& args) {
12451264
HandleScope scope(node_isolate);

src/node_crypto.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ class SSLWrap {
188188
static void Renegotiate(const v8::FunctionCallbackInfo<v8::Value>& args);
189189
static void Shutdown(const v8::FunctionCallbackInfo<v8::Value>& args);
190190

191+
#ifdef SSL_set_max_send_fragment
192+
static void SetMaxSendFragment(
193+
const v8::FunctionCallbackInfo<v8::Value>& args);
194+
#endif // SSL_set_max_send_fragment
195+
191196
#ifdef OPENSSL_NPN_NEGOTIATED
192197
static void GetNegotiatedProto(
193198
const v8::FunctionCallbackInfo<v8::Value>& args);
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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 buf = new Buffer(10000);
35+
var received = 0;
36+
var ended = 0;
37+
var maxChunk = 768;
38+
39+
var server = tls.createServer({
40+
key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'),
41+
cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem')
42+
}, function(c) {
43+
// Lower and upper limits
44+
assert(!c.setMaxSendFragment(511));
45+
assert(!c.setMaxSendFragment(16385));
46+
47+
// Correct fragment size
48+
assert(c.setMaxSendFragment(maxChunk));
49+
50+
c.end(buf);
51+
}).listen(common.PORT, function() {
52+
var c = tls.connect(common.PORT, {
53+
rejectUnauthorized: false
54+
}, function() {
55+
c.on('data', function(chunk) {
56+
assert(chunk.length <= maxChunk);
57+
received += chunk.length;
58+
});
59+
60+
// Ensure that we receive 'end' event anyway
61+
c.on('end', function() {
62+
ended++;
63+
c.destroy();
64+
server.close();
65+
});
66+
});
67+
});
68+
69+
process.on('exit', function() {
70+
assert.equal(ended, 1);
71+
assert.equal(received, buf.length);
72+
});

0 commit comments

Comments
 (0)