Skip to content

Commit 4a0f276

Browse files
oyydtargos
authored andcommitted
http2: add Http2Stream.bufferSize
This commit adds `bufferSize` for `Http2Stream`. Refs: #21631 PR-URL: #23711 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent b4c8158 commit 4a0f276

File tree

4 files changed

+139
-0
lines changed

4 files changed

+139
-0
lines changed

doc/api/http2.md

+10
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,15 @@ added: v8.4.0
10121012
Set to `true` if the `Http2Stream` instance was aborted abnormally. When set,
10131013
the `'aborted'` event will have been emitted.
10141014

1015+
#### http2stream.bufferSize
1016+
<!-- YAML
1017+
added: REPLACEME
1018+
-->
1019+
* {number}
1020+
1021+
This property shows the number of characters currently buffered to be written.
1022+
See [`net.Socket.bufferSize`][] for details.
1023+
10151024
#### http2stream.close(code[, callback])
10161025
<!-- YAML
10171026
added: v8.4.0
@@ -3415,6 +3424,7 @@ following additional properties:
34153424
[`http2stream.pushStream()`]: #http2_http2stream_pushstream_headers_options_callback
34163425
[`net.Server.close()`]: net.html#net_server_close_callback
34173426
[`net.Socket`]: net.html#net_class_net_socket
3427+
[`net.Socket.bufferSize`]: net.html#net_socket_buffersize
34183428
[`net.Socket.prototype.ref()`]: net.html#net_socket_ref
34193429
[`net.Socket.prototype.unref()`]: net.html#net_socket_unref
34203430
[`net.connect()`]: net.html#net_net_connect

lib/internal/http2/core.js

+6
Original file line numberDiff line numberDiff line change
@@ -1689,6 +1689,12 @@ class Http2Stream extends Duplex {
16891689
return `Http2Stream ${util.format(obj)}`;
16901690
}
16911691

1692+
get bufferSize() {
1693+
// `bufferSize` properties of `net.Socket` are `undefined` when
1694+
// their `_handle` are falsy. Here we avoid the behavior.
1695+
return this[kState].writeQueueSize + this.writableLength;
1696+
}
1697+
16921698
get endAfterHeaders() {
16931699
return this[kState].endAfterHeaders;
16941700
}
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict';
2+
3+
const { mustCall, hasCrypto, skip } = require('../common');
4+
if (!hasCrypto)
5+
skip('missing crypto');
6+
const assert = require('assert');
7+
const { createServer, connect } = require('http2');
8+
const Countdown = require('../common/countdown');
9+
10+
// This test ensures that `bufferSize` of Http2Session and Http2Stream work
11+
// as expected.
12+
{
13+
const SOCKETS = 2;
14+
const TIMES = 10;
15+
const BUFFER_SIZE = 30;
16+
const server = createServer();
17+
18+
// Other `bufferSize` tests for net module and tls module
19+
// don't assert `bufferSize` of server-side sockets.
20+
server.on('stream', mustCall((stream) => {
21+
stream.on('data', mustCall());
22+
stream.on('end', mustCall());
23+
}, SOCKETS));
24+
25+
server.listen(0, mustCall(() => {
26+
const authority = `http://localhost:${server.address().port}`;
27+
const client = connect(authority);
28+
const countdown = new Countdown(SOCKETS, () => {
29+
client.close();
30+
server.close();
31+
});
32+
33+
client.once('connect', mustCall());
34+
35+
for (let j = 0; j < SOCKETS; j += 1) {
36+
const stream = client.request({ ':method': 'POST' });
37+
stream.on('data', () => {});
38+
stream.on('close', mustCall(() => {
39+
countdown.dec();
40+
}));
41+
42+
for (let i = 0; i < TIMES; i += 1) {
43+
stream.write(Buffer.allocUnsafe(BUFFER_SIZE), mustCall());
44+
const expectedSocketBufferSize = BUFFER_SIZE * (i + 1);
45+
assert.strictEqual(stream.bufferSize, expectedSocketBufferSize);
46+
}
47+
stream.end();
48+
stream.close();
49+
}
50+
}));
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
'use strict';
2+
const common = require('../common');
3+
if (!common.hasCrypto)
4+
common.skip('missing crypto');
5+
const assert = require('assert');
6+
const fixtures = require('../common/fixtures');
7+
const makeDuplexPair = require('../common/duplexpair');
8+
const tls = require('tls');
9+
const net = require('net');
10+
11+
// This test ensures that `bufferSize` also works for those tlsSockets
12+
// created from `socket` of `Duplex`, with which, TLSSocket will wrap
13+
// sockets in `StreamWrap`.
14+
{
15+
const iter = 10;
16+
17+
function createDuplex(port) {
18+
const { clientSide, serverSide } = makeDuplexPair();
19+
20+
return new Promise((resolve, reject) => {
21+
const socket = net.connect({
22+
port,
23+
}, common.mustCall(() => {
24+
clientSide.pipe(socket);
25+
socket.pipe(clientSide);
26+
clientSide.on('close', common.mustCall(() => socket.destroy()));
27+
socket.on('close', common.mustCall(() => clientSide.destroy()));
28+
29+
resolve(serverSide);
30+
}));
31+
});
32+
}
33+
34+
const server = tls.createServer({
35+
key: fixtures.readKey('agent2-key.pem'),
36+
cert: fixtures.readKey('agent2-cert.pem')
37+
}, common.mustCall((socket) => {
38+
let str = '';
39+
socket.setEncoding('utf-8');
40+
socket.on('data', (chunk) => { str += chunk; });
41+
42+
socket.on('end', common.mustCall(() => {
43+
assert.strictEqual(str, 'a'.repeat(iter - 1));
44+
server.close();
45+
}));
46+
}));
47+
48+
server.listen(0, common.mustCall(() => {
49+
const { port } = server.address();
50+
createDuplex(port).then((socket) => {
51+
const client = tls.connect({
52+
socket,
53+
rejectUnauthorized: false,
54+
}, common.mustCall(() => {
55+
assert.strictEqual(client.bufferSize, 0);
56+
57+
for (let i = 1; i < iter; i++) {
58+
client.write('a');
59+
assert.strictEqual(client.bufferSize, i + 1);
60+
}
61+
62+
// It seems that tlsSockets created from sockets of `Duplex` emit no
63+
// "finish" events. We use "end" event instead.
64+
client.on('end', common.mustCall(() => {
65+
assert.strictEqual(client.bufferSize, undefined);
66+
}));
67+
68+
client.end();
69+
}));
70+
});
71+
}));
72+
}

0 commit comments

Comments
 (0)