diff --git a/index.js b/index.js index b079a3408..036500d24 100755 --- a/index.js +++ b/index.js @@ -37,7 +37,7 @@ function initParams (uri, options, callback) { params.callback = callback || params.callback // Disable http/2 when using custom agents that don't handle different versions separately - if (params.agents && !(params.agents.http1 || params.agents.auto || params.agents.h2)) { + if (params.agents && !(params.agents.http1 || params.agents.auto || params.agents.http2)) { params.protocolVersion = 'http1' } diff --git a/lib/autohttp/agent.js b/lib/autohttp/agent.js index 545983dab..e12f2bfab 100644 --- a/lib/autohttp/agent.js +++ b/lib/autohttp/agent.js @@ -83,7 +83,7 @@ class AutoHttp2Agent extends EventEmitter { connection && connection.socket && socketCb(connection.socket) return } - cb(null, 'h2', connection) + cb(null, 'http2', connection) socketCb(connection.socket) return } @@ -138,7 +138,7 @@ class AutoHttp2Agent extends EventEmitter { newOptions, socket ) - cb(null, 'h2', connection) + cb(null, 'http2', connection) } catch (e) { cb(e) } @@ -173,6 +173,10 @@ class AutoHttp2Agent extends EventEmitter { }) } + /* + * This function has been borrowed from Node.js HTTPS Agent implementation + * Ref: v20.15.0 https://github.com/nodejs/node/blob/6bf148e12b00a3ec596f4c123ec35445a48ab209/lib/https.js + */ getName (options) { let name = options.host || 'localhost' diff --git a/lib/autohttp/request.js b/lib/autohttp/request.js index 428048f60..52eadced2 100644 --- a/lib/autohttp/request.js +++ b/lib/autohttp/request.js @@ -16,13 +16,14 @@ class MultiProtocolRequest extends EventEmitter { const agent = options.agent || globalAgent // Request agent to perform alpn and return either an http agent or https agent - // Pass the request to the agent, the agent then calls the callback with http or h2 argument based on the result of alpn negotiation + // Pass the request to the agent, the agent then calls the callback with http or http2 argument based on the result + // of alpn negotiation agent.createConnection(this, options, (err, proto, req) => { if (err) { this.emit('error', err) return } - if (proto === 'h2') { + if (proto === 'http2') { this.onHttp2(req) } if (proto === 'http1') { @@ -115,12 +116,11 @@ class MultiProtocolRequest extends EventEmitter { } get _header () { + if (this._req && this._req._header) { + return this._req._header + } return new Promise((resolve, reject) => { const action = () => resolve(this._req._header) - if (this._req) { - action() - return - } this[kJobs].push(action) }) } diff --git a/lib/autohttp/utils/headers.js b/lib/autohttp/utils/headers.js index 95f30e54f..94afcceac 100644 --- a/lib/autohttp/utils/headers.js +++ b/lib/autohttp/utils/headers.js @@ -1,13 +1,18 @@ -const {constants} = require('http2') +/* + * The following code has been borrowed from the Node.js project + * v20.15.0 /Users/parth.verma@postman.com/node/lib/internal/http2/compat.js + */ +const {constants = {}} = require('http2') + +const kValidPseudoHeaders = new Set([ + constants.HTTP2_HEADER_STATUS, + constants.HTTP2_HEADER_METHOD, + constants.HTTP2_HEADER_AUTHORITY, + constants.HTTP2_HEADER_SCHEME, + constants.HTTP2_HEADER_PATH +]) function assertValidPseudoHeader (header) { - const kValidPseudoHeaders = new Set([ - constants.HTTP2_HEADER_STATUS, - constants.HTTP2_HEADER_METHOD, - constants.HTTP2_HEADER_AUTHORITY, - constants.HTTP2_HEADER_SCHEME, - constants.HTTP2_HEADER_PATH - ]) if (!kValidPseudoHeaders.has(header)) { throw new Error('Invalid PseudoHeader ' + header) } diff --git a/lib/http2/http2Agent.js b/lib/http2/http2Agent.js index bc727eb2f..11b75cb48 100644 --- a/lib/http2/http2Agent.js +++ b/lib/http2/http2Agent.js @@ -67,6 +67,10 @@ class Http2Agent extends EventEmitter { return connection } + /* + * This function has been borrowed from Node.js HTTPS Agent implementation + * Ref: v20.15.0 https://github.com/nodejs/node/blob/6bf148e12b00a3ec596f4c123ec35445a48ab209/lib/https.js + */ getName (options) { let name = options.host || 'localhost' diff --git a/lib/http2/request.js b/lib/http2/request.js index 3987bc935..9226f37e4 100644 --- a/lib/http2/request.js +++ b/lib/http2/request.js @@ -78,7 +78,7 @@ class Http2Request extends EventEmitter { this._client.once('error', this.onError) this.stream.on('response', (response) => { - this.emit('response', new ResponseProxy(response, this)) + this.emit('response', new ResponseProxy(response, this.stream)) }) this.stream.on('end', () => { @@ -153,18 +153,18 @@ function request (options) { } class ResponseProxy extends EventEmitter { - constructor (response, request) { + constructor (response, stream) { super() this.httpVersion = '2.0' - this.req = request + this.reqStream = stream this.response = response this.on = this.on.bind(this) this.registerRequestListeners() } registerRequestListeners () { - this.req.stream.on('error', (e) => this.emit('error', e)) - this.req.stream.on('close', () => { + this.reqStream.on('error', (e) => this.emit('error', e)) + this.reqStream.on('close', () => { this.emit('close') }) } @@ -177,13 +177,13 @@ class ResponseProxy extends EventEmitter { // that forwards the data event to the response object. // If there is no listener attached and we use the event forwarding pattern above, the data event will still be emitted // but with no listeners attached to it, thus causing data loss. - this.req.stream.on('data', (chunk) => { + this.reqStream.on('data', (chunk) => { this.emit('data', chunk) }) } if (eventName === 'end') { - this.req.stream.on('end', listener) + this.reqStream.on('end', listener) } return this } @@ -201,23 +201,23 @@ class ResponseProxy extends EventEmitter { } pause () { - this.req.stream.pause() + this.reqStream.pause() } resume () { - this.req.stream.resume() + this.reqStream.resume() } pipe (dest) { - this.req.stream.pipe(dest) + this.reqStream.pipe(dest) } setEncoding (encoding) { - this.req.stream.setEncoding(encoding) + this.reqStream.setEncoding(encoding) } destroy () { - this.req.stream.destroy() + this.reqStream.destroy() } } diff --git a/request.js b/request.js index 82708ee68..a51180df5 100644 --- a/request.js +++ b/request.js @@ -589,7 +589,7 @@ Request.prototype.init = function (options) { } var protocol = self.proxy && !self.tunnel ? self.proxy.protocol : self.uri.protocol - var defaultModules = {'http:': { h2: http, http1: http, auto: http }, 'https:': { http1: https, h2: http2, auto: autohttp2 }} + var defaultModules = {'http:': { http2: http, http1: http, auto: http }, 'https:': { http1: https, http2: http2, auto: autohttp2 }} var httpModules = self.httpModules || {} // If user defines httpModules, respect if they have different httpModules for different http versions, else use the tls specific http module diff --git a/tests/test-body-http2.js b/tests/test-body-http2.js index 2968c50da..ca163acd2 100644 --- a/tests/test-body-http2.js +++ b/tests/test-body-http2.js @@ -19,7 +19,7 @@ function addTest (name, data) { s.on('/' + name, data.resp) data.uri = s.url + '/' + name request( - { ...data, protocolVersion: 'h2', strictSSL: false }, + { ...data, protocolVersion: 'http2', strictSSL: false }, function (err, resp, body) { t.equal(err, null) if (data.expectBody && Buffer.isBuffer(data.expectBody)) { @@ -163,7 +163,7 @@ tape('testBinaryFile', function (t) { uri: 'https://localhost:' + s.port, method: 'POST', strictSSL: false, - protocolVersion: 'h2', + protocolVersion: 'http2', body: fs.createReadStream(path.join(__dirname, 'raw.file')) }, function (err, res, body) { @@ -190,7 +190,7 @@ tape('typed array', function (t) { body: data, encoding: null, strictSSL: false, - protocolVersion: 'h2' + protocolVersion: 'http2' }, function (err, res, body) { t.error(err) diff --git a/tests/test-brotli-http2.js b/tests/test-brotli-http2.js index dec9e8ae8..e143080ad 100644 --- a/tests/test-brotli-http2.js +++ b/tests/test-brotli-http2.js @@ -89,7 +89,7 @@ tape('transparently supports brotli decoding to callbacks', function (t) { var options = { url: s.url + '/foo', brotli: true, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } request.get(options, function (err, res, body) { @@ -104,7 +104,7 @@ tape('transparently supports brotli decoding to pipes', function (t) { var options = { url: s.url + '/foo', brotli: true, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } var chunks = [] @@ -130,7 +130,7 @@ tape( url: s.url + '/foo', headers: headers, brotli: true, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } request.get(options, function (err, res, body) { @@ -147,7 +147,7 @@ tape('does not decode user-requested encoding by default', function (t) { var options = { url: s.url + '/foo', headers: headers, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } request.get(options, function (err, res, body) { @@ -164,7 +164,7 @@ tape('does not decode brotli encoding when "gzip" option is set', function (t) { url: s.url + '/foo', headers: headers, gzip: true, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } request.get(options, function (err, res, body) { @@ -182,7 +182,7 @@ tape('supports character encoding with brotli encoding', function (t) { headers: headers, brotli: true, encoding: 'utf8', - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } var strings = [] @@ -205,7 +205,7 @@ tape('transparently supports brotli error to callbacks', function (t) { var options = { url: s.url + '/error', brotli: true, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } request.get(options, function (err, res, body) { @@ -220,7 +220,7 @@ tape('transparently supports brotli error to pipes', function (t) { var options = { url: s.url + '/error', brotli: true, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } request @@ -241,7 +241,7 @@ tape('pause when streaming from a brotli request object', function (t) { var options = { url: s.url + '/chunks', brotli: true, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } request.get(options, function (err, res, body) { @@ -256,7 +256,7 @@ tape('pause before streaming from a brotli request object', function (t) { var options = { url: s.url + '/foo', brotli: true, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } var r = request.get(options) @@ -279,7 +279,7 @@ tape('do not try to pipe HEAD request responses', function (t) { method: 'HEAD', url: s.url + '/foo', brotli: true, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } @@ -294,7 +294,7 @@ tape('do not try to pipe responses with no body', function (t) { var options = { url: s.url + '/foo', brotli: true, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false } diff --git a/tests/test-cookies-http2.js b/tests/test-cookies-http2.js index 4aa9c30c4..46ebddf3e 100644 --- a/tests/test-cookies-http2.js +++ b/tests/test-cookies-http2.js @@ -56,7 +56,7 @@ tape('after server sends a cookie', function (t) { method: 'GET', url: validUrl, jar: jar1, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false }, function (error, response, body) { @@ -78,7 +78,7 @@ tape('after server sends a malformed cookie', function (t) { method: 'GET', url: malformedUrl, jar: jar, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false }, function (error, response, body) { @@ -100,7 +100,7 @@ tape('after server sends a cookie for a different domain', function (t) { method: 'GET', url: invalidUrl, jar: jar2, - protocolVersion: 'h2', + protocolVersion: 'http2', strictSSL: false }, function (error, response, body) { diff --git a/tests/test-timeout-http2.js b/tests/test-timeout-http2.js index 4b6edc40a..cbf848f26 100644 --- a/tests/test-timeout-http2.js +++ b/tests/test-timeout-http2.js @@ -47,7 +47,7 @@ tape('should timeout', function (t) { url: s.url + '/timeout', timeout: 100, strictSSL: false, - protocolVersion: 'h2' + protocolVersion: 'http2' } request(shouldTimeout, function (err, res, body) { @@ -61,7 +61,7 @@ tape('should set connect to false', function (t) { url: s.url + '/timeout', timeout: 100, strictSSL: false, - protocolVersion: 'h2' + protocolVersion: 'http2' } request(shouldTimeout, function (err, res, body) { @@ -78,7 +78,7 @@ tape('should timeout with events', function (t) { url: s.url + '/timeout', timeout: 100, strictSSL: false, - protocolVersion: 'h2' + protocolVersion: 'http2' } var eventsEmitted = 0 @@ -95,7 +95,7 @@ tape('should not timeout', function (t) { url: s.url + '/timeout', timeout: 1200, strictSSL: false, - protocolVersion: 'h2' + protocolVersion: 'http2' } var socket @@ -113,7 +113,7 @@ tape('no timeout', function (t) { var noTimeout = { url: s.url + '/timeout', strictSSL: false, - protocolVersion: 'h2' + protocolVersion: 'http2' } request(noTimeout, function (err, res, body) { @@ -128,7 +128,7 @@ tape('negative timeout', function (t) { // should be treated a zero or the minim url: s.url + '/timeout', timeout: -1000, strictSSL: false, - protocolVersion: 'h2' + protocolVersion: 'http2' } request(negativeTimeout, function (err, res, body) { @@ -146,7 +146,7 @@ tape('float timeout', function (t) { // should be rounded by setTimeout anyway url: s.url + '/timeout', timeout: 100.76, strictSSL: false, - protocolVersion: 'h2' + protocolVersion: 'http2' } request(floatTimeout, function (err, res, body) { diff --git a/tests/test-timing-http2.js b/tests/test-timing-http2.js index 4a2ac9888..e07cfe51c 100644 --- a/tests/test-timing-http2.js +++ b/tests/test-timing-http2.js @@ -46,7 +46,7 @@ tape('setup', function (t) { }) tape('HTTPS: non-redirected request is timed', function (t) { - var options = {time: true, strictSSL: false, protocolVersion: 'h2'} + var options = {time: true, strictSSL: false, protocolVersion: 'http2'} var start = new Date().getTime() var r = request('https://localhost:' + httpsServer.port + '/', options, function (err, res, body) { @@ -100,7 +100,7 @@ tape('HTTPS: non-redirected request is timed', function (t) { }) tape('HTTPS: redirected request is timed with rollup', function (t) { - var options = {time: true, strictSSL: false, protocolVersion: 'h2'} + var options = {time: true, strictSSL: false, protocolVersion: 'http2'} var r = request('https://localhost:' + httpsServer.port + '/redir', options, function (err, res, body) { t.equal(err, null) t.equal(typeof res.elapsedTime, 'number')