mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
http2: add server handshake utility
PR-URL: https://github.com/nodejs/node/pull/51172 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
d44814ca68
commit
c50524a9fc
@ -2890,6 +2890,19 @@ added: v8.4.0
|
|||||||
Returns a [HTTP/2 Settings Object][] containing the deserialized settings from
|
Returns a [HTTP/2 Settings Object][] containing the deserialized settings from
|
||||||
the given `Buffer` as generated by `http2.getPackedSettings()`.
|
the given `Buffer` as generated by `http2.getPackedSettings()`.
|
||||||
|
|
||||||
|
### `http2.performServerHandshake(socket[, options])`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* `socket` {stream.Duplex}
|
||||||
|
* `options` {Object}
|
||||||
|
* ...: Any [`http2.createServer()`][] option can be provided.
|
||||||
|
* Returns: {ServerHttp2Session}
|
||||||
|
|
||||||
|
Create an HTTP/2 server session from an existing socket.
|
||||||
|
|
||||||
### `http2.sensitiveHeaders`
|
### `http2.sensitiveHeaders`
|
||||||
|
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
|
@ -8,6 +8,7 @@ const {
|
|||||||
getDefaultSettings,
|
getDefaultSettings,
|
||||||
getPackedSettings,
|
getPackedSettings,
|
||||||
getUnpackedSettings,
|
getUnpackedSettings,
|
||||||
|
performServerHandshake,
|
||||||
sensitiveHeaders,
|
sensitiveHeaders,
|
||||||
Http2ServerRequest,
|
Http2ServerRequest,
|
||||||
Http2ServerResponse,
|
Http2ServerResponse,
|
||||||
@ -21,6 +22,7 @@ module.exports = {
|
|||||||
getDefaultSettings,
|
getDefaultSettings,
|
||||||
getPackedSettings,
|
getPackedSettings,
|
||||||
getUnpackedSettings,
|
getUnpackedSettings,
|
||||||
|
performServerHandshake,
|
||||||
sensitiveHeaders,
|
sensitiveHeaders,
|
||||||
Http2ServerRequest,
|
Http2ServerRequest,
|
||||||
Http2ServerResponse,
|
Http2ServerResponse,
|
||||||
|
@ -1228,12 +1228,6 @@ class Http2Session extends EventEmitter {
|
|||||||
constructor(type, options, socket) {
|
constructor(type, options, socket) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (!socket._handle || !socket._handle.isStreamBase) {
|
|
||||||
socket = new JSStreamSocket(socket);
|
|
||||||
}
|
|
||||||
socket.on('error', socketOnError);
|
|
||||||
socket.on('close', socketOnClose);
|
|
||||||
|
|
||||||
// No validation is performed on the input parameters because this
|
// No validation is performed on the input parameters because this
|
||||||
// constructor is not exported directly for users.
|
// constructor is not exported directly for users.
|
||||||
|
|
||||||
@ -1245,6 +1239,12 @@ class Http2Session extends EventEmitter {
|
|||||||
|
|
||||||
socket[kSession] = this;
|
socket[kSession] = this;
|
||||||
|
|
||||||
|
if (!socket._handle || !socket._handle.isStreamBase) {
|
||||||
|
socket = new JSStreamSocket(socket);
|
||||||
|
}
|
||||||
|
socket.on('error', socketOnError);
|
||||||
|
socket.on('close', socketOnClose);
|
||||||
|
|
||||||
this[kState] = {
|
this[kState] = {
|
||||||
destroyCode: NGHTTP2_NO_ERROR,
|
destroyCode: NGHTTP2_NO_ERROR,
|
||||||
flags: SESSION_FLAGS_PENDING,
|
flags: SESSION_FLAGS_PENDING,
|
||||||
@ -1644,7 +1644,7 @@ class ServerHttp2Session extends Http2Session {
|
|||||||
// not be an issue in practice. Additionally, the 'priority' event on
|
// not be an issue in practice. Additionally, the 'priority' event on
|
||||||
// server instances (or any other object) is fully undocumented.
|
// server instances (or any other object) is fully undocumented.
|
||||||
this[kNativeFields][kSessionPriorityListenerCount] =
|
this[kNativeFields][kSessionPriorityListenerCount] =
|
||||||
server.listenerCount('priority');
|
server ? server.listenerCount('priority') : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
get server() {
|
get server() {
|
||||||
@ -3435,6 +3435,11 @@ function getUnpackedSettings(buf, options = kEmptyObject) {
|
|||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function performServerHandshake(socket, options = {}) {
|
||||||
|
options = initializeOptions(options);
|
||||||
|
return new ServerHttp2Session(options, socket, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
binding.setCallbackFunctions(
|
binding.setCallbackFunctions(
|
||||||
onSessionInternalError,
|
onSessionInternalError,
|
||||||
onPriority,
|
onPriority,
|
||||||
@ -3458,6 +3463,7 @@ module.exports = {
|
|||||||
getDefaultSettings,
|
getDefaultSettings,
|
||||||
getPackedSettings,
|
getPackedSettings,
|
||||||
getUnpackedSettings,
|
getUnpackedSettings,
|
||||||
|
performServerHandshake,
|
||||||
sensitiveHeaders: kSensitiveHeaders,
|
sensitiveHeaders: kSensitiveHeaders,
|
||||||
Http2Session,
|
Http2Session,
|
||||||
Http2Stream,
|
Http2Stream,
|
||||||
|
@ -17,6 +17,7 @@ let debug = require('internal/util/debuglog').debuglog(
|
|||||||
);
|
);
|
||||||
const { owner_symbol } = require('internal/async_hooks').symbols;
|
const { owner_symbol } = require('internal/async_hooks').symbols;
|
||||||
const { ERR_STREAM_WRAP } = require('internal/errors').codes;
|
const { ERR_STREAM_WRAP } = require('internal/errors').codes;
|
||||||
|
const { kSession } = require('internal/stream_base_commons');
|
||||||
|
|
||||||
const kCurrentWriteRequest = Symbol('kCurrentWriteRequest');
|
const kCurrentWriteRequest = Symbol('kCurrentWriteRequest');
|
||||||
const kCurrentShutdownRequest = Symbol('kCurrentShutdownRequest');
|
const kCurrentShutdownRequest = Symbol('kCurrentShutdownRequest');
|
||||||
@ -263,6 +264,14 @@ class JSStreamSocket extends Socket {
|
|||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get [kSession]() {
|
||||||
|
return this.stream[kSession];
|
||||||
|
}
|
||||||
|
|
||||||
|
set [kSession](session) {
|
||||||
|
this.stream[kSession] = session;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = JSStreamSocket;
|
module.exports = JSStreamSocket;
|
||||||
|
48
test/parallel/test-http2-perform-server-handshake.js
Normal file
48
test/parallel/test-http2-perform-server-handshake.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
|
||||||
|
if (!common.hasCrypto)
|
||||||
|
common.skip('missing crypto');
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
const http2 = require('http2');
|
||||||
|
const stream = require('stream');
|
||||||
|
const makeDuplexPair = require('../common/duplexpair');
|
||||||
|
|
||||||
|
// Basic test
|
||||||
|
{
|
||||||
|
const { clientSide, serverSide } = makeDuplexPair();
|
||||||
|
|
||||||
|
const client = http2.connect('http://example.com', {
|
||||||
|
createConnection: () => clientSide,
|
||||||
|
});
|
||||||
|
|
||||||
|
const session = http2.performServerHandshake(serverSide);
|
||||||
|
|
||||||
|
session.on('stream', common.mustCall((stream, headers) => {
|
||||||
|
assert.strictEqual(headers[':path'], '/test');
|
||||||
|
stream.respond({
|
||||||
|
':status': 200,
|
||||||
|
});
|
||||||
|
stream.end('hi!');
|
||||||
|
}));
|
||||||
|
|
||||||
|
const req = client.request({ ':path': '/test' });
|
||||||
|
req.on('response', common.mustCall());
|
||||||
|
req.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Double bind should fail
|
||||||
|
{
|
||||||
|
const socket = new stream.Duplex({
|
||||||
|
read() {},
|
||||||
|
write() {},
|
||||||
|
});
|
||||||
|
|
||||||
|
http2.performServerHandshake(socket);
|
||||||
|
|
||||||
|
assert.throws(() => {
|
||||||
|
http2.performServerHandshake(socket);
|
||||||
|
}, { code: 'ERR_HTTP2_SOCKET_BOUND' });
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user