11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci mustCall, 51cb0ef41Sopenharmony_ci mustNotCall, 61cb0ef41Sopenharmony_ci hasCrypto, 71cb0ef41Sopenharmony_ci platformTimeout, 81cb0ef41Sopenharmony_ci skip 91cb0ef41Sopenharmony_ci} = require('../common'); 101cb0ef41Sopenharmony_ciif (!hasCrypto) 111cb0ef41Sopenharmony_ci skip('missing crypto'); 121cb0ef41Sopenharmony_ciconst { strictEqual } = require('assert'); 131cb0ef41Sopenharmony_ciconst { 141cb0ef41Sopenharmony_ci createServer, 151cb0ef41Sopenharmony_ci connect, 161cb0ef41Sopenharmony_ci constants: { 171cb0ef41Sopenharmony_ci HTTP2_HEADER_STATUS, 181cb0ef41Sopenharmony_ci HTTP_STATUS_OK 191cb0ef41Sopenharmony_ci } 201cb0ef41Sopenharmony_ci} = require('http2'); 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci{ 231cb0ef41Sopenharmony_ci // Http2ServerResponse.end accepts chunk, encoding, cb as args 241cb0ef41Sopenharmony_ci // It may be invoked repeatedly without throwing errors 251cb0ef41Sopenharmony_ci // but callback will only be called once 261cb0ef41Sopenharmony_ci const server = createServer(mustCall((request, response) => { 271cb0ef41Sopenharmony_ci response.end('end', 'utf8', mustCall(() => { 281cb0ef41Sopenharmony_ci response.end(mustCall()); 291cb0ef41Sopenharmony_ci process.nextTick(() => { 301cb0ef41Sopenharmony_ci response.end(mustCall()); 311cb0ef41Sopenharmony_ci server.close(); 321cb0ef41Sopenharmony_ci }); 331cb0ef41Sopenharmony_ci })); 341cb0ef41Sopenharmony_ci response.on('finish', mustCall(() => { 351cb0ef41Sopenharmony_ci response.end(mustCall()); 361cb0ef41Sopenharmony_ci })); 371cb0ef41Sopenharmony_ci response.end(mustCall()); 381cb0ef41Sopenharmony_ci })); 391cb0ef41Sopenharmony_ci server.listen(0, mustCall(() => { 401cb0ef41Sopenharmony_ci let data = ''; 411cb0ef41Sopenharmony_ci const { port } = server.address(); 421cb0ef41Sopenharmony_ci const url = `http://localhost:${port}`; 431cb0ef41Sopenharmony_ci const client = connect(url, mustCall(() => { 441cb0ef41Sopenharmony_ci const headers = { 451cb0ef41Sopenharmony_ci ':path': '/', 461cb0ef41Sopenharmony_ci ':method': 'GET', 471cb0ef41Sopenharmony_ci ':scheme': 'http', 481cb0ef41Sopenharmony_ci ':authority': `localhost:${port}` 491cb0ef41Sopenharmony_ci }; 501cb0ef41Sopenharmony_ci const request = client.request(headers); 511cb0ef41Sopenharmony_ci request.setEncoding('utf8'); 521cb0ef41Sopenharmony_ci request.on('data', (chunk) => (data += chunk)); 531cb0ef41Sopenharmony_ci request.on('end', mustCall(() => { 541cb0ef41Sopenharmony_ci strictEqual(data, 'end'); 551cb0ef41Sopenharmony_ci client.close(); 561cb0ef41Sopenharmony_ci })); 571cb0ef41Sopenharmony_ci request.end(); 581cb0ef41Sopenharmony_ci request.resume(); 591cb0ef41Sopenharmony_ci })); 601cb0ef41Sopenharmony_ci })); 611cb0ef41Sopenharmony_ci} 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci{ 641cb0ef41Sopenharmony_ci // Http2ServerResponse.end should return self after end 651cb0ef41Sopenharmony_ci const server = createServer(mustCall((request, response) => { 661cb0ef41Sopenharmony_ci strictEqual(response, response.end()); 671cb0ef41Sopenharmony_ci strictEqual(response, response.end()); 681cb0ef41Sopenharmony_ci server.close(); 691cb0ef41Sopenharmony_ci })); 701cb0ef41Sopenharmony_ci server.listen(0, mustCall(() => { 711cb0ef41Sopenharmony_ci const { port } = server.address(); 721cb0ef41Sopenharmony_ci const url = `http://localhost:${port}`; 731cb0ef41Sopenharmony_ci const client = connect(url, mustCall(() => { 741cb0ef41Sopenharmony_ci const headers = { 751cb0ef41Sopenharmony_ci ':path': '/', 761cb0ef41Sopenharmony_ci ':method': 'GET', 771cb0ef41Sopenharmony_ci ':scheme': 'http', 781cb0ef41Sopenharmony_ci ':authority': `localhost:${port}` 791cb0ef41Sopenharmony_ci }; 801cb0ef41Sopenharmony_ci const request = client.request(headers); 811cb0ef41Sopenharmony_ci request.setEncoding('utf8'); 821cb0ef41Sopenharmony_ci request.on('end', mustCall(() => { 831cb0ef41Sopenharmony_ci client.close(); 841cb0ef41Sopenharmony_ci })); 851cb0ef41Sopenharmony_ci request.end(); 861cb0ef41Sopenharmony_ci request.resume(); 871cb0ef41Sopenharmony_ci })); 881cb0ef41Sopenharmony_ci })); 891cb0ef41Sopenharmony_ci} 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci{ 921cb0ef41Sopenharmony_ci // Http2ServerResponse.end can omit encoding arg, sets it to utf-8 931cb0ef41Sopenharmony_ci const server = createServer(mustCall((request, response) => { 941cb0ef41Sopenharmony_ci response.end('test\uD83D\uDE00', mustCall(() => { 951cb0ef41Sopenharmony_ci server.close(); 961cb0ef41Sopenharmony_ci })); 971cb0ef41Sopenharmony_ci })); 981cb0ef41Sopenharmony_ci server.listen(0, mustCall(() => { 991cb0ef41Sopenharmony_ci let data = ''; 1001cb0ef41Sopenharmony_ci const { port } = server.address(); 1011cb0ef41Sopenharmony_ci const url = `http://localhost:${port}`; 1021cb0ef41Sopenharmony_ci const client = connect(url, mustCall(() => { 1031cb0ef41Sopenharmony_ci const headers = { 1041cb0ef41Sopenharmony_ci ':path': '/', 1051cb0ef41Sopenharmony_ci ':method': 'GET', 1061cb0ef41Sopenharmony_ci ':scheme': 'http', 1071cb0ef41Sopenharmony_ci ':authority': `localhost:${port}` 1081cb0ef41Sopenharmony_ci }; 1091cb0ef41Sopenharmony_ci const request = client.request(headers); 1101cb0ef41Sopenharmony_ci request.setEncoding('utf8'); 1111cb0ef41Sopenharmony_ci request.on('data', (chunk) => (data += chunk)); 1121cb0ef41Sopenharmony_ci request.on('end', mustCall(() => { 1131cb0ef41Sopenharmony_ci strictEqual(data, 'test\uD83D\uDE00'); 1141cb0ef41Sopenharmony_ci client.close(); 1151cb0ef41Sopenharmony_ci })); 1161cb0ef41Sopenharmony_ci request.end(); 1171cb0ef41Sopenharmony_ci request.resume(); 1181cb0ef41Sopenharmony_ci })); 1191cb0ef41Sopenharmony_ci })); 1201cb0ef41Sopenharmony_ci} 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci{ 1231cb0ef41Sopenharmony_ci // Http2ServerResponse.end can omit chunk & encoding args 1241cb0ef41Sopenharmony_ci const server = createServer(mustCall((request, response) => { 1251cb0ef41Sopenharmony_ci response.end(mustCall(() => { 1261cb0ef41Sopenharmony_ci server.close(); 1271cb0ef41Sopenharmony_ci })); 1281cb0ef41Sopenharmony_ci })); 1291cb0ef41Sopenharmony_ci server.listen(0, mustCall(() => { 1301cb0ef41Sopenharmony_ci const { port } = server.address(); 1311cb0ef41Sopenharmony_ci const url = `http://localhost:${port}`; 1321cb0ef41Sopenharmony_ci const client = connect(url, mustCall(() => { 1331cb0ef41Sopenharmony_ci const headers = { 1341cb0ef41Sopenharmony_ci ':path': '/', 1351cb0ef41Sopenharmony_ci ':method': 'GET', 1361cb0ef41Sopenharmony_ci ':scheme': 'http', 1371cb0ef41Sopenharmony_ci ':authority': `localhost:${port}` 1381cb0ef41Sopenharmony_ci }; 1391cb0ef41Sopenharmony_ci const request = client.request(headers); 1401cb0ef41Sopenharmony_ci request.on('data', mustNotCall()); 1411cb0ef41Sopenharmony_ci request.on('end', mustCall(() => client.close())); 1421cb0ef41Sopenharmony_ci request.end(); 1431cb0ef41Sopenharmony_ci request.resume(); 1441cb0ef41Sopenharmony_ci })); 1451cb0ef41Sopenharmony_ci })); 1461cb0ef41Sopenharmony_ci} 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci{ 1491cb0ef41Sopenharmony_ci // Http2ServerResponse.end is necessary on HEAD requests in compat 1501cb0ef41Sopenharmony_ci // for http1 compatibility 1511cb0ef41Sopenharmony_ci const server = createServer(mustCall((request, response) => { 1521cb0ef41Sopenharmony_ci strictEqual(response.writableEnded, false); 1531cb0ef41Sopenharmony_ci strictEqual(response.finished, false); 1541cb0ef41Sopenharmony_ci response.writeHead(HTTP_STATUS_OK, { foo: 'bar' }); 1551cb0ef41Sopenharmony_ci strictEqual(response.finished, false); 1561cb0ef41Sopenharmony_ci response.end('data', mustCall()); 1571cb0ef41Sopenharmony_ci strictEqual(response.writableEnded, true); 1581cb0ef41Sopenharmony_ci strictEqual(response.finished, true); 1591cb0ef41Sopenharmony_ci })); 1601cb0ef41Sopenharmony_ci server.listen(0, mustCall(() => { 1611cb0ef41Sopenharmony_ci const { port } = server.address(); 1621cb0ef41Sopenharmony_ci const url = `http://localhost:${port}`; 1631cb0ef41Sopenharmony_ci const client = connect(url, mustCall(() => { 1641cb0ef41Sopenharmony_ci const headers = { 1651cb0ef41Sopenharmony_ci ':path': '/', 1661cb0ef41Sopenharmony_ci ':method': 'HEAD', 1671cb0ef41Sopenharmony_ci ':scheme': 'http', 1681cb0ef41Sopenharmony_ci ':authority': `localhost:${port}` 1691cb0ef41Sopenharmony_ci }; 1701cb0ef41Sopenharmony_ci const request = client.request(headers); 1711cb0ef41Sopenharmony_ci request.on('response', mustCall((headers, flags) => { 1721cb0ef41Sopenharmony_ci strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); 1731cb0ef41Sopenharmony_ci strictEqual(flags, 5); // The end of stream flag is set 1741cb0ef41Sopenharmony_ci strictEqual(headers.foo, 'bar'); 1751cb0ef41Sopenharmony_ci })); 1761cb0ef41Sopenharmony_ci request.on('data', mustNotCall()); 1771cb0ef41Sopenharmony_ci request.on('end', mustCall(() => { 1781cb0ef41Sopenharmony_ci client.close(); 1791cb0ef41Sopenharmony_ci server.close(); 1801cb0ef41Sopenharmony_ci })); 1811cb0ef41Sopenharmony_ci request.end(); 1821cb0ef41Sopenharmony_ci request.resume(); 1831cb0ef41Sopenharmony_ci })); 1841cb0ef41Sopenharmony_ci })); 1851cb0ef41Sopenharmony_ci} 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci{ 1881cb0ef41Sopenharmony_ci // .end should trigger 'end' event on request if user did not attempt 1891cb0ef41Sopenharmony_ci // to read from the request 1901cb0ef41Sopenharmony_ci const server = createServer(mustCall((request, response) => { 1911cb0ef41Sopenharmony_ci request.on('end', mustCall()); 1921cb0ef41Sopenharmony_ci response.end(); 1931cb0ef41Sopenharmony_ci })); 1941cb0ef41Sopenharmony_ci server.listen(0, mustCall(() => { 1951cb0ef41Sopenharmony_ci const { port } = server.address(); 1961cb0ef41Sopenharmony_ci const url = `http://localhost:${port}`; 1971cb0ef41Sopenharmony_ci const client = connect(url, mustCall(() => { 1981cb0ef41Sopenharmony_ci const headers = { 1991cb0ef41Sopenharmony_ci ':path': '/', 2001cb0ef41Sopenharmony_ci ':method': 'HEAD', 2011cb0ef41Sopenharmony_ci ':scheme': 'http', 2021cb0ef41Sopenharmony_ci ':authority': `localhost:${port}` 2031cb0ef41Sopenharmony_ci }; 2041cb0ef41Sopenharmony_ci const request = client.request(headers); 2051cb0ef41Sopenharmony_ci request.on('data', mustNotCall()); 2061cb0ef41Sopenharmony_ci request.on('end', mustCall(() => { 2071cb0ef41Sopenharmony_ci client.close(); 2081cb0ef41Sopenharmony_ci server.close(); 2091cb0ef41Sopenharmony_ci })); 2101cb0ef41Sopenharmony_ci request.end(); 2111cb0ef41Sopenharmony_ci request.resume(); 2121cb0ef41Sopenharmony_ci })); 2131cb0ef41Sopenharmony_ci })); 2141cb0ef41Sopenharmony_ci} 2151cb0ef41Sopenharmony_ci 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci{ 2181cb0ef41Sopenharmony_ci // Should be able to call .end with cb from stream 'close' 2191cb0ef41Sopenharmony_ci const server = createServer(mustCall((request, response) => { 2201cb0ef41Sopenharmony_ci response.writeHead(HTTP_STATUS_OK, { foo: 'bar' }); 2211cb0ef41Sopenharmony_ci response.stream.on('close', mustCall(() => { 2221cb0ef41Sopenharmony_ci response.end(mustCall()); 2231cb0ef41Sopenharmony_ci })); 2241cb0ef41Sopenharmony_ci })); 2251cb0ef41Sopenharmony_ci server.listen(0, mustCall(() => { 2261cb0ef41Sopenharmony_ci const { port } = server.address(); 2271cb0ef41Sopenharmony_ci const url = `http://localhost:${port}`; 2281cb0ef41Sopenharmony_ci const client = connect(url, mustCall(() => { 2291cb0ef41Sopenharmony_ci const headers = { 2301cb0ef41Sopenharmony_ci ':path': '/', 2311cb0ef41Sopenharmony_ci ':method': 'HEAD', 2321cb0ef41Sopenharmony_ci ':scheme': 'http', 2331cb0ef41Sopenharmony_ci ':authority': `localhost:${port}` 2341cb0ef41Sopenharmony_ci }; 2351cb0ef41Sopenharmony_ci const request = client.request(headers); 2361cb0ef41Sopenharmony_ci request.on('response', mustCall((headers, flags) => { 2371cb0ef41Sopenharmony_ci strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); 2381cb0ef41Sopenharmony_ci strictEqual(flags, 5); // The end of stream flag is set 2391cb0ef41Sopenharmony_ci strictEqual(headers.foo, 'bar'); 2401cb0ef41Sopenharmony_ci })); 2411cb0ef41Sopenharmony_ci request.on('data', mustNotCall()); 2421cb0ef41Sopenharmony_ci request.on('end', mustCall(() => { 2431cb0ef41Sopenharmony_ci client.close(); 2441cb0ef41Sopenharmony_ci server.close(); 2451cb0ef41Sopenharmony_ci })); 2461cb0ef41Sopenharmony_ci request.end(); 2471cb0ef41Sopenharmony_ci request.resume(); 2481cb0ef41Sopenharmony_ci })); 2491cb0ef41Sopenharmony_ci })); 2501cb0ef41Sopenharmony_ci} 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ci{ 2531cb0ef41Sopenharmony_ci // Should be able to respond to HEAD request after timeout 2541cb0ef41Sopenharmony_ci const server = createServer(mustCall((request, response) => { 2551cb0ef41Sopenharmony_ci setTimeout(mustCall(() => { 2561cb0ef41Sopenharmony_ci response.writeHead(HTTP_STATUS_OK, { foo: 'bar' }); 2571cb0ef41Sopenharmony_ci response.end('data', mustCall()); 2581cb0ef41Sopenharmony_ci }), platformTimeout(10)); 2591cb0ef41Sopenharmony_ci })); 2601cb0ef41Sopenharmony_ci server.listen(0, mustCall(() => { 2611cb0ef41Sopenharmony_ci const { port } = server.address(); 2621cb0ef41Sopenharmony_ci const url = `http://localhost:${port}`; 2631cb0ef41Sopenharmony_ci const client = connect(url, mustCall(() => { 2641cb0ef41Sopenharmony_ci const headers = { 2651cb0ef41Sopenharmony_ci ':path': '/', 2661cb0ef41Sopenharmony_ci ':method': 'HEAD', 2671cb0ef41Sopenharmony_ci ':scheme': 'http', 2681cb0ef41Sopenharmony_ci ':authority': `localhost:${port}` 2691cb0ef41Sopenharmony_ci }; 2701cb0ef41Sopenharmony_ci const request = client.request(headers); 2711cb0ef41Sopenharmony_ci request.on('response', mustCall((headers, flags) => { 2721cb0ef41Sopenharmony_ci strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); 2731cb0ef41Sopenharmony_ci strictEqual(flags, 5); // The end of stream flag is set 2741cb0ef41Sopenharmony_ci strictEqual(headers.foo, 'bar'); 2751cb0ef41Sopenharmony_ci })); 2761cb0ef41Sopenharmony_ci request.on('data', mustNotCall()); 2771cb0ef41Sopenharmony_ci request.on('end', mustCall(() => { 2781cb0ef41Sopenharmony_ci client.close(); 2791cb0ef41Sopenharmony_ci server.close(); 2801cb0ef41Sopenharmony_ci })); 2811cb0ef41Sopenharmony_ci request.end(); 2821cb0ef41Sopenharmony_ci request.resume(); 2831cb0ef41Sopenharmony_ci })); 2841cb0ef41Sopenharmony_ci })); 2851cb0ef41Sopenharmony_ci} 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci{ 2881cb0ef41Sopenharmony_ci // Finish should only trigger after 'end' is called 2891cb0ef41Sopenharmony_ci const server = createServer(mustCall((request, response) => { 2901cb0ef41Sopenharmony_ci let finished = false; 2911cb0ef41Sopenharmony_ci response.writeHead(HTTP_STATUS_OK, { foo: 'bar' }); 2921cb0ef41Sopenharmony_ci response.on('finish', mustCall(() => { 2931cb0ef41Sopenharmony_ci finished = false; 2941cb0ef41Sopenharmony_ci })); 2951cb0ef41Sopenharmony_ci response.end('data', mustCall(() => { 2961cb0ef41Sopenharmony_ci strictEqual(finished, false); 2971cb0ef41Sopenharmony_ci response.end('data', mustCall()); 2981cb0ef41Sopenharmony_ci })); 2991cb0ef41Sopenharmony_ci })); 3001cb0ef41Sopenharmony_ci server.listen(0, mustCall(() => { 3011cb0ef41Sopenharmony_ci const { port } = server.address(); 3021cb0ef41Sopenharmony_ci const url = `http://localhost:${port}`; 3031cb0ef41Sopenharmony_ci const client = connect(url, mustCall(() => { 3041cb0ef41Sopenharmony_ci const headers = { 3051cb0ef41Sopenharmony_ci ':path': '/', 3061cb0ef41Sopenharmony_ci ':method': 'HEAD', 3071cb0ef41Sopenharmony_ci ':scheme': 'http', 3081cb0ef41Sopenharmony_ci ':authority': `localhost:${port}` 3091cb0ef41Sopenharmony_ci }; 3101cb0ef41Sopenharmony_ci const request = client.request(headers); 3111cb0ef41Sopenharmony_ci request.on('response', mustCall((headers, flags) => { 3121cb0ef41Sopenharmony_ci strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); 3131cb0ef41Sopenharmony_ci strictEqual(flags, 5); // The end of stream flag is set 3141cb0ef41Sopenharmony_ci strictEqual(headers.foo, 'bar'); 3151cb0ef41Sopenharmony_ci })); 3161cb0ef41Sopenharmony_ci request.on('data', mustNotCall()); 3171cb0ef41Sopenharmony_ci request.on('end', mustCall(() => { 3181cb0ef41Sopenharmony_ci client.close(); 3191cb0ef41Sopenharmony_ci server.close(); 3201cb0ef41Sopenharmony_ci })); 3211cb0ef41Sopenharmony_ci request.end(); 3221cb0ef41Sopenharmony_ci request.resume(); 3231cb0ef41Sopenharmony_ci })); 3241cb0ef41Sopenharmony_ci })); 3251cb0ef41Sopenharmony_ci} 3261cb0ef41Sopenharmony_ci 3271cb0ef41Sopenharmony_ci{ 3281cb0ef41Sopenharmony_ci // Should be able to respond to HEAD with just .end 3291cb0ef41Sopenharmony_ci const server = createServer(mustCall((request, response) => { 3301cb0ef41Sopenharmony_ci response.end('data', mustCall()); 3311cb0ef41Sopenharmony_ci response.end(mustCall()); 3321cb0ef41Sopenharmony_ci })); 3331cb0ef41Sopenharmony_ci server.listen(0, mustCall(() => { 3341cb0ef41Sopenharmony_ci const { port } = server.address(); 3351cb0ef41Sopenharmony_ci const url = `http://localhost:${port}`; 3361cb0ef41Sopenharmony_ci const client = connect(url, mustCall(() => { 3371cb0ef41Sopenharmony_ci const headers = { 3381cb0ef41Sopenharmony_ci ':path': '/', 3391cb0ef41Sopenharmony_ci ':method': 'HEAD', 3401cb0ef41Sopenharmony_ci ':scheme': 'http', 3411cb0ef41Sopenharmony_ci ':authority': `localhost:${port}` 3421cb0ef41Sopenharmony_ci }; 3431cb0ef41Sopenharmony_ci const request = client.request(headers); 3441cb0ef41Sopenharmony_ci request.on('response', mustCall((headers, flags) => { 3451cb0ef41Sopenharmony_ci strictEqual(headers[HTTP2_HEADER_STATUS], HTTP_STATUS_OK); 3461cb0ef41Sopenharmony_ci strictEqual(flags, 5); // The end of stream flag is set 3471cb0ef41Sopenharmony_ci })); 3481cb0ef41Sopenharmony_ci request.on('data', mustNotCall()); 3491cb0ef41Sopenharmony_ci request.on('end', mustCall(() => { 3501cb0ef41Sopenharmony_ci client.close(); 3511cb0ef41Sopenharmony_ci server.close(); 3521cb0ef41Sopenharmony_ci })); 3531cb0ef41Sopenharmony_ci request.end(); 3541cb0ef41Sopenharmony_ci request.resume(); 3551cb0ef41Sopenharmony_ci })); 3561cb0ef41Sopenharmony_ci })); 3571cb0ef41Sopenharmony_ci} 358