Skip to content

Commit

Permalink
Merge pull request #1764 from tobiasdiez/es6_http2wrapper
Browse files Browse the repository at this point in the history
feat: migrate to es6 class instead of util.inherit in http2wrapper
  • Loading branch information
titanism authored Aug 15, 2023
2 parents a29a062 + 7801408 commit 2fd4292
Showing 1 changed file with 137 additions and 138 deletions.
275 changes: 137 additions & 138 deletions src/node/http2wrapper.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const Stream = require('stream');
const util = require('util');
const net = require('net');
const tls = require('tls');
// eslint-disable-next-line node/no-deprecated-api
Expand Down Expand Up @@ -31,169 +30,169 @@ function setProtocol(protocol) {
};
}

function Request(protocol, options) {
Stream.call(this);
const defaultPort = protocol === 'https:' ? 443 : 80;
const defaultHost = 'localhost';
const port = options.port || defaultPort;
const host = options.host || defaultHost;
class Request extends Stream {
constructor(protocol, options) {
super();
const defaultPort = protocol === 'https:' ? 443 : 80;
const defaultHost = 'localhost';
const port = options.port || defaultPort;
const host = options.host || defaultHost;

delete options.port;
delete options.host;

this.method = options.method;
this.path = options.path;
this.protocol = protocol;
this.host = host;

delete options.method;
delete options.path;

const sessionOptions = { ...options };
if (options.socketPath) {
sessionOptions.socketPath = options.socketPath;
sessionOptions.createConnection = this.createUnixConnection.bind(this);
}

delete options.port;
delete options.host;
this._headers = {};

this.method = options.method;
this.path = options.path;
this.protocol = protocol;
this.host = host;
const session = http2.connect(
`${protocol}//${host}:${port}`,
sessionOptions
);
this.setHeader('host', `${host}:${port}`);

delete options.method;
delete options.path;
session.on('error', (error) => this.emit('error', error));

const sessionOptions = { ...options };
if (options.socketPath) {
sessionOptions.socketPath = options.socketPath;
sessionOptions.createConnection = this.createUnixConnection.bind(this);
this.session = session;
}

this._headers = {};
createUnixConnection(authority, options) {
switch (this.protocol) {
case 'http:':
return net.connect(options.socketPath);
case 'https:':
options.ALPNProtocols = ['h2'];
options.servername = this.host;
options.allowHalfOpen = true;
return tls.connect(options.socketPath, options);
default:
throw new Error('Unsupported protocol', this.protocol);
}
}

const session = http2.connect(`${protocol}//${host}:${port}`, sessionOptions);
this.setHeader('host', `${host}:${port}`);
setNoDelay(bool) {

Check warning on line 85 in src/node/http2wrapper.js

View workflow job for this annotation

GitHub Actions / test (14.x)

'bool' is defined but never used

Check warning on line 85 in src/node/http2wrapper.js

View workflow job for this annotation

GitHub Actions / test (16.x)

'bool' is defined but never used

Check warning on line 85 in src/node/http2wrapper.js

View workflow job for this annotation

GitHub Actions / test (18.x)

'bool' is defined but never used
// We can not use setNoDelay with HTTP/2.
// Node 10 limits http2session.socket methods to ones safe to use with HTTP/2.
// See also https://nodejs.org/api/http2.html#http2_http2session_socket
}

session.on('error', (error) => this.emit('error', error));
getFrame() {
if (this.frame) {
return this.frame;
}

this.session = session;
}
const method = {
[HTTP2_HEADER_PATH]: this.path,
[HTTP2_HEADER_METHOD]: this.method
};

/**
* Inherit from `Stream` (which inherits from `EventEmitter`).
*/
util.inherits(Request, Stream);

Request.prototype.createUnixConnection = function (authority, options) {
switch (this.protocol) {
case 'http:':
return net.connect(options.socketPath);
case 'https:':
options.ALPNProtocols = ['h2'];
options.servername = this.host;
options.allowHalfOpen = true;
return tls.connect(options.socketPath, options);
default:
throw new Error('Unsupported protocol', this.protocol);
}
};
let headers = this.mapToHttp2Header(this._headers);

Request.prototype.setNoDelay = function (bool) {
// We can not use setNoDelay with HTTP/2.
// Node 10 limits http2session.socket methods to ones safe to use with HTTP/2.
// See also https://nodejs.org/api/http2.html#http2_http2session_socket
};
headers = Object.assign(headers, method);

Request.prototype.getFrame = function () {
if (this.frame) {
return this.frame;
}
const frame = this.session.request(headers);

const method = {
[HTTP2_HEADER_PATH]: this.path,
[HTTP2_HEADER_METHOD]: this.method
};
frame.once('response', (headers, flags) => {

Check warning on line 107 in src/node/http2wrapper.js

View workflow job for this annotation

GitHub Actions / test (14.x)

'flags' is defined but never used

Check warning on line 107 in src/node/http2wrapper.js

View workflow job for this annotation

GitHub Actions / test (16.x)

'flags' is defined but never used

Check warning on line 107 in src/node/http2wrapper.js

View workflow job for this annotation

GitHub Actions / test (18.x)

'flags' is defined but never used
headers = this.mapToHttpHeader(headers);
frame.headers = headers;
frame.statusCode = headers[HTTP2_HEADER_STATUS];
frame.status = frame.statusCode;
this.emit('response', frame);
});

let headers = this.mapToHttp2Header(this._headers);
this._headerSent = true;

headers = Object.assign(headers, method);
frame.once('drain', () => this.emit('drain'));
frame.on('error', (error) => this.emit('error', error));
frame.on('close', () => this.session.close());

const frame = this.session.request(headers);
this.frame = frame;
return frame;
}

frame.once('response', (headers, flags) => {
headers = this.mapToHttpHeader(headers);
frame.headers = headers;
frame.statusCode = headers[HTTP2_HEADER_STATUS];
frame.status = frame.statusCode;
this.emit('response', frame);
});
mapToHttpHeader(headers) {
const keys = Object.keys(headers);
const http2Headers = {};
for (let key of keys) {
let value = headers[key];
key = key.toLowerCase();
switch (key) {
case HTTP2_HEADER_SET_COOKIE:
value = Array.isArray(value) ? value : [value];
break;
default:
break;
}

http2Headers[key] = value;
}

this._headerSent = true;
return http2Headers;
}

frame.once('drain', () => this.emit('drain'));
frame.on('error', (error) => this.emit('error', error));
frame.on('close', () => this.session.close());
mapToHttp2Header(headers) {
const keys = Object.keys(headers);
const http2Headers = {};
for (let key of keys) {
let value = headers[key];
key = key.toLowerCase();
switch (key) {
case HTTP2_HEADER_HOST:
key = HTTP2_HEADER_AUTHORITY;
value = /^http:\/\/|^https:\/\//.test(value)
? parse(value).host
: value;
break;
default:
break;
}

http2Headers[key] = value;
}

this.frame = frame;
return frame;
};
return http2Headers;
}

Request.prototype.mapToHttpHeader = function (headers) {
const keys = Object.keys(headers);
const http2Headers = {};
for (let key of keys) {
let value = headers[key];
key = key.toLowerCase();
switch (key) {
case HTTP2_HEADER_SET_COOKIE:
value = Array.isArray(value) ? value : [value];
break;
default:
break;
}
setHeader(name, value) {
this._headers[name.toLowerCase()] = value;
}

http2Headers[key] = value;
getHeader(name) {
return this._headers[name.toLowerCase()];
}

return http2Headers;
};

Request.prototype.mapToHttp2Header = function (headers) {
const keys = Object.keys(headers);
const http2Headers = {};
for (let key of keys) {
let value = headers[key];
key = key.toLowerCase();
switch (key) {
case HTTP2_HEADER_HOST:
key = HTTP2_HEADER_AUTHORITY;
value = /^http:\/\/|^https:\/\//.test(value)
? parse(value).host
: value;
break;
default:
break;
}
write(data, encoding) {
const frame = this.getFrame();
return frame.write(data, encoding);
}

pipe(stream, options) {
const frame = this.getFrame();
return frame.pipe(stream, options);
}

http2Headers[key] = value;
end(data) {
const frame = this.getFrame();
frame.end(data);
}

return http2Headers;
};

Request.prototype.setHeader = function (name, value) {
this._headers[name.toLowerCase()] = value;
};

Request.prototype.getHeader = function (name) {
return this._headers[name.toLowerCase()];
};

Request.prototype.write = function (data, encoding) {
const frame = this.getFrame();
return frame.write(data, encoding);
};

Request.prototype.pipe = function (stream, options) {
const frame = this.getFrame();
return frame.pipe(stream, options);
};

Request.prototype.end = function (data) {
const frame = this.getFrame();
frame.end(data);
};

Request.prototype.abort = function (data) {
const frame = this.getFrame();
frame.close(NGHTTP2_CANCEL);
this.session.destroy();
};
abort(data) {

Check warning on line 191 in src/node/http2wrapper.js

View workflow job for this annotation

GitHub Actions / test (14.x)

'data' is defined but never used

Check warning on line 191 in src/node/http2wrapper.js

View workflow job for this annotation

GitHub Actions / test (16.x)

'data' is defined but never used

Check warning on line 191 in src/node/http2wrapper.js

View workflow job for this annotation

GitHub Actions / test (18.x)

'data' is defined but never used
const frame = this.getFrame();
frame.close(NGHTTP2_CANCEL);
this.session.destroy();
}
}

exports.setProtocol = setProtocol;

0 comments on commit 2fd4292

Please sign in to comment.