• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const common = require('../common');
4if (!common.hasCrypto)
5  common.skip('missing crypto');
6const assert = require('assert');
7const h2 = require('http2');
8
9// Http2ServerResponse should support checking and reading custom headers
10
11const server = h2.createServer();
12server.listen(0, common.mustCall(function() {
13  const port = server.address().port;
14  server.once('request', common.mustCall(function(request, response) {
15    const real = 'foo-bar';
16    const fake = 'bar-foo';
17    const denormalised = ` ${real.toUpperCase()}\n\t`;
18    const expectedValue = 'abc123';
19
20    response.setHeader(real, expectedValue);
21
22    assert.strictEqual(response.hasHeader(real), true);
23    assert.strictEqual(response.hasHeader(fake), false);
24    assert.strictEqual(response.hasHeader(denormalised), true);
25    assert.strictEqual(response.getHeader(real), expectedValue);
26    assert.strictEqual(response.getHeader(denormalised), expectedValue);
27    assert.strictEqual(response.getHeader(fake), undefined);
28
29    response.removeHeader(fake);
30    assert.strictEqual(response.hasHeader(fake), false);
31
32    response.setHeader(real, expectedValue);
33    assert.strictEqual(response.getHeader(real), expectedValue);
34    assert.strictEqual(response.hasHeader(real), true);
35    response.removeHeader(real);
36    assert.strictEqual(response.hasHeader(real), false);
37
38    response.setHeader(denormalised, expectedValue);
39    assert.strictEqual(response.getHeader(denormalised), expectedValue);
40    assert.strictEqual(response.hasHeader(denormalised), true);
41    response.removeHeader(denormalised);
42    assert.strictEqual(response.hasHeader(denormalised), false);
43
44    ['hasHeader', 'getHeader', 'removeHeader'].forEach((fnName) => {
45      assert.throws(
46        () => response[fnName](),
47        {
48          code: 'ERR_INVALID_ARG_TYPE',
49          name: 'TypeError',
50          message: 'The "name" argument must be of type string. Received ' +
51                   'undefined'
52        }
53      );
54    });
55
56    [
57      ':status',
58      ':method',
59      ':path',
60      ':authority',
61      ':scheme',
62    ].forEach((header) => assert.throws(
63      () => response.setHeader(header, 'foobar'),
64      {
65        code: 'ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED',
66        name: 'TypeError',
67        message: 'Cannot set HTTP/2 pseudo-headers'
68      })
69    );
70    assert.throws(() => {
71      response.setHeader(real, null);
72    }, {
73      code: 'ERR_HTTP2_INVALID_HEADER_VALUE',
74      name: 'TypeError',
75      message: 'Invalid value "null" for header "foo-bar"'
76    });
77    assert.throws(() => {
78      response.setHeader(real, undefined);
79    }, {
80      code: 'ERR_HTTP2_INVALID_HEADER_VALUE',
81      name: 'TypeError',
82      message: 'Invalid value "undefined" for header "foo-bar"'
83    });
84    assert.throws(
85      () => response.setHeader(), // Header name undefined
86      {
87        code: 'ERR_INVALID_ARG_TYPE',
88        name: 'TypeError',
89        message: 'The "name" argument must be of type string. Received ' +
90                 'undefined'
91      }
92    );
93    assert.throws(
94      () => response.setHeader(''),
95      {
96        code: 'ERR_INVALID_HTTP_TOKEN',
97        name: 'TypeError',
98        message: 'Header name must be a valid HTTP token [""]'
99      }
100    );
101
102    response.setHeader(real, expectedValue);
103    const expectedHeaderNames = [real];
104    assert.deepStrictEqual(response.getHeaderNames(), expectedHeaderNames);
105    const expectedHeaders = Object.create(null);
106    expectedHeaders[real] = expectedValue;
107    assert.deepStrictEqual(response.getHeaders(), expectedHeaders);
108
109    response.getHeaders()[fake] = fake;
110    assert.strictEqual(response.hasHeader(fake), false);
111    assert.strictEqual(Object.getPrototypeOf(response.getHeaders()), null);
112
113    assert.strictEqual(response.sendDate, true);
114    response.sendDate = false;
115    assert.strictEqual(response.sendDate, false);
116
117    response.sendDate = true;
118    assert.strictEqual(response.sendDate, true);
119    response.removeHeader('Date');
120    assert.strictEqual(response.sendDate, false);
121
122    response.on('finish', common.mustCall(function() {
123      assert.strictEqual(response.headersSent, true);
124
125      assert.throws(
126        () => response.setHeader(real, expectedValue),
127        {
128          code: 'ERR_HTTP2_HEADERS_SENT',
129          name: 'Error',
130          message: 'Response has already been initiated.'
131        }
132      );
133      assert.throws(
134        () => response.removeHeader(real, expectedValue),
135        {
136          code: 'ERR_HTTP2_HEADERS_SENT',
137          name: 'Error',
138          message: 'Response has already been initiated.'
139        }
140      );
141
142      process.nextTick(() => {
143        assert.throws(
144          () => response.setHeader(real, expectedValue),
145          {
146            code: 'ERR_HTTP2_HEADERS_SENT',
147            name: 'Error',
148            message: 'Response has already been initiated.'
149          }
150        );
151        assert.throws(
152          () => response.removeHeader(real, expectedValue),
153          {
154            code: 'ERR_HTTP2_HEADERS_SENT',
155            name: 'Error',
156            message: 'Response has already been initiated.'
157          }
158        );
159
160        assert.strictEqual(response.headersSent, true);
161        server.close();
162      });
163    }));
164    response.end();
165  }));
166
167  const url = `http://localhost:${port}`;
168  const client = h2.connect(url, common.mustCall(function() {
169    const headers = {
170      ':path': '/',
171      ':method': 'GET',
172      ':scheme': 'http',
173      ':authority': `localhost:${port}`
174    };
175    const request = client.request(headers);
176    request.on('end', common.mustCall(function() {
177      client.close();
178    }));
179    request.end();
180    request.resume();
181  }));
182}));
183