JSPM

  • Created
  • Published
  • Downloads 13974763
  • Score
    100M100P100Q219152F
  • License MIT

HTTP2 client, just with the familiar `https` API

Package Exports

  • http2-wrapper

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (http2-wrapper) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

http2-wrapper

HTTP2 client, just with the familiar https API

Build Status Coverage Status npm install size

This package is under heavy development. It may contain bugs. Don't forget to report them if you notice any.

This package was created to support HTTP2 without the need to rewrite your code.
I recommend adapting to the http2 module if possible - it's much simpler to use and has many cool features!

Tip: http2-wrapper is very useful when you rely on other modules that use the HTTP1 API and you want to support HTTP2.

Installation

$ npm install http2-wrapper
$ yarn add http2-wrapper

Usage

'use strict';
const http2 = require('http2-wrapper');

const options = {
    hostname: 'nghttp2.org',
    protocol: 'https:',
    path: '/httpbin/post',
    method: 'POST',
    headers: {
        'content-length': 6
    }
};

const request = http2.request(options, response => {
    console.log('statusCode:', response.statusCode);
    console.log('headers:', response.headers);

    const body = [];
    response.on('data', chunk => {
        body.push(chunk);
    });
    response.on('end', () => {
        console.log('body:', Buffer.concat(body).toString());
    });
});

request.on('error', e => console.error(e));

request.write('123');
request.end('456');

// statusCode: 200
// headers: { ':status': 200,
//   date: 'Sat, 11 Aug 2018 09:37:41 GMT',
//   'content-type': 'application/json',
//   'content-length': '264',
//   'access-control-allow-origin': '*',
//   'access-control-allow-credentials': 'true',
//   'x-backend-header-rtt': '0.002997',
//   'strict-transport-security': 'max-age=31536000',
//   server: 'nghttpx',
//   via: '1.1 nghttpx',
//   'x-frame-options': 'SAMEORIGIN',
//   'x-xss-protection': '1; mode=block',
//   'x-content-type-options': 'nosniff' }
// body: {
//   "args": {},
//   "data": "123456",
//   "files": {},
//   "form": {},
//   "headers": {
//     "Content-Length": "6",
//     "Host": "nghttp2.org:443",
//     "Via": "2 nghttpx"
//   },
//   "json": 123456,
//   "origin": "xxx.xxx.xxx.xxx",
//   "url": "https://nghttp2.org:443/httpbin/post"
// }

API

Note: the session option accepts an instance of Http2Session. To pass a SSL session, use socketSession instead.

http2.auto(url, options, callback)

Performs ALPN negotiation. Returns a Promise giving proper ClientRequest instance (depending on the ALPN).

Note: the agent option also accepts an object with http, https and http2 properties.

'use strict';
const http2 = require('http2-wrapper');

const options = {
    hostname: 'httpbin.org',
    protocol: 'http:', // Note the `http:` protocol here
    path: '/post',
    method: 'POST',
    headers: {
        'content-length': 6
    }
};

(async () => {
    try {
        const request = await http2.auto(options, response => {
            console.log('statusCode:', response.statusCode);
            console.log('headers:', response.headers);

            const body = [];
            response.on('data', chunk => body.push(chunk));
            response.on('end', () => {
                console.log('body:', Buffer.concat(body).toString());
            });
        });

        request.on('error', console.error);

        request.write('123');
        request.end('456');
    } catch (error) {
        console.error(error);
    }
})();

// statusCode: 200
// headers: { connection: 'close',
//   server: 'gunicorn/19.9.0',
//   date: 'Sat, 15 Dec 2018 18:19:32 GMT',
//   'content-type': 'application/json',
//   'content-length': '259',
//   'access-control-allow-origin': '*',
//   'access-control-allow-credentials': 'true',
//   via: '1.1 vegur' }
// body: {
//   "args": {},
//   "data": "123456",
//   "files": {},
//   "form": {},
//   "headers": {
//     "Connection": "close",
//     "Content-Length": "6",
//     "Host": "httpbin.org"
//   },
//   "json": 123456,
//   "origin": "xxx.xxx.xxx.xxx",
//   "url": "http://httpbin.org/post"
// }

http2.auto.prepareRequest(url, options)

Performs ALPN negotiation. Returns a Promise giving an object with options and request.

Depending on the ALPN protocol, request is either http2.request or http.request.
Options are normalized.

Note: the agent option also accepts an object with http, https and http2 properties.

http2.auto.resolveALPN(options)

Resolves ALPN using HTTP options.

http2.auto.protocolCache

An object storing cache for detecting ALPN. It looks like:

{
    'hostname:port:alpn1,alpn2': 'alpn1'
}

There are maximum 100 entries.

http2.request(url, options, callback)

Same as https.request.

http2.get(url, options, callback)

Same as https.get.

new http2.ClientRequest(url, options, callback)

Same as https.ClientRequest.

new http2.IncomingMessage(socket)

Same as https.IncomingMessage.

new http2.Agent(options)

Note: this is not compatible with the classic http.Agent.

Usage example:

'use strict';
const http2 = require('http2-wrapper');

class MyAgent extends http2.Agent {
    createConnection(authority, options) {
        console.log(`Connecting to ${authority}`);
        return http2.Agent.connect(authority, options);
    }
}

http2.get({
    hostname: 'google.com',
    agent: new MyAgent()
}, res => {
    res.on('data', chunk => console.log(`Received chunk of ${chunk.length} bytes`));
});

options

Each option is assigned to each Agent instance and can be changed later.

timeout

Type: number
Default: 30000

If there's no activity in given time (milliseconds), the session is closed.

maxSessions

Type: number
Default: Infinity

Max sessions per origin.

maxFreeSessions

Type: number
Default: 1

Max free sessions per origin.

agent.getName(authority, options)

Returns a string containing a proper name for sessions created with these options.

agent.getSession(authority, options)

Returns a Promise giving free Http2Session. If no free sessions are found, a new one is created.

authority

Type: string

Authority used to create a new session.

options

Type: Object

Options used to create a new session.

agent.request(authority, options, headers)

Returns a Promise giving Http2Stream.

agent.createConnection(authority, options)

Returns a new TLS Socket. It defaults to Agent.connect(authority, options).

agent.closeFreeSessions()

Makes an attempt to close free sessions. Only sessions with no concurrent streams are closed.

agent.destroy()

Destroys all sessions.

Notes

Benchmarks

CPU: Intel i7-7700k
Server: H2O 2.2.5 h2o.conf
Node: v12.6.0
Version: master

http2-wrapper x 10,839 ops/sec ±2.19% (84 runs sampled)
http2-wrapper - preconfigured session x 13,005 ops/sec ±3.65% (84 runs sampled)
http2 x 17,100 ops/sec ±3.40% (81 runs sampled)
http2 - using PassThrough proxies x 14,831 ops/sec ±2.22% (84 runs sampled)
https x 1,623 ops/sec ±3.40% (76 runs sampled)
http x 6,761 ops/sec ±3.46% (76 runs sampled)
Fastest is http2

http2-wrapper:

  • It's 1.58x slower than http2.
  • It's 1.37x slower than http2 with PassThrough.
  • It's 6.68x faster than https.
  • It's 1.60x faster than http.

http2-wrapper - preconfigured session:

  • It's 1.31x slower than http2.
  • It's 1.14x slower than http2 with PassThrough.
  • It's 8.01x faster than https.
  • It's 1.92x faster than http.
  • got - Simplified HTTP requests

License

MIT