diff options
author | Anatoli Papirovski <apapirovski@mac.com> | 2017-10-02 21:56:53 -0400 |
---|---|---|
committer | Matteo Collina <hello@matteocollina.com> | 2017-10-06 14:04:22 -0700 |
commit | 2da7d9b8207d9c35d199734da75fa2bb15f326b6 (patch) | |
tree | 9aa1ed51d29bc3d9241539e9ded4d0e4da951970 /test/parallel/test-http2-compat-serverresponse-end.js | |
parent | 4f339b54e9cd8a2cb69b41d87832ad8ca3a6b5e2 (diff) | |
download | android-node-v8-2da7d9b8207d9c35d199734da75fa2bb15f326b6.tar.gz android-node-v8-2da7d9b8207d9c35d199734da75fa2bb15f326b6.tar.bz2 android-node-v8-2da7d9b8207d9c35d199734da75fa2bb15f326b6.zip |
http2: near full http1 compatibility, add tests
Extensive re-work of http1 compatibility layer based on tests in
express, on-finished and finalhandler. Fix handling of HEAD
method to match http1. Adjust write, end, etc. to call writeHead
as in http1 and as expected by user-land modules. Add socket
proxy that instead uses the Http2Stream for the vast majority of
socket interactions. Add and change tests to closer represent
http1 behaviour.
Refs: https://github.com/nodejs/node/pull/15633
Refs: https://github.com/expressjs/express/tree/master/test
Refs: https://github.com/jshttp/on-finished/blob/master/test/test.js
Refs: https://github.com/pillarjs/finalhandler/blob/master/test/test.js
PR-URL: https://github.com/nodejs/node/pull/15702
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'test/parallel/test-http2-compat-serverresponse-end.js')
-rw-r--r-- | test/parallel/test-http2-compat-serverresponse-end.js | 191 |
1 files changed, 185 insertions, 6 deletions
diff --git a/test/parallel/test-http2-compat-serverresponse-end.js b/test/parallel/test-http2-compat-serverresponse-end.js index 76cb692938..fafb3ea76d 100644 --- a/test/parallel/test-http2-compat-serverresponse-end.js +++ b/test/parallel/test-http2-compat-serverresponse-end.js @@ -1,6 +1,12 @@ 'use strict'; -const { mustCall, mustNotCall, hasCrypto, skip } = require('../common'); +const { + mustCall, + mustNotCall, + hasCrypto, + platformTimeout, + skip +} = require('../common'); if (!hasCrypto) skip('missing crypto'); const { strictEqual } = require('assert'); @@ -18,15 +24,16 @@ const { // It may be invoked repeatedly without throwing errors // but callback will only be called once const server = createServer(mustCall((request, response) => { - strictEqual(response.closed, false); response.end('end', 'utf8', mustCall(() => { - strictEqual(response.closed, true); response.end(mustNotCall()); process.nextTick(() => { response.end(mustNotCall()); server.close(); }); })); + response.on('finish', mustCall(() => { + response.end(mustNotCall()); + })); response.end(mustNotCall()); })); server.listen(0, mustCall(() => { @@ -111,12 +118,77 @@ const { } { - // Http2ServerResponse.end is not necessary on HEAD requests since the stream - // is already closed. Headers, however, can still be sent to the client. + // Http2ServerResponse.end is necessary on HEAD requests in compat + // for http1 compatibility const server = createServer(mustCall((request, response) => { strictEqual(response.finished, true); response.writeHead(HTTP_STATUS_OK, { foo: 'bar' }); - response.end(mustNotCall()); + response.end('data', mustCall()); + })); + server.listen(0, mustCall(() => { + const { port } = server.address(); + const url = `http://localhost:${port}`; + const client = connect(url, mustCall(() => { + const headers = { + ':path': '/', + ':method': 'HEAD', + ':scheme': 'http', + ':authority': `localhost:${port}` + }; + const request = client.request(headers); + request.on('response', mustCall((headers, flags) => { + strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); + strictEqual(flags, 5); // the end of stream flag is set + strictEqual(headers.foo, 'bar'); + })); + request.on('data', mustNotCall()); + request.on('end', mustCall(() => { + client.destroy(); + server.close(); + })); + request.end(); + request.resume(); + })); + })); +} + +{ + // .end should trigger 'end' event on request if user did not attempt + // to read from the request + const server = createServer(mustCall((request, response) => { + request.on('end', mustCall()); + response.end(); + })); + server.listen(0, mustCall(() => { + const { port } = server.address(); + const url = `http://localhost:${port}`; + const client = connect(url, mustCall(() => { + const headers = { + ':path': '/', + ':method': 'HEAD', + ':scheme': 'http', + ':authority': `localhost:${port}` + }; + const request = client.request(headers); + request.on('data', mustNotCall()); + request.on('end', mustCall(() => { + client.destroy(); + server.close(); + })); + request.end(); + request.resume(); + })); + })); +} + + +{ + // Should be able to call .end with cb from stream 'streamClosed' + const server = createServer(mustCall((request, response) => { + response.writeHead(HTTP_STATUS_OK, { foo: 'bar' }); + response.stream.on('streamClosed', mustCall(() => { + response.end(mustCall()); + })); })); server.listen(0, mustCall(() => { const { port } = server.address(); @@ -144,3 +216,110 @@ const { })); })); } + +{ + // Should be able to respond to HEAD request after timeout + const server = createServer(mustCall((request, response) => { + setTimeout(mustCall(() => { + response.writeHead(HTTP_STATUS_OK, { foo: 'bar' }); + response.end('data', mustCall()); + }), platformTimeout(10)); + })); + server.listen(0, mustCall(() => { + const { port } = server.address(); + const url = `http://localhost:${port}`; + const client = connect(url, mustCall(() => { + const headers = { + ':path': '/', + ':method': 'HEAD', + ':scheme': 'http', + ':authority': `localhost:${port}` + }; + const request = client.request(headers); + request.on('response', mustCall((headers, flags) => { + strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); + strictEqual(flags, 5); // the end of stream flag is set + strictEqual(headers.foo, 'bar'); + })); + request.on('data', mustNotCall()); + request.on('end', mustCall(() => { + client.destroy(); + server.close(); + })); + request.end(); + request.resume(); + })); + })); +} + +{ + // finish should only trigger after 'end' is called + const server = createServer(mustCall((request, response) => { + let finished = false; + response.writeHead(HTTP_STATUS_OK, { foo: 'bar' }); + response.on('finish', mustCall(() => { + finished = false; + })); + response.end('data', mustCall(() => { + strictEqual(finished, false); + response.end('data', mustNotCall()); + })); + })); + server.listen(0, mustCall(() => { + const { port } = server.address(); + const url = `http://localhost:${port}`; + const client = connect(url, mustCall(() => { + const headers = { + ':path': '/', + ':method': 'HEAD', + ':scheme': 'http', + ':authority': `localhost:${port}` + }; + const request = client.request(headers); + request.on('response', mustCall((headers, flags) => { + strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); + strictEqual(flags, 5); // the end of stream flag is set + strictEqual(headers.foo, 'bar'); + })); + request.on('data', mustNotCall()); + request.on('end', mustCall(() => { + client.destroy(); + server.close(); + })); + request.end(); + request.resume(); + })); + })); +} + +{ + // Should be able to respond to HEAD with just .end + const server = createServer(mustCall((request, response) => { + response.end('data', mustCall()); + response.end(mustNotCall()); + })); + server.listen(0, mustCall(() => { + const { port } = server.address(); + const url = `http://localhost:${port}`; + const client = connect(url, mustCall(() => { + const headers = { + ':path': '/', + ':method': 'HEAD', + ':scheme': 'http', + ':authority': `localhost:${port}` + }; + const request = client.request(headers); + request.on('response', mustCall((headers, flags) => { + strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); + strictEqual(flags, 5); // the end of stream flag is set + })); + request.on('data', mustNotCall()); + request.on('end', mustCall(() => { + client.destroy(); + server.close(); + })); + request.end(); + request.resume(); + })); + })); +} |