| 'use strict'; |
| |
| const { |
| mustCall, |
| mustNotCall, |
| hasCrypto, |
| platformTimeout, |
| skip |
| } = require('../common'); |
| if (!hasCrypto) |
| skip('missing crypto'); |
| const assert = require('assert'); |
| const { |
| createServer, |
| connect, |
| constants: { |
| HTTP2_HEADER_STATUS, |
| HTTP_STATUS_OK |
| } |
| } = require('http2'); |
| |
| { |
| // Http2ServerResponse.end accepts chunk, encoding, cb as args |
| // It may be invoked repeatedly without throwing errors |
| // but callback will only be called once |
| const server = createServer(mustCall((request, response) => { |
| response.end('end', 'utf8', mustCall(() => { |
| response.end(mustCall()); |
| process.nextTick(() => { |
| response.end(mustCall()); |
| server.close(); |
| }); |
| })); |
| response.on('finish', mustCall(() => { |
| response.end(mustCall()); |
| })); |
| response.end(mustCall()); |
| })); |
| server.listen(0, mustCall(() => { |
| let data = ''; |
| const { port } = server.address(); |
| const url = `http://localhost:${port}`; |
| const client = connect(url, mustCall(() => { |
| const headers = { |
| ':path': '/', |
| ':method': 'GET', |
| ':scheme': 'http', |
| ':authority': `localhost:${port}` |
| }; |
| const request = client.request(headers); |
| request.setEncoding('utf8'); |
| request.on('data', (chunk) => (data += chunk)); |
| request.on('end', mustCall(() => { |
| assert.strictEqual(data, 'end'); |
| client.close(); |
| })); |
| request.end(); |
| request.resume(); |
| })); |
| })); |
| } |
| |
| { |
| // Http2ServerResponse.end should return self after end |
| const server = createServer(mustCall((request, response) => { |
| assert.strictEqual(response, response.end()); |
| assert.strictEqual(response, response.end()); |
| server.close(); |
| })); |
| server.listen(0, mustCall(() => { |
| const { port } = server.address(); |
| const url = `http://localhost:${port}`; |
| const client = connect(url, mustCall(() => { |
| const headers = { |
| ':path': '/', |
| ':method': 'GET', |
| ':scheme': 'http', |
| ':authority': `localhost:${port}` |
| }; |
| const request = client.request(headers); |
| request.setEncoding('utf8'); |
| request.on('end', mustCall(() => { |
| client.close(); |
| })); |
| request.end(); |
| request.resume(); |
| })); |
| })); |
| } |
| |
| { |
| // Http2ServerResponse.end can omit encoding arg, sets it to utf-8 |
| const server = createServer(mustCall((request, response) => { |
| response.end('test\uD83D\uDE00', mustCall(() => { |
| server.close(); |
| })); |
| })); |
| server.listen(0, mustCall(() => { |
| let data = ''; |
| const { port } = server.address(); |
| const url = `http://localhost:${port}`; |
| const client = connect(url, mustCall(() => { |
| const headers = { |
| ':path': '/', |
| ':method': 'GET', |
| ':scheme': 'http', |
| ':authority': `localhost:${port}` |
| }; |
| const request = client.request(headers); |
| request.setEncoding('utf8'); |
| request.on('data', (chunk) => (data += chunk)); |
| request.on('end', mustCall(() => { |
| assert.strictEqual(data, 'test\uD83D\uDE00'); |
| client.close(); |
| })); |
| request.end(); |
| request.resume(); |
| })); |
| })); |
| } |
| |
| { |
| // Http2ServerResponse.end can omit chunk & encoding args |
| const server = createServer(mustCall((request, response) => { |
| response.end(mustCall(() => { |
| server.close(); |
| })); |
| })); |
| server.listen(0, mustCall(() => { |
| const { port } = server.address(); |
| const url = `http://localhost:${port}`; |
| const client = connect(url, mustCall(() => { |
| const headers = { |
| ':path': '/', |
| ':method': 'GET', |
| ':scheme': 'http', |
| ':authority': `localhost:${port}` |
| }; |
| const request = client.request(headers); |
| request.on('data', mustNotCall()); |
| request.on('end', mustCall(() => client.close())); |
| request.end(); |
| request.resume(); |
| })); |
| })); |
| } |
| |
| { |
| // Http2ServerResponse.end is necessary on HEAD requests in compat |
| // for http1 compatibility |
| const server = createServer(mustCall((request, response) => { |
| assert.strictEqual(response.writableEnded, false); |
| assert.strictEqual(response.finished, false); |
| response.writeHead(HTTP_STATUS_OK, { foo: 'bar' }); |
| assert.strictEqual(response.finished, false); |
| response.end('data', mustCall()); |
| assert.strictEqual(response.writableEnded, true); |
| assert.strictEqual(response.finished, true); |
| })); |
| 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) => { |
| assert.strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); |
| assert.strictEqual(flags, 5); // The end of stream flag is set |
| assert.strictEqual(headers.foo, 'bar'); |
| })); |
| request.on('data', mustNotCall()); |
| request.on('end', mustCall(() => { |
| client.close(); |
| 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.close(); |
| server.close(); |
| })); |
| request.end(); |
| request.resume(); |
| })); |
| })); |
| } |
| |
| |
| { |
| // Should be able to call .end with cb from stream 'close' |
| const server = createServer(mustCall((request, response) => { |
| response.writeHead(HTTP_STATUS_OK, { foo: 'bar' }); |
| response.stream.on('close', mustCall(() => { |
| response.end(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) => { |
| assert.strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); |
| assert.strictEqual(flags, 5); // The end of stream flag is set |
| assert.strictEqual(headers.foo, 'bar'); |
| })); |
| request.on('data', mustNotCall()); |
| request.on('end', mustCall(() => { |
| client.close(); |
| server.close(); |
| })); |
| request.end(); |
| request.resume(); |
| })); |
| })); |
| } |
| |
| { |
| // 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) => { |
| assert.strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); |
| assert.strictEqual(flags, 5); // The end of stream flag is set |
| assert.strictEqual(headers.foo, 'bar'); |
| })); |
| request.on('data', mustNotCall()); |
| request.on('end', mustCall(() => { |
| client.close(); |
| 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(() => { |
| assert.strictEqual(finished, false); |
| 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) => { |
| assert.strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); |
| assert.strictEqual(flags, 5); // The end of stream flag is set |
| assert.strictEqual(headers.foo, 'bar'); |
| })); |
| request.on('data', mustNotCall()); |
| request.on('end', mustCall(() => { |
| client.close(); |
| 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(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) => { |
| assert.strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); |
| assert.strictEqual(flags, 5); // The end of stream flag is set |
| })); |
| request.on('data', mustNotCall()); |
| request.on('end', mustCall(() => { |
| client.close(); |
| server.close(); |
| })); |
| request.end(); |
| request.resume(); |
| })); |
| })); |
| } |