• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const common = require('../common');
4if (!common.hasCrypto)
5  common.skip('missing crypto');
6const fixtures = require('../common/fixtures');
7const assert = require('assert');
8const http2 = require('http2');
9const fs = require('fs');
10const { inspect } = require('util');
11
12const optionsWithTypeError = {
13  offset: 'number',
14  length: 'number',
15  statCheck: 'function'
16};
17
18const types = {
19  boolean: true,
20  function: () => {},
21  number: 1,
22  object: {},
23  array: [],
24  null: null,
25  symbol: Symbol('test')
26};
27
28const fname = fixtures.path('elipses.txt');
29const fd = fs.openSync(fname, 'r');
30
31const server = http2.createServer();
32
33server.on('stream', common.mustCall((stream) => {
34  // Should throw if fd isn't a number
35  Object.keys(types).forEach((type) => {
36    if (type === 'number') {
37      return;
38    }
39
40    assert.throws(
41      () => stream.respondWithFD(types[type], {
42        'content-type': 'text/plain'
43      }),
44      {
45        name: 'TypeError',
46        code: 'ERR_INVALID_ARG_TYPE',
47        message: 'The "fd" argument must be of type number or an instance of' +
48                 ` FileHandle.${common.invalidArgTypeHelper(types[type])}`
49      }
50    );
51  });
52
53  // Check for all possible TypeError triggers on options
54  Object.keys(optionsWithTypeError).forEach((option) => {
55    Object.keys(types).forEach((type) => {
56      if (type === optionsWithTypeError[option]) {
57        return;
58      }
59
60      assert.throws(
61        () => stream.respondWithFD(fd, {
62          'content-type': 'text/plain'
63        }, {
64          [option]: types[type]
65        }),
66        {
67          name: 'TypeError',
68          code: 'ERR_INVALID_OPT_VALUE',
69          message: `The value "${inspect(types[type])}" is invalid ` +
70                   `for option "${option}"`
71        }
72      );
73    });
74  });
75
76  // Should throw if :status 204, 205 or 304
77  [204, 205, 304].forEach((status) => assert.throws(
78    () => stream.respondWithFD(fd, {
79      'content-type': 'text/plain',
80      ':status': status,
81    }),
82    {
83      code: 'ERR_HTTP2_PAYLOAD_FORBIDDEN',
84      name: 'Error',
85      message: `Responses with ${status} status must not have a payload`
86    }
87  ));
88
89  // Should throw if headers already sent
90  stream.respond();
91  assert.throws(
92    () => stream.respondWithFD(fd, {
93      'content-type': 'text/plain'
94    }),
95    {
96      code: 'ERR_HTTP2_HEADERS_SENT',
97      name: 'Error',
98      message: 'Response has already been initiated.'
99    }
100  );
101
102  // Should throw if stream already destroyed
103  stream.destroy();
104  assert.throws(
105    () => stream.respondWithFD(fd, {
106      'content-type': 'text/plain'
107    }),
108    {
109      code: 'ERR_HTTP2_INVALID_STREAM',
110      name: 'Error',
111      message: 'The stream has been destroyed'
112    }
113  );
114}));
115
116server.listen(0, common.mustCall(() => {
117  const client = http2.connect(`http://localhost:${server.address().port}`);
118  const req = client.request();
119
120  req.on('close', common.mustCall(() => {
121    client.close();
122    server.close();
123  }));
124  req.end();
125}));
126