diff --git a/doc/api/errors.md b/doc/api/errors.md index 72e61c49bb970a..61bf5a9dbdc09f 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1031,6 +1031,12 @@ The `Http2Session` settings canceled. An attempt was made to connect a `Http2Session` object to a `net.Socket` or `tls.TLSSocket` that had already been bound to another `Http2Session` object. + +### ERR_HTTP2_SOCKET_UNBOUND + +An attempt was made to use the `socket` property of an `Http2Session` that +has already been closed. + ### ERR_HTTP2_STATUS_101 diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 0520fbbc6f6668..899979e5cc39e8 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -588,6 +588,8 @@ E('ERR_HTTP2_SESSION_ERROR', 'Session closed with error code %s', Error); E('ERR_HTTP2_SETTINGS_CANCEL', 'HTTP2 session settings canceled', Error); E('ERR_HTTP2_SOCKET_BOUND', 'The socket is already bound to an Http2Session', Error); +E('ERR_HTTP2_SOCKET_UNBOUND', + 'The socket has been disconnected from the Http2Session', Error); E('ERR_HTTP2_STATUS_101', 'HTTP status code 101 (Switching Protocols) is forbidden in HTTP/2', Error); E('ERR_HTTP2_STATUS_INVALID', 'Invalid status code: %s', RangeError); diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index c0c452a35f175f..61dd06b5edec76 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -60,6 +60,7 @@ const { ERR_HTTP2_SESSION_ERROR, ERR_HTTP2_SETTINGS_CANCEL, ERR_HTTP2_SOCKET_BOUND, + ERR_HTTP2_SOCKET_UNBOUND, ERR_HTTP2_STATUS_101, ERR_HTTP2_STATUS_INVALID, ERR_HTTP2_STREAM_CANCEL, @@ -685,12 +686,17 @@ const proxySocketHandler = { throw new ERR_HTTP2_NO_SOCKET_MANIPULATION(); default: const socket = session[kSocket]; + if (socket === undefined) + throw new ERR_HTTP2_SOCKET_UNBOUND(); const value = socket[prop]; return typeof value === 'function' ? value.bind(socket) : value; } }, getPrototypeOf(session) { - return Reflect.getPrototypeOf(session[kSocket]); + const socket = session[kSocket]; + if (socket === undefined) + throw new ERR_HTTP2_SOCKET_UNBOUND(); + return Reflect.getPrototypeOf(socket); }, set(session, prop, value) { switch (prop) { @@ -706,7 +712,10 @@ const proxySocketHandler = { case 'write': throw new ERR_HTTP2_NO_SOCKET_MANIPULATION(); default: - session[kSocket][prop] = value; + const socket = session[kSocket]; + if (socket === undefined) + throw new ERR_HTTP2_SOCKET_UNBOUND(); + socket[prop] = value; return true; } } diff --git a/test/parallel/test-http2-unbound-socket-proxy.js b/test/parallel/test-http2-unbound-socket-proxy.js new file mode 100644 index 00000000000000..44f113bac962f7 --- /dev/null +++ b/test/parallel/test-http2-unbound-socket-proxy.js @@ -0,0 +1,69 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const http2 = require('http2'); +const net = require('net'); + +const server = http2.createServer(); +server.on('stream', common.mustCall((stream) => { + stream.respond(); + stream.end('ok'); +})); + +server.listen(0, common.mustCall(() => { + const client = http2.connect(`http://localhost:${server.address().port}`); + const socket = client.socket; + const req = client.request(); + req.resume(); + req.on('close', common.mustCall(() => { + client.close(); + server.close(); + + // Tests to make sure accessing the socket proxy fails with an + // informative error. + setImmediate(common.mustCall(() => { + common.expectsError(() => { + socket.example; + }, { + code: 'ERR_HTTP2_SOCKET_UNBOUND' + }); + common.expectsError(() => { + socket.example = 1; + }, { + code: 'ERR_HTTP2_SOCKET_UNBOUND' + }); + common.expectsError(() => { + socket instanceof net.Socket; + }, { + code: 'ERR_HTTP2_SOCKET_UNBOUND' + }); + common.expectsError(() => { + socket.ref(); + }, { + code: 'ERR_HTTP2_SOCKET_UNBOUND' + }); + common.expectsError(() => { + socket.unref(); + }, { + code: 'ERR_HTTP2_SOCKET_UNBOUND' + }); + common.expectsError(() => { + socket.setEncoding(); + }, { + code: 'ERR_HTTP2_SOCKET_UNBOUND' + }); + common.expectsError(() => { + socket.setKeepAlive(); + }, { + code: 'ERR_HTTP2_SOCKET_UNBOUND' + }); + common.expectsError(() => { + socket.setNoDelay(); + }, { + code: 'ERR_HTTP2_SOCKET_UNBOUND' + }); + })); + })); +}));