UNPKG

1.94 kBJavaScriptView Raw
1const http = require('http');
2const Stream = require('stream');
3const EventEmitter = require('events');
4const http2 = (() => {
5 try {
6 const h2 = require('http2');
7 if (!h2.constants) throw new Error('DAMN_YOU_NPM_HTTP2');
8 return h2;
9 } catch (err) {
10 return {
11 constants: {},
12 connect: () => {
13 throw new Error('Please run node with --expose-http2 to use the http2 request transport');
14 },
15 };
16 }
17})();
18
19const {
20 HTTP2_HEADER_PATH,
21 HTTP2_HEADER_METHOD,
22 HTTP2_HEADER_STATUS,
23} = http2.constants;
24
25class Http2Request extends EventEmitter {
26 constructor(options) {
27 super();
28 this.options = options;
29 this._headers = {
30 [HTTP2_HEADER_PATH]: options.pathname,
31 [HTTP2_HEADER_METHOD]: options.method.toUpperCase(),
32 };
33 }
34
35 setHeader(name, value) {
36 this._headers[name.toLowerCase()] = value;
37 }
38
39 getHeader(name) {
40 return this._headers[name];
41 }
42
43 end() {
44 const options = this.options;
45 const client = http2.connect(`${options.protocol}//${options.hostname}`);
46
47 const req = client.request(this._headers);
48
49 const stream = new Stream.PassThrough();
50
51 client.once('error', (e) => this.emit('error', e));
52 client.once('frameError', (e) => this.emit('error', e));
53
54 req.once('response', (headers) => {
55 stream.headers = headers;
56 stream.statusCode = headers[HTTP2_HEADER_STATUS];
57 stream.status = http.STATUS_CODES[stream.statusCode];
58
59 this.emit('response', stream);
60
61 req.on('data', (chunk) => {
62 if (!stream.push(chunk)) req.pause();
63 });
64
65 req.once('end', () => {
66 stream.push(null);
67 client.destroy();
68 });
69
70 stream.once('error', (err) => {
71 stream.statusCode = 400;
72 stream.status = err.message;
73 });
74 });
75
76 req.end();
77
78 return req;
79 }
80}
81
82
83function request(options) {
84 return new Http2Request(options);
85}
86
87module.exports = { request };