| 'use strict'; |
| |
| const common = require('../common'); |
| if (!common.hasCrypto) |
| common.skip('missing crypto'); |
| const assert = require('assert'); |
| const h2 = require('http2'); |
| |
| // Http2ServerResponse should support checking and reading custom headers |
| |
| const server = h2.createServer(); |
| server.listen(0, common.mustCall(function() { |
| const port = server.address().port; |
| server.once('request', common.mustCall(function(request, response) { |
| const real = 'foo-bar'; |
| const fake = 'bar-foo'; |
| const denormalised = ` ${real.toUpperCase()}\n\t`; |
| const expectedValue = 'abc123'; |
| |
| response.setHeader(real, expectedValue); |
| |
| assert.strictEqual(response.hasHeader(real), true); |
| assert.strictEqual(response.hasHeader(fake), false); |
| assert.strictEqual(response.hasHeader(denormalised), true); |
| assert.strictEqual(response.getHeader(real), expectedValue); |
| assert.strictEqual(response.getHeader(denormalised), expectedValue); |
| assert.strictEqual(response.getHeader(fake), undefined); |
| |
| response.removeHeader(fake); |
| assert.strictEqual(response.hasHeader(fake), false); |
| |
| response.setHeader(real, expectedValue); |
| assert.strictEqual(response.getHeader(real), expectedValue); |
| assert.strictEqual(response.hasHeader(real), true); |
| response.removeHeader(real); |
| assert.strictEqual(response.hasHeader(real), false); |
| |
| response.setHeader(denormalised, expectedValue); |
| assert.strictEqual(response.getHeader(denormalised), expectedValue); |
| assert.strictEqual(response.hasHeader(denormalised), true); |
| assert.strictEqual(response.hasHeader(real), true); |
| |
| response.appendHeader(real, expectedValue); |
| assert.deepStrictEqual(response.getHeader(real), [ |
| expectedValue, |
| expectedValue, |
| ]); |
| assert.strictEqual(response.hasHeader(real), true); |
| |
| response.removeHeader(denormalised); |
| assert.strictEqual(response.hasHeader(denormalised), false); |
| assert.strictEqual(response.hasHeader(real), false); |
| |
| ['hasHeader', 'getHeader', 'removeHeader'].forEach((fnName) => { |
| assert.throws( |
| () => response[fnName](), |
| { |
| code: 'ERR_INVALID_ARG_TYPE', |
| name: 'TypeError', |
| message: 'The "name" argument must be of type string. Received ' + |
| 'undefined' |
| } |
| ); |
| }); |
| |
| [ |
| ':status', |
| ':method', |
| ':path', |
| ':authority', |
| ':scheme', |
| ].forEach((header) => assert.throws( |
| () => response.setHeader(header, 'foobar'), |
| { |
| code: 'ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED', |
| name: 'TypeError', |
| message: 'Cannot set HTTP/2 pseudo-headers' |
| }) |
| ); |
| assert.throws(() => { |
| response.setHeader(real, null); |
| }, { |
| code: 'ERR_HTTP2_INVALID_HEADER_VALUE', |
| name: 'TypeError', |
| message: 'Invalid value "null" for header "foo-bar"' |
| }); |
| assert.throws(() => { |
| response.setHeader(real, undefined); |
| }, { |
| code: 'ERR_HTTP2_INVALID_HEADER_VALUE', |
| name: 'TypeError', |
| message: 'Invalid value "undefined" for header "foo-bar"' |
| }); |
| assert.throws( |
| () => response.setHeader(), // Header name undefined |
| { |
| code: 'ERR_INVALID_ARG_TYPE', |
| name: 'TypeError', |
| message: 'The "name" argument must be of type string. Received ' + |
| 'undefined' |
| } |
| ); |
| assert.throws( |
| () => response.setHeader(''), |
| { |
| code: 'ERR_INVALID_HTTP_TOKEN', |
| name: 'TypeError', |
| message: 'Header name must be a valid HTTP token [""]' |
| } |
| ); |
| |
| response.setHeader(real, expectedValue); |
| const expectedHeaderNames = [real]; |
| assert.deepStrictEqual(response.getHeaderNames(), expectedHeaderNames); |
| const expectedHeaders = { __proto__: null }; |
| expectedHeaders[real] = expectedValue; |
| assert.deepStrictEqual(response.getHeaders(), expectedHeaders); |
| |
| response.getHeaders()[fake] = fake; |
| assert.strictEqual(response.hasHeader(fake), false); |
| assert.strictEqual(Object.getPrototypeOf(response.getHeaders()), null); |
| |
| assert.strictEqual(response.sendDate, true); |
| response.sendDate = false; |
| assert.strictEqual(response.sendDate, false); |
| |
| response.sendDate = true; |
| assert.strictEqual(response.sendDate, true); |
| response.removeHeader('Date'); |
| assert.strictEqual(response.sendDate, false); |
| |
| response.on('finish', common.mustCall(function() { |
| assert.strictEqual(response.headersSent, true); |
| |
| assert.throws( |
| () => response.setHeader(real, expectedValue), |
| { |
| code: 'ERR_HTTP2_HEADERS_SENT', |
| name: 'Error', |
| message: 'Response has already been initiated.' |
| } |
| ); |
| assert.throws( |
| () => response.removeHeader(real, expectedValue), |
| { |
| code: 'ERR_HTTP2_HEADERS_SENT', |
| name: 'Error', |
| message: 'Response has already been initiated.' |
| } |
| ); |
| |
| process.nextTick(() => { |
| assert.throws( |
| () => response.setHeader(real, expectedValue), |
| { |
| code: 'ERR_HTTP2_HEADERS_SENT', |
| name: 'Error', |
| message: 'Response has already been initiated.' |
| } |
| ); |
| assert.throws( |
| () => response.removeHeader(real, expectedValue), |
| { |
| code: 'ERR_HTTP2_HEADERS_SENT', |
| name: 'Error', |
| message: 'Response has already been initiated.' |
| } |
| ); |
| |
| assert.strictEqual(response.headersSent, true); |
| server.close(); |
| }); |
| })); |
| response.end(); |
| })); |
| |
| const url = `http://localhost:${port}`; |
| const client = h2.connect(url, common.mustCall(function() { |
| const headers = { |
| ':path': '/', |
| ':method': 'GET', |
| ':scheme': 'http', |
| ':authority': `localhost:${port}` |
| }; |
| const request = client.request(headers); |
| request.on('end', common.mustCall(function() { |
| client.close(); |
| })); |
| request.end(); |
| request.resume(); |
| })); |
| })); |