mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 18:25:13 +08:00
Increase the default HTTP/2 stream window from 64KB (65535) to 4MB (4194304) and the default local connection window to 32MB (33554432). The default 64KB window limits throughput on high-latency connections to window_size / RTT. With a 250ms RTT, throughput is limited to 256KB/s. The new defaults improve throughput to 16MB/s (128Mbps) for the stream window and 128MB/s (1Gbps) for the connection window. Fixes: https://github.com/nodejs/node/issues/38426 Signed-off-by: Matteo Collina <hello@matteocollina.com> PR-URL: https://github.com/nodejs/node/pull/64623 Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Aviv Keller <me@aviv.sh> Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
85 lines
2.8 KiB
JavaScript
85 lines
2.8 KiB
JavaScript
'use strict';
|
|
|
|
const common = require('../common');
|
|
|
|
if (!common.hasCrypto)
|
|
common.skip('missing crypto');
|
|
|
|
const http2 = require('http2');
|
|
const net = require('net');
|
|
|
|
// Regression test: a connection-level WINDOW_UPDATE that causes the flow
|
|
// control window to exceed 2^31-1 must destroy the Http2Session (not leak it).
|
|
//
|
|
// nghttp2 responds with GOAWAY(FLOW_CONTROL_ERROR) internally but previously
|
|
// Node's OnInvalidFrame callback only propagated errors for
|
|
// NGHTTP2_ERR_STREAM_CLOSED and NGHTTP2_ERR_PROTO. The missing
|
|
// NGHTTP2_ERR_FLOW_CONTROL case left the session unreachable after the GOAWAY,
|
|
// causing a memory leak.
|
|
|
|
const server = http2.createServer();
|
|
|
|
server.on('session', common.mustCall((session) => {
|
|
session.on('error', common.mustCall());
|
|
session.on('close', common.mustCall(() => server.close()));
|
|
}));
|
|
|
|
server.listen(0, common.mustCall(() => {
|
|
const conn = net.connect({
|
|
port: server.address().port,
|
|
allowHalfOpen: true,
|
|
});
|
|
|
|
// HTTP/2 client connection preface.
|
|
conn.write('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n');
|
|
|
|
// Empty SETTINGS frame (9-byte header, 0-byte payload).
|
|
const settingsFrame = Buffer.alloc(9);
|
|
settingsFrame[3] = 0x04; // type: SETTINGS
|
|
conn.write(settingsFrame);
|
|
|
|
let inbuf = Buffer.alloc(0);
|
|
let state = 'settingsHeader';
|
|
let settingsFrameLength;
|
|
|
|
conn.on('data', (chunk) => {
|
|
inbuf = Buffer.concat([inbuf, chunk]);
|
|
|
|
switch (state) {
|
|
case 'settingsHeader':
|
|
if (inbuf.length < 9) return;
|
|
settingsFrameLength = inbuf.readUIntBE(0, 3);
|
|
inbuf = inbuf.slice(9);
|
|
state = 'readingSettings';
|
|
// Fallthrough
|
|
case 'readingSettings': {
|
|
if (inbuf.length < settingsFrameLength) return;
|
|
inbuf = inbuf.slice(settingsFrameLength);
|
|
state = 'done';
|
|
|
|
// ACK the server SETTINGS.
|
|
const ack = Buffer.alloc(9);
|
|
ack[3] = 0x04; // type: SETTINGS
|
|
ack[4] = 0x01; // flag: ACK
|
|
conn.write(ack);
|
|
|
|
// WINDOW_UPDATE on stream 0 (connection level) with increment 2^31-1.
|
|
// Default connection window is now 33554432, so the new total would be
|
|
// 33554432 + 2147483647 = 2181038079 > 2^31-1, triggering
|
|
// NGHTTP2_ERR_FLOW_CONTROL inside nghttp2.
|
|
const windowUpdate = Buffer.alloc(13);
|
|
windowUpdate.writeUIntBE(4, 0, 3); // length = 4
|
|
windowUpdate[3] = 0x08; // type: WINDOW_UPDATE
|
|
windowUpdate[4] = 0x00; // flags: none
|
|
windowUpdate.writeUIntBE(0, 5, 4); // stream id: 0
|
|
windowUpdate.writeUIntBE(0x7FFFFFFF, 9, 4); // increment: 2^31-1
|
|
conn.write(windowUpdate);
|
|
}
|
|
}
|
|
});
|
|
|
|
// The server must close the connection after sending GOAWAY.
|
|
conn.on('end', common.mustCall(() => conn.end()));
|
|
conn.on('close', common.mustCall());
|
|
}));
|