| 'use strict'; |
| |
| const common = require('../common'); |
| |
| if (!common.hasCrypto) |
| common.skip('missing crypto'); |
| |
| const h2 = require('http2'); |
| const net = require('net'); |
| |
| const preamble = Buffer.from([ |
| 0x50, 0x52, 0x49, 0x20, 0x2a, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, |
| 0x32, 0x2e, 0x30, 0x0d, 0x0a, 0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, |
| 0x0d, 0x0a, 0x00, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x03, 0x00, 0x00, 0x00, 0x64, 0x00, 0x04, 0x00, 0x00, 0xff, |
| 0xff, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, |
| 0x00, 0xc8, 0x00, 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x05, |
| 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x05, 0x02, 0x00, 0x00, |
| 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, |
| 0x02, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, |
| 0x00, 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, |
| 0x00, 0x03, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x24, 0x00, 0x00, 0x00, |
| 0x0d, 0x00, 0x00, 0x00, 0x0b, 0x0f, 0x83, 0x84, 0x86, 0x41, 0x8a, |
| 0xa0, 0xe4, 0x1d, 0x13, 0x9d, 0x09, 0xb8, 0xf0, 0x1e, 0x07, 0x53, |
| 0x03, 0x2a, 0x2f, 0x2a, 0x90, 0x7a, 0x8a, 0xaa, 0x69, 0xd2, 0x9a, |
| 0xc4, 0xc0, 0x57, 0x0b, 0xcb, 0x87, 0x0f, 0x0d, 0x83, 0x08, 0x00, |
| 0x0f |
| ]); |
| |
| const data = Buffer.from([ |
| 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, |
| 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, |
| 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, |
| 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, |
| 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, |
| 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, |
| 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, |
| 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, |
| 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, |
| 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, |
| 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, |
| 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, |
| 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, |
| 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, |
| 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, |
| 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, |
| 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, |
| 0x6c, 0x6f, 0x0a, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x0a |
| ]); |
| |
| // This is testing the case of a misbehaving client that is not paying |
| // attention to flow control. The initial window size is set to data |
| // payload, which in this case is 18, the stream is set to flowing so |
| // WINDOW_UPDATE frames are being sent, but the client is writing |
| // faster than those can be read. |
| // |
| // Bad client! Bad! |
| // |
| // Fortunately, nghttp2 handles this situation for us by keeping track |
| // of the flow control window and responding with a FLOW_CONTROL_ERROR |
| // causing the stream to get shut down... |
| // |
| // At least, that's what is supposed to happen. |
| |
| let client; |
| const server = h2.createServer({ settings: { initialWindowSize: 18 } }); |
| server.on('stream', (stream) => { |
| stream.on('error', common.expectsError({ |
| code: 'ERR_HTTP2_STREAM_ERROR', |
| name: 'Error', |
| message: 'Stream closed with error code NGHTTP2_FLOW_CONTROL_ERROR' |
| })); |
| stream.on('close', common.mustCall(() => { |
| server.close(common.mustCall()); |
| client.destroy(); |
| })); |
| stream.resume(); |
| stream.respond(); |
| stream.end('ok'); |
| }); |
| |
| server.on('close', common.mustCall()); |
| |
| server.listen(0, () => { |
| client = net.connect(server.address().port, () => { |
| client.write(preamble); |
| client.write(data); |
| client.write(data); |
| }); |
| }); |