From cc7258469c982b40dec562d710ccd785d2b9bef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Lucas=20Lucchetta?= Date: Thu, 20 Aug 2020 00:01:57 -0300 Subject: [PATCH] http2: fix Http2Response.sendDate The `sendDate` flag was not being respected by the current implementation and the `Date` header was being sent regardless of the config. This commit fixes that and adds tests for this case. Fixes: https://github.com/nodejs/node/issues/34841 PR-URL: https://github.com/nodejs/node/pull/34850 Reviewed-By: Matteo Collina Reviewed-By: Ricky Zhou <0x19951125@gmail.com> Reviewed-By: Denys Otrishko Reviewed-By: Rich Trott --- lib/internal/http2/compat.js | 8 ++++++ lib/internal/http2/core.js | 17 +++++++----- ...compat-serverresponse-headers-send-date.js | 26 +++++++++++++++++++ ...est-http2-compat-serverresponse-headers.js | 5 ++++ 4 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 test/parallel/test-http2-compat-serverresponse-headers-send-date.js diff --git a/lib/internal/http2/compat.js b/lib/internal/http2/compat.js index 085ae11b9e5491..38413510de5ff3 100644 --- a/lib/internal/http2/compat.js +++ b/lib/internal/http2/compat.js @@ -583,6 +583,13 @@ class Http2ServerResponse extends Stream { throw new ERR_HTTP2_HEADERS_SENT(); name = name.trim().toLowerCase(); + + if (name === 'date') { + this[kState].sendDate = false; + + return; + } + delete this[kHeaders][name]; } @@ -775,6 +782,7 @@ class Http2ServerResponse extends Stream { const options = { endStream: state.ending, waitForTrailers: true, + sendDate: state.sendDate }; this[kStream].respond(headers, options); } diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index 1bd0a9f7ae90bc..80f9834006ba56 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -2257,7 +2257,7 @@ function callStreamClose(stream) { stream.close(); } -function processHeaders(oldHeaders) { +function processHeaders(oldHeaders, options) { assertIsObject(oldHeaders, 'headers'); const headers = ObjectCreate(null); @@ -2274,9 +2274,12 @@ function processHeaders(oldHeaders) { headers[HTTP2_HEADER_STATUS] = headers[HTTP2_HEADER_STATUS] | 0 || HTTP_STATUS_OK; - if (headers[HTTP2_HEADER_DATE] === null || - headers[HTTP2_HEADER_DATE] === undefined) - headers[HTTP2_HEADER_DATE] = utcDate(); + if (options.sendDate == null || options.sendDate) { + if (headers[HTTP2_HEADER_DATE] === null || + headers[HTTP2_HEADER_DATE] === undefined) { + headers[HTTP2_HEADER_DATE] = utcDate(); + } + } // This is intentionally stricter than the HTTP/1 implementation, which // allows values between 100 and 999 (inclusive) in order to allow for @@ -2602,7 +2605,7 @@ class ServerHttp2Stream extends Http2Stream { state.flags |= STREAM_FLAGS_HAS_TRAILERS; } - headers = processHeaders(headers); + headers = processHeaders(headers, options); const headersList = mapToHeaders(headers, assertValidPseudoHeaderResponse); this[kSentHeaders] = headers; @@ -2668,7 +2671,7 @@ class ServerHttp2Stream extends Http2Stream { this[kUpdateTimer](); this.ownsFd = false; - headers = processHeaders(headers); + headers = processHeaders(headers, options); const statusCode = headers[HTTP2_HEADER_STATUS] |= 0; // Payload/DATA frames are not permitted in these cases if (statusCode === HTTP_STATUS_NO_CONTENT || @@ -2729,7 +2732,7 @@ class ServerHttp2Stream extends Http2Stream { this[kUpdateTimer](); this.ownsFd = true; - headers = processHeaders(headers); + headers = processHeaders(headers, options); const statusCode = headers[HTTP2_HEADER_STATUS] |= 0; // Payload/DATA frames are not permitted in these cases if (statusCode === HTTP_STATUS_NO_CONTENT || diff --git a/test/parallel/test-http2-compat-serverresponse-headers-send-date.js b/test/parallel/test-http2-compat-serverresponse-headers-send-date.js new file mode 100644 index 00000000000000..b22b1f7304038e --- /dev/null +++ b/test/parallel/test-http2-compat-serverresponse-headers-send-date.js @@ -0,0 +1,26 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) { common.skip('missing crypto'); } +const assert = require('assert'); +const http2 = require('http2'); + +const server = http2.createServer(common.mustCall((request, response) => { + response.sendDate = false; + response.writeHead(200); + response.end(); +})); + +server.listen(0, common.mustCall(() => { + const session = http2.connect(`http://localhost:${server.address().port}`); + const req = session.request(); + + req.on('response', common.mustCall((headers, flags) => { + assert.strictEqual('Date' in headers, false); + assert.strictEqual('date' in headers, false); + })); + + req.on('end', common.mustCall(() => { + session.close(); + server.close(); + })); +})); diff --git a/test/parallel/test-http2-compat-serverresponse-headers.js b/test/parallel/test-http2-compat-serverresponse-headers.js index 96875e1bce3400..19720b1e41f2bd 100644 --- a/test/parallel/test-http2-compat-serverresponse-headers.js +++ b/test/parallel/test-http2-compat-serverresponse-headers.js @@ -114,6 +114,11 @@ server.listen(0, common.mustCall(function() { 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);