diff options
author | Anatoli Papirovski <apapirovski@mac.com> | 2017-09-04 22:29:59 -0400 |
---|---|---|
committer | Myles Borins <mylesborins@google.com> | 2017-09-12 03:18:26 +0200 |
commit | 764213cc7bbb4b0d20824e729a0b9cf00ca2cb3d (patch) | |
tree | d7eb767f89c6bd0ee854c50090b424d9bfe97f34 /test/parallel | |
parent | ddbcc9e59d8abb8af8851b968f7a1ec981896bf7 (diff) | |
download | node-new-764213cc7bbb4b0d20824e729a0b9cf00ca2cb3d.tar.gz |
http2: add compat trailers, adjust multi-headers
Adds Http2ServerRequest trailers & rawTrailers functionality. Also fixes
behaviour of multi-headers to conform with the spec (all values but
set-cookie and cookie should be comma delimited, cookie should be
semi-colon delimited and only set-cookie should be an array). Adds
setter for statusMessage that warns, for backwards compatibility.
End readable side of the stream on trailers or bodyless requests
Refs: https://github.com/expressjs/express/pull/3390#discussion_r136718729
PR-URL: https://github.com/nodejs/node/pull/15193
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'test/parallel')
7 files changed, 221 insertions, 11 deletions
diff --git a/test/parallel/test-http2-compat-serverrequest-end.js b/test/parallel/test-http2-compat-serverrequest-end.js new file mode 100644 index 0000000000..a84f73883d --- /dev/null +++ b/test/parallel/test-http2-compat-serverrequest-end.js @@ -0,0 +1,40 @@ +// Flags: --expose-http2 +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const h2 = require('http2'); + +// Http2ServerRequest should always end readable stream +// even on GET requests with no body + +const server = h2.createServer(); +server.listen(0, common.mustCall(function() { + const port = server.address().port; + server.once('request', common.mustCall(function(request, response) { + request.on('data', () => {}); + request.on('end', common.mustCall(() => { + response.on('finish', common.mustCall(function() { + server.close(); + })); + response.end(); + })); + })); + + const url = `http://localhost:${port}`; + const client = h2.connect(url, common.mustCall(function() { + const headers = { + ':path': '/foobar', + ':method': 'GET', + ':scheme': 'http', + ':authority': `localhost:${port}` + }; + const request = client.request(headers); + request.resume(); + request.on('end', common.mustCall(function() { + client.destroy(); + })); + request.end(); + })); +})); diff --git a/test/parallel/test-http2-compat-serverrequest-trailers.js b/test/parallel/test-http2-compat-serverrequest-trailers.js new file mode 100644 index 0000000000..7fa649fe7f --- /dev/null +++ b/test/parallel/test-http2-compat-serverrequest-trailers.js @@ -0,0 +1,71 @@ +// Flags: --expose-http2 +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const h2 = require('http2'); + +// Http2ServerRequest should have getter for trailers & rawTrailers + +const expectedTrailers = { + 'x-foo': 'xOxOxOx, OxOxOxO, xOxOxOx, OxOxOxO', + 'x-foo-test': 'test, test' +}; + +const server = h2.createServer(); +server.listen(0, common.mustCall(function() { + const port = server.address().port; + server.once('request', common.mustCall(function(request, response) { + let data = ''; + request.setEncoding('utf8'); + request.on('data', common.mustCall((chunk) => data += chunk)); + request.on('end', common.mustCall(() => { + const trailers = request.trailers; + for (const [name, value] of Object.entries(expectedTrailers)) { + assert.strictEqual(trailers[name], value); + } + assert.deepStrictEqual([ + 'x-foo', + 'xOxOxOx', + 'x-foo', + 'OxOxOxO', + 'x-foo', + 'xOxOxOx', + 'x-foo', + 'OxOxOxO', + 'x-foo-test', + 'test, test' + ], request.rawTrailers); + assert.strictEqual(data, 'test\ntest'); + response.end(); + })); + })); + + const url = `http://localhost:${port}`; + const client = h2.connect(url, common.mustCall(function() { + const headers = { + ':path': '/foobar', + ':method': 'POST', + ':scheme': 'http', + ':authority': `localhost:${port}` + }; + const request = client.request(headers, { + getTrailers(trailers) { + trailers['x-fOo'] = 'xOxOxOx'; + trailers['x-foO'] = 'OxOxOxO'; + trailers['X-fOo'] = 'xOxOxOx'; + trailers['X-foO'] = 'OxOxOxO'; + trailers['x-foo-test'] = 'test, test'; + } + }); + request.resume(); + request.on('end', common.mustCall(function() { + server.close(); + client.destroy(); + })); + request.write('test\n'); + request.end('test'); + })); +})); diff --git a/test/parallel/test-http2-compat-serverresponse-statusmessage-property-set.js b/test/parallel/test-http2-compat-serverresponse-statusmessage-property-set.js new file mode 100644 index 0000000000..bec056d013 --- /dev/null +++ b/test/parallel/test-http2-compat-serverresponse-statusmessage-property-set.js @@ -0,0 +1,51 @@ +// Flags: --expose-http2 +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const h2 = require('http2'); + +// Http2ServerResponse.statusMessage should warn + +const unsupportedWarned = common.mustCall(1); +process.on('warning', ({ name, message }) => { + const expectedMessage = + 'Status message is not supported by HTTP/2 (RFC7540 8.1.2.4)'; + if (name === 'UnsupportedWarning' && message === expectedMessage) + unsupportedWarned(); +}); + +const server = h2.createServer(); +server.listen(0, common.mustCall(function() { + const port = server.address().port; + server.once('request', common.mustCall(function(request, response) { + response.on('finish', common.mustCall(function() { + response.statusMessage = 'test'; + response.statusMessage = 'test'; // only warn once + assert.strictEqual(response.statusMessage, ''); // no change + 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('response', common.mustCall(function(headers) { + assert.strictEqual(headers[':status'], 200); + }, 1)); + request.on('end', common.mustCall(function() { + client.destroy(); + })); + request.end(); + request.resume(); + })); +})); diff --git a/test/parallel/test-http2-compat-serverresponse-statusmessage-property.js b/test/parallel/test-http2-compat-serverresponse-statusmessage-property.js index 782c239f0f..3b3ef6bdc2 100644 --- a/test/parallel/test-http2-compat-serverresponse-statusmessage-property.js +++ b/test/parallel/test-http2-compat-serverresponse-statusmessage-property.js @@ -23,6 +23,7 @@ server.listen(0, common.mustCall(function() { server.once('request', common.mustCall(function(request, response) { response.on('finish', common.mustCall(function() { assert.strictEqual(response.statusMessage, ''); + assert.strictEqual(response.statusMessage, ''); // only warn once server.close(); })); response.end(); diff --git a/test/parallel/test-http2-cookies.js b/test/parallel/test-http2-cookies.js index 6e2ae0bdfd..3e20a5749d 100644 --- a/test/parallel/test-http2-cookies.js +++ b/test/parallel/test-http2-cookies.js @@ -19,11 +19,8 @@ server.on('stream', common.mustCall(onStream)); function onStream(stream, headers, flags) { - assert(Array.isArray(headers.abc)); - assert.strictEqual(headers.abc.length, 3); - assert.strictEqual(headers.abc[0], '1'); - assert.strictEqual(headers.abc[1], '2'); - assert.strictEqual(headers.abc[2], '3'); + assert.strictEqual(typeof headers.abc, 'string'); + assert.strictEqual(headers.abc, '1, 2, 3'); assert.strictEqual(typeof headers.cookie, 'string'); assert.strictEqual(headers.cookie, 'a=b; c=d; e=f'); diff --git a/test/parallel/test-http2-multiheaders-raw.js b/test/parallel/test-http2-multiheaders-raw.js new file mode 100644 index 0000000000..f9c7cc5f9b --- /dev/null +++ b/test/parallel/test-http2-multiheaders-raw.js @@ -0,0 +1,50 @@ +// Flags: --expose-http2 +'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(); + +const src = Object.create(null); +src['www-authenticate'] = 'foo'; +src['WWW-Authenticate'] = 'bar'; +src['WWW-AUTHENTICATE'] = 'baz'; +src['test'] = 'foo, bar, baz'; + +server.on('stream', common.mustCall((stream, headers, flags, rawHeaders) => { + const expected = [ + ':path', + '/', + ':scheme', + 'http', + ':authority', + `localhost:${server.address().port}`, + ':method', + 'GET', + 'www-authenticate', + 'foo', + 'www-authenticate', + 'bar', + 'www-authenticate', + 'baz', + 'test', + 'foo, bar, baz' + ]; + + assert.deepStrictEqual(expected, rawHeaders); + stream.respond(src); + stream.end(); +})); + +server.listen(0, common.mustCall(() => { + const client = http2.connect(`http://localhost:${server.address().port}`); + const req = client.request(src); + req.on('streamClosed', common.mustCall(() => { + server.close(); + client.destroy(); + })); +})); diff --git a/test/parallel/test-http2-multiheaders.js b/test/parallel/test-http2-multiheaders.js index 54a900b04e..bcdc9458b3 100644 --- a/test/parallel/test-http2-multiheaders.js +++ b/test/parallel/test-http2-multiheaders.js @@ -31,15 +31,15 @@ src['__Proto__'] = 'baz'; function checkHeaders(headers) { assert.deepStrictEqual(headers['accept'], - [ 'abc', 'def', 'ghijklmnop' ]); + 'abc, def, ghijklmnop'); assert.deepStrictEqual(headers['www-authenticate'], - [ 'foo', 'bar', 'baz' ]); + 'foo, bar, baz'); assert.deepStrictEqual(headers['proxy-authenticate'], - [ 'foo', 'bar', 'baz' ]); - assert.deepStrictEqual(headers['x-foo'], [ 'foo', 'bar', 'baz' ]); - assert.deepStrictEqual(headers['constructor'], [ 'foo', 'bar', 'baz' ]); + 'foo, bar, baz'); + assert.deepStrictEqual(headers['x-foo'], 'foo, bar, baz'); + assert.deepStrictEqual(headers['constructor'], 'foo, bar, baz'); // eslint-disable-next-line no-proto - assert.deepStrictEqual(headers['__proto__'], [ 'foo', 'bar', 'baz' ]); + assert.deepStrictEqual(headers['__proto__'], 'foo, bar, baz'); } server.on('stream', common.mustCall((stream, headers) => { |