diff --git a/doc/api/errors.md b/doc/api/errors.md
index f52bf680f63a92..46ed1be162a38a 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -1033,6 +1033,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 c70ca2db7b4d05..dc84d9fb6fe4a7 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -590,6 +590,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 e1eb8b517a5e56..950ceb45fc52aa 100644
--- a/lib/internal/http2/core.js
+++ b/lib/internal/http2/core.js
@@ -59,6 +59,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,
@@ -684,12 +685,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) {
@@ -705,7 +711,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'
+ });
+ }));
+ }));
+}));