• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2// Flags: --expose-internals
3
4const common = require('../common');
5if (!common.hasCrypto)
6  common.skip('missing crypto');
7
8const { internalBinding } = require('internal/test/binding');
9const {
10  constants,
11  Http2Session,
12  nghttp2ErrorString
13} = internalBinding('http2');
14const http2 = require('http2');
15const { NghttpError } = require('internal/http2/util');
16
17// Tests error handling within requestOnConnect
18// - NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE (should emit session error)
19// - NGHTTP2_ERR_INVALID_ARGUMENT (should emit stream error)
20// - every other NGHTTP2 error from binding (should emit session error)
21
22const specificTestKeys = [
23  'NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE',
24  'NGHTTP2_ERR_INVALID_ARGUMENT',
25];
26
27const specificTests = [
28  {
29    ngError: constants.NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE,
30    error: {
31      code: 'ERR_HTTP2_OUT_OF_STREAMS',
32      name: 'Error',
33      message: 'No stream ID is available because ' +
34               'maximum stream ID has been reached'
35    },
36    type: 'stream'
37  },
38  {
39    ngError: constants.NGHTTP2_ERR_INVALID_ARGUMENT,
40    error: {
41      code: 'ERR_HTTP2_STREAM_SELF_DEPENDENCY',
42      name: 'Error',
43      message: 'A stream cannot depend on itself'
44    },
45    type: 'stream'
46  },
47];
48
49const genericTests = Object.getOwnPropertyNames(constants)
50  .filter((key) => (
51    key.indexOf('NGHTTP2_ERR') === 0 && specificTestKeys.indexOf(key) < 0
52  ))
53  .map((key) => ({
54    ngError: constants[key],
55    error: {
56      code: 'ERR_HTTP2_ERROR',
57      constructor: NghttpError,
58      name: 'Error',
59      message: nghttp2ErrorString(constants[key])
60    },
61    type: 'session'
62  }));
63
64const tests = specificTests.concat(genericTests);
65
66let currentError;
67
68// Mock submitRequest because we only care about testing error handling
69Http2Session.prototype.request = () => currentError;
70
71const server = http2.createServer(common.mustNotCall());
72
73server.listen(0, common.mustCall(() => runTest(tests.shift())));
74
75function runTest(test) {
76  const client = http2.connect(`http://localhost:${server.address().port}`);
77  client.on('close', common.mustCall());
78
79  const req = client.request({ ':method': 'POST' });
80
81  currentError = test.ngError;
82  req.resume();
83  req.end();
84
85  const errorMustCall = common.expectsError(test.error);
86  const errorMustNotCall = common.mustNotCall(
87    `${test.error.code} should emit on ${test.type}`
88  );
89
90  if (test.type === 'stream') {
91    client.on('error', errorMustNotCall);
92    req.on('error', errorMustCall);
93  } else {
94    client.on('error', errorMustCall);
95    req.on('error', (err) => {
96      common.expectsError({
97        code: 'ERR_HTTP2_STREAM_CANCEL'
98      })(err);
99      common.expectsError({
100        code: 'ERR_HTTP2_ERROR'
101      })(err.cause);
102    });
103  }
104
105  req.on('end', common.mustNotCall());
106  req.on('close', common.mustCall(() => {
107    client.destroy();
108
109    if (!tests.length) {
110      server.close();
111    } else {
112      runTest(tests.shift());
113    }
114  }));
115}
116