11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors. 21cb0ef41Sopenharmony_ci// 31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the 51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including 61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish, 71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit 81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the 91cb0ef41Sopenharmony_ci// following conditions: 101cb0ef41Sopenharmony_ci// 111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included 121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software. 131cb0ef41Sopenharmony_ci// 141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE. 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci'use strict'; 231cb0ef41Sopenharmony_ciconst { mustCall, mustNotCall } = require('../common'); 241cb0ef41Sopenharmony_ciconst assert = require('assert'); 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ciconst { methods, HTTPParser } = require('_http_common'); 271cb0ef41Sopenharmony_ciconst { REQUEST, RESPONSE } = HTTPParser; 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ciconst kOnHeaders = HTTPParser.kOnHeaders | 0; 301cb0ef41Sopenharmony_ciconst kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0; 311cb0ef41Sopenharmony_ciconst kOnBody = HTTPParser.kOnBody | 0; 321cb0ef41Sopenharmony_ciconst kOnMessageComplete = HTTPParser.kOnMessageComplete | 0; 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci// The purpose of this test is not to check HTTP compliance but to test the 351cb0ef41Sopenharmony_ci// binding. Tests for pathological http messages should be submitted 361cb0ef41Sopenharmony_ci// upstream to https://github.com/joyent/http-parser for inclusion into 371cb0ef41Sopenharmony_ci// deps/http-parser/test.c 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_cifunction newParser(type) { 411cb0ef41Sopenharmony_ci const parser = new HTTPParser(); 421cb0ef41Sopenharmony_ci parser.initialize(type, {}); 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci parser.headers = []; 451cb0ef41Sopenharmony_ci parser.url = ''; 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci parser[kOnHeaders] = function(headers, url) { 481cb0ef41Sopenharmony_ci parser.headers = parser.headers.concat(headers); 491cb0ef41Sopenharmony_ci parser.url += url; 501cb0ef41Sopenharmony_ci }; 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = function() { 531cb0ef41Sopenharmony_ci }; 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci parser[kOnBody] = mustNotCall('kOnBody should not be called'); 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci parser[kOnMessageComplete] = function() { 581cb0ef41Sopenharmony_ci }; 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci return parser; 611cb0ef41Sopenharmony_ci} 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_cifunction expectBody(expected) { 651cb0ef41Sopenharmony_ci return mustCall(function(buf) { 661cb0ef41Sopenharmony_ci const body = String(buf); 671cb0ef41Sopenharmony_ci assert.strictEqual(body, expected); 681cb0ef41Sopenharmony_ci }); 691cb0ef41Sopenharmony_ci} 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci// 731cb0ef41Sopenharmony_ci// Simple request test. 741cb0ef41Sopenharmony_ci// 751cb0ef41Sopenharmony_ci{ 761cb0ef41Sopenharmony_ci const request = Buffer.from('GET /hello HTTP/1.1\r\n\r\n'); 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ci const onHeadersComplete = (versionMajor, versionMinor, headers, 791cb0ef41Sopenharmony_ci method, url) => { 801cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 811cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 1); 821cb0ef41Sopenharmony_ci assert.strictEqual(method, methods.indexOf('GET')); 831cb0ef41Sopenharmony_ci assert.strictEqual(url || parser.url, '/hello'); 841cb0ef41Sopenharmony_ci }; 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci const parser = newParser(REQUEST); 871cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = mustCall(onHeadersComplete); 881cb0ef41Sopenharmony_ci parser.execute(request, 0, request.length); 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci // 911cb0ef41Sopenharmony_ci // Check that if we throw an error in the callbacks that error will be 921cb0ef41Sopenharmony_ci // thrown from parser.execute() 931cb0ef41Sopenharmony_ci // 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = function() { 961cb0ef41Sopenharmony_ci throw new Error('hello world'); 971cb0ef41Sopenharmony_ci }; 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci parser.initialize(REQUEST, {}); 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci assert.throws( 1021cb0ef41Sopenharmony_ci () => { parser.execute(request, 0, request.length); }, 1031cb0ef41Sopenharmony_ci { name: 'Error', message: 'hello world' } 1041cb0ef41Sopenharmony_ci ); 1051cb0ef41Sopenharmony_ci} 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci// 1091cb0ef41Sopenharmony_ci// Simple response test. 1101cb0ef41Sopenharmony_ci// 1111cb0ef41Sopenharmony_ci{ 1121cb0ef41Sopenharmony_ci const request = Buffer.from( 1131cb0ef41Sopenharmony_ci 'HTTP/1.1 200 OK\r\n' + 1141cb0ef41Sopenharmony_ci 'Content-Type: text/plain\r\n' + 1151cb0ef41Sopenharmony_ci 'Content-Length: 4\r\n' + 1161cb0ef41Sopenharmony_ci '\r\n' + 1171cb0ef41Sopenharmony_ci 'pong' 1181cb0ef41Sopenharmony_ci ); 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci const onHeadersComplete = (versionMajor, versionMinor, headers, 1211cb0ef41Sopenharmony_ci method, url, statusCode, statusMessage) => { 1221cb0ef41Sopenharmony_ci assert.strictEqual(method, undefined); 1231cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 1241cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 1); 1251cb0ef41Sopenharmony_ci assert.strictEqual(statusCode, 200); 1261cb0ef41Sopenharmony_ci assert.strictEqual(statusMessage, 'OK'); 1271cb0ef41Sopenharmony_ci }; 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci const onBody = (buf) => { 1301cb0ef41Sopenharmony_ci const body = String(buf); 1311cb0ef41Sopenharmony_ci assert.strictEqual(body, 'pong'); 1321cb0ef41Sopenharmony_ci }; 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci const parser = newParser(RESPONSE); 1351cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = mustCall(onHeadersComplete); 1361cb0ef41Sopenharmony_ci parser[kOnBody] = mustCall(onBody); 1371cb0ef41Sopenharmony_ci parser.execute(request, 0, request.length); 1381cb0ef41Sopenharmony_ci} 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci// 1421cb0ef41Sopenharmony_ci// Response with no headers. 1431cb0ef41Sopenharmony_ci// 1441cb0ef41Sopenharmony_ci{ 1451cb0ef41Sopenharmony_ci const request = Buffer.from( 1461cb0ef41Sopenharmony_ci 'HTTP/1.0 200 Connection established\r\n\r\n'); 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci const onHeadersComplete = (versionMajor, versionMinor, headers, 1491cb0ef41Sopenharmony_ci method, url, statusCode, statusMessage) => { 1501cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 1511cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 0); 1521cb0ef41Sopenharmony_ci assert.strictEqual(method, undefined); 1531cb0ef41Sopenharmony_ci assert.strictEqual(statusCode, 200); 1541cb0ef41Sopenharmony_ci assert.strictEqual(statusMessage, 'Connection established'); 1551cb0ef41Sopenharmony_ci assert.deepStrictEqual(headers || parser.headers, []); 1561cb0ef41Sopenharmony_ci }; 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci const parser = newParser(RESPONSE); 1591cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = mustCall(onHeadersComplete); 1601cb0ef41Sopenharmony_ci parser.execute(request, 0, request.length); 1611cb0ef41Sopenharmony_ci} 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ci// 1651cb0ef41Sopenharmony_ci// Trailing headers. 1661cb0ef41Sopenharmony_ci// 1671cb0ef41Sopenharmony_ci{ 1681cb0ef41Sopenharmony_ci const request = Buffer.from( 1691cb0ef41Sopenharmony_ci 'POST /it HTTP/1.1\r\n' + 1701cb0ef41Sopenharmony_ci 'Transfer-Encoding: chunked\r\n' + 1711cb0ef41Sopenharmony_ci '\r\n' + 1721cb0ef41Sopenharmony_ci '4\r\n' + 1731cb0ef41Sopenharmony_ci 'ping\r\n' + 1741cb0ef41Sopenharmony_ci '0\r\n' + 1751cb0ef41Sopenharmony_ci 'Vary: *\r\n' + 1761cb0ef41Sopenharmony_ci 'Content-Type: text/plain\r\n' + 1771cb0ef41Sopenharmony_ci '\r\n' 1781cb0ef41Sopenharmony_ci ); 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci let seen_body = false; 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci const onHeaders = (headers) => { 1831cb0ef41Sopenharmony_ci assert.ok(seen_body); // Trailers should come after the body 1841cb0ef41Sopenharmony_ci assert.deepStrictEqual(headers, 1851cb0ef41Sopenharmony_ci ['Vary', '*', 'Content-Type', 'text/plain']); 1861cb0ef41Sopenharmony_ci }; 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci const onHeadersComplete = (versionMajor, versionMinor, headers, 1891cb0ef41Sopenharmony_ci method, url) => { 1901cb0ef41Sopenharmony_ci assert.strictEqual(method, methods.indexOf('POST')); 1911cb0ef41Sopenharmony_ci assert.strictEqual(url || parser.url, '/it'); 1921cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 1931cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 1); 1941cb0ef41Sopenharmony_ci // Expect to see trailing headers now 1951cb0ef41Sopenharmony_ci parser[kOnHeaders] = mustCall(onHeaders); 1961cb0ef41Sopenharmony_ci }; 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ci const onBody = (buf) => { 1991cb0ef41Sopenharmony_ci const body = String(buf); 2001cb0ef41Sopenharmony_ci assert.strictEqual(body, 'ping'); 2011cb0ef41Sopenharmony_ci seen_body = true; 2021cb0ef41Sopenharmony_ci }; 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci const parser = newParser(REQUEST); 2051cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = mustCall(onHeadersComplete); 2061cb0ef41Sopenharmony_ci parser[kOnBody] = mustCall(onBody); 2071cb0ef41Sopenharmony_ci parser.execute(request, 0, request.length); 2081cb0ef41Sopenharmony_ci} 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci// 2121cb0ef41Sopenharmony_ci// Test header ordering. 2131cb0ef41Sopenharmony_ci// 2141cb0ef41Sopenharmony_ci{ 2151cb0ef41Sopenharmony_ci const request = Buffer.from( 2161cb0ef41Sopenharmony_ci 'GET / HTTP/1.0\r\n' + 2171cb0ef41Sopenharmony_ci 'X-Filler: 1337\r\n' + 2181cb0ef41Sopenharmony_ci 'X-Filler: 42\r\n' + 2191cb0ef41Sopenharmony_ci 'X-Filler2: 42\r\n' + 2201cb0ef41Sopenharmony_ci '\r\n' 2211cb0ef41Sopenharmony_ci ); 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_ci const onHeadersComplete = (versionMajor, versionMinor, headers, 2241cb0ef41Sopenharmony_ci method) => { 2251cb0ef41Sopenharmony_ci assert.strictEqual(method, methods.indexOf('GET')); 2261cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 2271cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 0); 2281cb0ef41Sopenharmony_ci assert.deepStrictEqual( 2291cb0ef41Sopenharmony_ci headers || parser.headers, 2301cb0ef41Sopenharmony_ci ['X-Filler', '1337', 'X-Filler', '42', 'X-Filler2', '42']); 2311cb0ef41Sopenharmony_ci }; 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci const parser = newParser(REQUEST); 2341cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = mustCall(onHeadersComplete); 2351cb0ef41Sopenharmony_ci parser.execute(request, 0, request.length); 2361cb0ef41Sopenharmony_ci} 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci// 2401cb0ef41Sopenharmony_ci// Test large number of headers 2411cb0ef41Sopenharmony_ci// 2421cb0ef41Sopenharmony_ci{ 2431cb0ef41Sopenharmony_ci // 256 X-Filler headers 2441cb0ef41Sopenharmony_ci const lots_of_headers = 'X-Filler: 42\r\n'.repeat(256); 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ci const request = Buffer.from( 2471cb0ef41Sopenharmony_ci 'GET /foo/bar/baz?quux=42#1337 HTTP/1.0\r\n' + 2481cb0ef41Sopenharmony_ci lots_of_headers + 2491cb0ef41Sopenharmony_ci '\r\n' 2501cb0ef41Sopenharmony_ci ); 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ci const onHeadersComplete = (versionMajor, versionMinor, headers, 2531cb0ef41Sopenharmony_ci method, url) => { 2541cb0ef41Sopenharmony_ci assert.strictEqual(method, methods.indexOf('GET')); 2551cb0ef41Sopenharmony_ci assert.strictEqual(url || parser.url, '/foo/bar/baz?quux=42#1337'); 2561cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 2571cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 0); 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci headers = headers || parser.headers; 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_ci assert.strictEqual(headers.length, 2 * 256); // 256 key/value pairs 2621cb0ef41Sopenharmony_ci for (let i = 0; i < headers.length; i += 2) { 2631cb0ef41Sopenharmony_ci assert.strictEqual(headers[i], 'X-Filler'); 2641cb0ef41Sopenharmony_ci assert.strictEqual(headers[i + 1], '42'); 2651cb0ef41Sopenharmony_ci } 2661cb0ef41Sopenharmony_ci }; 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_ci const parser = newParser(REQUEST); 2691cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = mustCall(onHeadersComplete); 2701cb0ef41Sopenharmony_ci parser.execute(request, 0, request.length); 2711cb0ef41Sopenharmony_ci} 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_ci// 2751cb0ef41Sopenharmony_ci// Test request body 2761cb0ef41Sopenharmony_ci// 2771cb0ef41Sopenharmony_ci{ 2781cb0ef41Sopenharmony_ci const request = Buffer.from( 2791cb0ef41Sopenharmony_ci 'POST /it HTTP/1.1\r\n' + 2801cb0ef41Sopenharmony_ci 'Content-Type: application/x-www-form-urlencoded\r\n' + 2811cb0ef41Sopenharmony_ci 'Content-Length: 15\r\n' + 2821cb0ef41Sopenharmony_ci '\r\n' + 2831cb0ef41Sopenharmony_ci 'foo=42&bar=1337' 2841cb0ef41Sopenharmony_ci ); 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ci const onHeadersComplete = (versionMajor, versionMinor, headers, 2871cb0ef41Sopenharmony_ci method, url) => { 2881cb0ef41Sopenharmony_ci assert.strictEqual(method, methods.indexOf('POST')); 2891cb0ef41Sopenharmony_ci assert.strictEqual(url || parser.url, '/it'); 2901cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 2911cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 1); 2921cb0ef41Sopenharmony_ci }; 2931cb0ef41Sopenharmony_ci 2941cb0ef41Sopenharmony_ci const onBody = (buf) => { 2951cb0ef41Sopenharmony_ci const body = String(buf); 2961cb0ef41Sopenharmony_ci assert.strictEqual(body, 'foo=42&bar=1337'); 2971cb0ef41Sopenharmony_ci }; 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci const parser = newParser(REQUEST); 3001cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = mustCall(onHeadersComplete); 3011cb0ef41Sopenharmony_ci parser[kOnBody] = mustCall(onBody); 3021cb0ef41Sopenharmony_ci parser.execute(request, 0, request.length); 3031cb0ef41Sopenharmony_ci} 3041cb0ef41Sopenharmony_ci 3051cb0ef41Sopenharmony_ci 3061cb0ef41Sopenharmony_ci// 3071cb0ef41Sopenharmony_ci// Test chunked request body 3081cb0ef41Sopenharmony_ci// 3091cb0ef41Sopenharmony_ci{ 3101cb0ef41Sopenharmony_ci const request = Buffer.from( 3111cb0ef41Sopenharmony_ci 'POST /it HTTP/1.1\r\n' + 3121cb0ef41Sopenharmony_ci 'Content-Type: text/plain\r\n' + 3131cb0ef41Sopenharmony_ci 'Transfer-Encoding: chunked\r\n' + 3141cb0ef41Sopenharmony_ci '\r\n' + 3151cb0ef41Sopenharmony_ci '3\r\n' + 3161cb0ef41Sopenharmony_ci '123\r\n' + 3171cb0ef41Sopenharmony_ci '6\r\n' + 3181cb0ef41Sopenharmony_ci '123456\r\n' + 3191cb0ef41Sopenharmony_ci 'A\r\n' + 3201cb0ef41Sopenharmony_ci '1234567890\r\n' + 3211cb0ef41Sopenharmony_ci '0\r\n' 3221cb0ef41Sopenharmony_ci ); 3231cb0ef41Sopenharmony_ci 3241cb0ef41Sopenharmony_ci const onHeadersComplete = (versionMajor, versionMinor, headers, 3251cb0ef41Sopenharmony_ci method, url) => { 3261cb0ef41Sopenharmony_ci assert.strictEqual(method, methods.indexOf('POST')); 3271cb0ef41Sopenharmony_ci assert.strictEqual(url || parser.url, '/it'); 3281cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 3291cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 1); 3301cb0ef41Sopenharmony_ci }; 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci let body_part = 0; 3331cb0ef41Sopenharmony_ci const body_parts = ['123', '123456', '1234567890']; 3341cb0ef41Sopenharmony_ci 3351cb0ef41Sopenharmony_ci const onBody = (buf) => { 3361cb0ef41Sopenharmony_ci const body = String(buf); 3371cb0ef41Sopenharmony_ci assert.strictEqual(body, body_parts[body_part++]); 3381cb0ef41Sopenharmony_ci }; 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci const parser = newParser(REQUEST); 3411cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = mustCall(onHeadersComplete); 3421cb0ef41Sopenharmony_ci parser[kOnBody] = mustCall(onBody, body_parts.length); 3431cb0ef41Sopenharmony_ci parser.execute(request, 0, request.length); 3441cb0ef41Sopenharmony_ci} 3451cb0ef41Sopenharmony_ci 3461cb0ef41Sopenharmony_ci 3471cb0ef41Sopenharmony_ci// 3481cb0ef41Sopenharmony_ci// Test chunked request body spread over multiple buffers (packets) 3491cb0ef41Sopenharmony_ci// 3501cb0ef41Sopenharmony_ci{ 3511cb0ef41Sopenharmony_ci let request = Buffer.from( 3521cb0ef41Sopenharmony_ci 'POST /it HTTP/1.1\r\n' + 3531cb0ef41Sopenharmony_ci 'Content-Type: text/plain\r\n' + 3541cb0ef41Sopenharmony_ci 'Transfer-Encoding: chunked\r\n' + 3551cb0ef41Sopenharmony_ci '\r\n' + 3561cb0ef41Sopenharmony_ci '3\r\n' + 3571cb0ef41Sopenharmony_ci '123\r\n' + 3581cb0ef41Sopenharmony_ci '6\r\n' + 3591cb0ef41Sopenharmony_ci '123456\r\n' 3601cb0ef41Sopenharmony_ci ); 3611cb0ef41Sopenharmony_ci 3621cb0ef41Sopenharmony_ci const onHeadersComplete = (versionMajor, versionMinor, headers, 3631cb0ef41Sopenharmony_ci method, url) => { 3641cb0ef41Sopenharmony_ci assert.strictEqual(method, methods.indexOf('POST')); 3651cb0ef41Sopenharmony_ci assert.strictEqual(url || parser.url, '/it'); 3661cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 3671cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 1); 3681cb0ef41Sopenharmony_ci }; 3691cb0ef41Sopenharmony_ci 3701cb0ef41Sopenharmony_ci let body_part = 0; 3711cb0ef41Sopenharmony_ci const body_parts = 3721cb0ef41Sopenharmony_ci ['123', '123456', '123456789', '123456789ABC', '123456789ABCDEF']; 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ci const onBody = (buf) => { 3751cb0ef41Sopenharmony_ci const body = String(buf); 3761cb0ef41Sopenharmony_ci assert.strictEqual(body, body_parts[body_part++]); 3771cb0ef41Sopenharmony_ci }; 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_ci const parser = newParser(REQUEST); 3801cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = mustCall(onHeadersComplete); 3811cb0ef41Sopenharmony_ci parser[kOnBody] = mustCall(onBody, body_parts.length); 3821cb0ef41Sopenharmony_ci parser.execute(request, 0, request.length); 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_ci request = Buffer.from( 3851cb0ef41Sopenharmony_ci '9\r\n' + 3861cb0ef41Sopenharmony_ci '123456789\r\n' + 3871cb0ef41Sopenharmony_ci 'C\r\n' + 3881cb0ef41Sopenharmony_ci '123456789ABC\r\n' + 3891cb0ef41Sopenharmony_ci 'F\r\n' + 3901cb0ef41Sopenharmony_ci '123456789ABCDEF\r\n' + 3911cb0ef41Sopenharmony_ci '0\r\n' 3921cb0ef41Sopenharmony_ci ); 3931cb0ef41Sopenharmony_ci 3941cb0ef41Sopenharmony_ci parser.execute(request, 0, request.length); 3951cb0ef41Sopenharmony_ci} 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci 3981cb0ef41Sopenharmony_ci// 3991cb0ef41Sopenharmony_ci// Stress test. 4001cb0ef41Sopenharmony_ci// 4011cb0ef41Sopenharmony_ci{ 4021cb0ef41Sopenharmony_ci const request = Buffer.from( 4031cb0ef41Sopenharmony_ci 'POST /helpme HTTP/1.1\r\n' + 4041cb0ef41Sopenharmony_ci 'Content-Type: text/plain\r\n' + 4051cb0ef41Sopenharmony_ci 'Transfer-Encoding: chunked\r\n' + 4061cb0ef41Sopenharmony_ci '\r\n' + 4071cb0ef41Sopenharmony_ci '3\r\n' + 4081cb0ef41Sopenharmony_ci '123\r\n' + 4091cb0ef41Sopenharmony_ci '6\r\n' + 4101cb0ef41Sopenharmony_ci '123456\r\n' + 4111cb0ef41Sopenharmony_ci '9\r\n' + 4121cb0ef41Sopenharmony_ci '123456789\r\n' + 4131cb0ef41Sopenharmony_ci 'C\r\n' + 4141cb0ef41Sopenharmony_ci '123456789ABC\r\n' + 4151cb0ef41Sopenharmony_ci 'F\r\n' + 4161cb0ef41Sopenharmony_ci '123456789ABCDEF\r\n' + 4171cb0ef41Sopenharmony_ci '0\r\n' 4181cb0ef41Sopenharmony_ci ); 4191cb0ef41Sopenharmony_ci 4201cb0ef41Sopenharmony_ci function test(a, b) { 4211cb0ef41Sopenharmony_ci const onHeadersComplete = (versionMajor, versionMinor, headers, 4221cb0ef41Sopenharmony_ci method, url) => { 4231cb0ef41Sopenharmony_ci assert.strictEqual(method, methods.indexOf('POST')); 4241cb0ef41Sopenharmony_ci assert.strictEqual(url || parser.url, '/helpme'); 4251cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 4261cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 1); 4271cb0ef41Sopenharmony_ci }; 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_ci let expected_body = '123123456123456789123456789ABC123456789ABCDEF'; 4301cb0ef41Sopenharmony_ci 4311cb0ef41Sopenharmony_ci const onBody = (buf) => { 4321cb0ef41Sopenharmony_ci const chunk = String(buf); 4331cb0ef41Sopenharmony_ci assert.strictEqual(expected_body.indexOf(chunk), 0); 4341cb0ef41Sopenharmony_ci expected_body = expected_body.slice(chunk.length); 4351cb0ef41Sopenharmony_ci }; 4361cb0ef41Sopenharmony_ci 4371cb0ef41Sopenharmony_ci const parser = newParser(REQUEST); 4381cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = mustCall(onHeadersComplete); 4391cb0ef41Sopenharmony_ci parser[kOnBody] = onBody; 4401cb0ef41Sopenharmony_ci parser.execute(a, 0, a.length); 4411cb0ef41Sopenharmony_ci parser.execute(b, 0, b.length); 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_ci assert.strictEqual(expected_body, ''); 4441cb0ef41Sopenharmony_ci } 4451cb0ef41Sopenharmony_ci 4461cb0ef41Sopenharmony_ci for (let i = 1; i < request.length - 1; ++i) { 4471cb0ef41Sopenharmony_ci const a = request.slice(0, i); 4481cb0ef41Sopenharmony_ci const b = request.slice(i); 4491cb0ef41Sopenharmony_ci test(a, b); 4501cb0ef41Sopenharmony_ci } 4511cb0ef41Sopenharmony_ci} 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ci 4541cb0ef41Sopenharmony_ci// 4551cb0ef41Sopenharmony_ci// Byte by byte test. 4561cb0ef41Sopenharmony_ci// 4571cb0ef41Sopenharmony_ci{ 4581cb0ef41Sopenharmony_ci const request = Buffer.from( 4591cb0ef41Sopenharmony_ci 'POST /it HTTP/1.1\r\n' + 4601cb0ef41Sopenharmony_ci 'Content-Type: text/plain\r\n' + 4611cb0ef41Sopenharmony_ci 'Transfer-Encoding: chunked\r\n' + 4621cb0ef41Sopenharmony_ci '\r\n' + 4631cb0ef41Sopenharmony_ci '3\r\n' + 4641cb0ef41Sopenharmony_ci '123\r\n' + 4651cb0ef41Sopenharmony_ci '6\r\n' + 4661cb0ef41Sopenharmony_ci '123456\r\n' + 4671cb0ef41Sopenharmony_ci '9\r\n' + 4681cb0ef41Sopenharmony_ci '123456789\r\n' + 4691cb0ef41Sopenharmony_ci 'C\r\n' + 4701cb0ef41Sopenharmony_ci '123456789ABC\r\n' + 4711cb0ef41Sopenharmony_ci 'F\r\n' + 4721cb0ef41Sopenharmony_ci '123456789ABCDEF\r\n' + 4731cb0ef41Sopenharmony_ci '0\r\n' 4741cb0ef41Sopenharmony_ci ); 4751cb0ef41Sopenharmony_ci 4761cb0ef41Sopenharmony_ci const onHeadersComplete = (versionMajor, versionMinor, headers, 4771cb0ef41Sopenharmony_ci method, url) => { 4781cb0ef41Sopenharmony_ci assert.strictEqual(method, methods.indexOf('POST')); 4791cb0ef41Sopenharmony_ci assert.strictEqual(url || parser.url, '/it'); 4801cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 4811cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 1); 4821cb0ef41Sopenharmony_ci assert.deepStrictEqual( 4831cb0ef41Sopenharmony_ci headers || parser.headers, 4841cb0ef41Sopenharmony_ci ['Content-Type', 'text/plain', 'Transfer-Encoding', 'chunked']); 4851cb0ef41Sopenharmony_ci }; 4861cb0ef41Sopenharmony_ci 4871cb0ef41Sopenharmony_ci let expected_body = '123123456123456789123456789ABC123456789ABCDEF'; 4881cb0ef41Sopenharmony_ci 4891cb0ef41Sopenharmony_ci const onBody = (buf) => { 4901cb0ef41Sopenharmony_ci const chunk = String(buf); 4911cb0ef41Sopenharmony_ci assert.strictEqual(expected_body.indexOf(chunk), 0); 4921cb0ef41Sopenharmony_ci expected_body = expected_body.slice(chunk.length); 4931cb0ef41Sopenharmony_ci }; 4941cb0ef41Sopenharmony_ci 4951cb0ef41Sopenharmony_ci const parser = newParser(REQUEST); 4961cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = mustCall(onHeadersComplete); 4971cb0ef41Sopenharmony_ci parser[kOnBody] = onBody; 4981cb0ef41Sopenharmony_ci 4991cb0ef41Sopenharmony_ci for (let i = 0; i < request.length; ++i) { 5001cb0ef41Sopenharmony_ci parser.execute(request, i, 1); 5011cb0ef41Sopenharmony_ci } 5021cb0ef41Sopenharmony_ci 5031cb0ef41Sopenharmony_ci assert.strictEqual(expected_body, ''); 5041cb0ef41Sopenharmony_ci} 5051cb0ef41Sopenharmony_ci 5061cb0ef41Sopenharmony_ci 5071cb0ef41Sopenharmony_ci// 5081cb0ef41Sopenharmony_ci// Test parser reinit sequence. 5091cb0ef41Sopenharmony_ci// 5101cb0ef41Sopenharmony_ci{ 5111cb0ef41Sopenharmony_ci const req1 = Buffer.from( 5121cb0ef41Sopenharmony_ci 'PUT /this HTTP/1.1\r\n' + 5131cb0ef41Sopenharmony_ci 'Content-Type: text/plain\r\n' + 5141cb0ef41Sopenharmony_ci 'Transfer-Encoding: chunked\r\n' + 5151cb0ef41Sopenharmony_ci '\r\n' + 5161cb0ef41Sopenharmony_ci '4\r\n' + 5171cb0ef41Sopenharmony_ci 'ping\r\n' + 5181cb0ef41Sopenharmony_ci '0\r\n' 5191cb0ef41Sopenharmony_ci ); 5201cb0ef41Sopenharmony_ci 5211cb0ef41Sopenharmony_ci const req2 = Buffer.from( 5221cb0ef41Sopenharmony_ci 'POST /that HTTP/1.0\r\n' + 5231cb0ef41Sopenharmony_ci 'Content-Type: text/plain\r\n' + 5241cb0ef41Sopenharmony_ci 'Content-Length: 4\r\n' + 5251cb0ef41Sopenharmony_ci '\r\n' + 5261cb0ef41Sopenharmony_ci 'pong' 5271cb0ef41Sopenharmony_ci ); 5281cb0ef41Sopenharmony_ci 5291cb0ef41Sopenharmony_ci const onHeadersComplete1 = (versionMajor, versionMinor, headers, 5301cb0ef41Sopenharmony_ci method, url) => { 5311cb0ef41Sopenharmony_ci assert.strictEqual(method, methods.indexOf('PUT')); 5321cb0ef41Sopenharmony_ci assert.strictEqual(url, '/this'); 5331cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 5341cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 1); 5351cb0ef41Sopenharmony_ci assert.deepStrictEqual( 5361cb0ef41Sopenharmony_ci headers, 5371cb0ef41Sopenharmony_ci ['Content-Type', 'text/plain', 'Transfer-Encoding', 'chunked']); 5381cb0ef41Sopenharmony_ci }; 5391cb0ef41Sopenharmony_ci 5401cb0ef41Sopenharmony_ci const onHeadersComplete2 = (versionMajor, versionMinor, headers, 5411cb0ef41Sopenharmony_ci method, url) => { 5421cb0ef41Sopenharmony_ci assert.strictEqual(method, methods.indexOf('POST')); 5431cb0ef41Sopenharmony_ci assert.strictEqual(url, '/that'); 5441cb0ef41Sopenharmony_ci assert.strictEqual(versionMajor, 1); 5451cb0ef41Sopenharmony_ci assert.strictEqual(versionMinor, 0); 5461cb0ef41Sopenharmony_ci assert.deepStrictEqual( 5471cb0ef41Sopenharmony_ci headers, 5481cb0ef41Sopenharmony_ci ['Content-Type', 'text/plain', 'Content-Length', '4'] 5491cb0ef41Sopenharmony_ci ); 5501cb0ef41Sopenharmony_ci }; 5511cb0ef41Sopenharmony_ci 5521cb0ef41Sopenharmony_ci const parser = newParser(REQUEST); 5531cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = onHeadersComplete1; 5541cb0ef41Sopenharmony_ci parser[kOnBody] = expectBody('ping'); 5551cb0ef41Sopenharmony_ci parser.execute(req1, 0, req1.length); 5561cb0ef41Sopenharmony_ci 5571cb0ef41Sopenharmony_ci parser.initialize(REQUEST, req2); 5581cb0ef41Sopenharmony_ci parser[kOnBody] = expectBody('pong'); 5591cb0ef41Sopenharmony_ci parser[kOnHeadersComplete] = onHeadersComplete2; 5601cb0ef41Sopenharmony_ci parser.execute(req2, 0, req2.length); 5611cb0ef41Sopenharmony_ci} 5621cb0ef41Sopenharmony_ci 5631cb0ef41Sopenharmony_ci// Test parser 'this' safety 5641cb0ef41Sopenharmony_ci// https://github.com/joyent/node/issues/6690 5651cb0ef41Sopenharmony_ciassert.throws(function() { 5661cb0ef41Sopenharmony_ci const request = Buffer.from('GET /hello HTTP/1.1\r\n\r\n'); 5671cb0ef41Sopenharmony_ci 5681cb0ef41Sopenharmony_ci const parser = newParser(REQUEST); 5691cb0ef41Sopenharmony_ci const notparser = { execute: parser.execute }; 5701cb0ef41Sopenharmony_ci notparser.execute(request, 0, request.length); 5711cb0ef41Sopenharmony_ci}, TypeError); 572