11cb0ef41Sopenharmony_ci// Flags: --expose-internals
21cb0ef41Sopenharmony_ci'use strict';
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ciconst assert = require('assert');
51cb0ef41Sopenharmony_ciconst http = require('http');
61cb0ef41Sopenharmony_ciconst net = require('net');
71cb0ef41Sopenharmony_ciconst MAX = +(process.argv[2] || 16 * 1024); // Command line option, or 16KB.
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciconst { getOptionValue } = require('internal/options');
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ciconsole.log('pid is', process.pid);
121cb0ef41Sopenharmony_ciconsole.log('max header size is', getOptionValue('--max-http-header-size'));
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ci// Verify that we cannot receive more than 16KB of headers.
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_cifunction once(cb) {
171cb0ef41Sopenharmony_ci  let called = false;
181cb0ef41Sopenharmony_ci  return () => {
191cb0ef41Sopenharmony_ci    if (!called) {
201cb0ef41Sopenharmony_ci      called = true;
211cb0ef41Sopenharmony_ci      cb();
221cb0ef41Sopenharmony_ci    }
231cb0ef41Sopenharmony_ci  };
241cb0ef41Sopenharmony_ci}
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_cifunction finished(client, callback) {
271cb0ef41Sopenharmony_ci  ['abort', 'error', 'end'].forEach((e) => {
281cb0ef41Sopenharmony_ci    client.on(e, once(() => setImmediate(callback)));
291cb0ef41Sopenharmony_ci  });
301cb0ef41Sopenharmony_ci}
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_cifunction fillHeaders(headers, currentSize, valid = false) {
331cb0ef41Sopenharmony_ci  // `llhttp` counts actual header name/value sizes, excluding the whitespace
341cb0ef41Sopenharmony_ci  // and stripped chars.
351cb0ef41Sopenharmony_ci  // OK, Content-Length, 0, X-CRASH, aaa...
361cb0ef41Sopenharmony_ci  headers += 'a'.repeat(MAX - currentSize);
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  // Generate valid headers
391cb0ef41Sopenharmony_ci  if (valid) {
401cb0ef41Sopenharmony_ci    headers = headers.slice(0, -1);
411cb0ef41Sopenharmony_ci  }
421cb0ef41Sopenharmony_ci  return headers + '\r\n\r\n';
431cb0ef41Sopenharmony_ci}
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_cifunction writeHeaders(socket, headers) {
461cb0ef41Sopenharmony_ci  const array = [];
471cb0ef41Sopenharmony_ci  const chunkSize = 100;
481cb0ef41Sopenharmony_ci  let last = 0;
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci  for (let i = 0; i < headers.length / chunkSize; i++) {
511cb0ef41Sopenharmony_ci    const current = (i + 1) * chunkSize;
521cb0ef41Sopenharmony_ci    array.push(headers.slice(last, current));
531cb0ef41Sopenharmony_ci    last = current;
541cb0ef41Sopenharmony_ci  }
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  // Safety check we are chunking correctly
571cb0ef41Sopenharmony_ci  assert.strictEqual(array.join(''), headers);
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci  next();
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  function next() {
621cb0ef41Sopenharmony_ci    if (socket.destroyed) {
631cb0ef41Sopenharmony_ci      console.log('socket was destroyed early, data left to write:',
641cb0ef41Sopenharmony_ci                  array.join('').length);
651cb0ef41Sopenharmony_ci      return;
661cb0ef41Sopenharmony_ci    }
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci    const chunk = array.shift();
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci    if (chunk) {
711cb0ef41Sopenharmony_ci      console.log('writing chunk of size', chunk.length);
721cb0ef41Sopenharmony_ci      socket.write(chunk, next);
731cb0ef41Sopenharmony_ci    } else {
741cb0ef41Sopenharmony_ci      socket.end();
751cb0ef41Sopenharmony_ci    }
761cb0ef41Sopenharmony_ci  }
771cb0ef41Sopenharmony_ci}
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_cifunction test1() {
801cb0ef41Sopenharmony_ci  console.log('test1');
811cb0ef41Sopenharmony_ci  let headers =
821cb0ef41Sopenharmony_ci    'HTTP/1.1 200 OK\r\n' +
831cb0ef41Sopenharmony_ci    'Content-Length: 0\r\n' +
841cb0ef41Sopenharmony_ci    'X-CRASH: ';
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  // OK, Content-Length, 0, X-CRASH, aaa...
871cb0ef41Sopenharmony_ci  const currentSize = 2 + 14 + 1 + 7;
881cb0ef41Sopenharmony_ci  headers = fillHeaders(headers, currentSize);
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  const server = net.createServer((sock) => {
911cb0ef41Sopenharmony_ci    sock.once('data', () => {
921cb0ef41Sopenharmony_ci      writeHeaders(sock, headers);
931cb0ef41Sopenharmony_ci      sock.resume();
941cb0ef41Sopenharmony_ci    });
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci    // The socket might error but that's ok
971cb0ef41Sopenharmony_ci    sock.on('error', () => {});
981cb0ef41Sopenharmony_ci  });
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  server.listen(0, common.mustCall(() => {
1011cb0ef41Sopenharmony_ci    const port = server.address().port;
1021cb0ef41Sopenharmony_ci    const client = http.get({ port: port }, common.mustNotCall());
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci    client.on('error', common.mustCall((err) => {
1051cb0ef41Sopenharmony_ci      assert.strictEqual(err.code, 'HPE_HEADER_OVERFLOW');
1061cb0ef41Sopenharmony_ci      server.close(test2);
1071cb0ef41Sopenharmony_ci    }));
1081cb0ef41Sopenharmony_ci  }));
1091cb0ef41Sopenharmony_ci}
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ciconst test2 = common.mustCall(() => {
1121cb0ef41Sopenharmony_ci  console.log('test2');
1131cb0ef41Sopenharmony_ci  let headers =
1141cb0ef41Sopenharmony_ci    'GET / HTTP/1.1\r\n' +
1151cb0ef41Sopenharmony_ci    'Host: localhost\r\n' +
1161cb0ef41Sopenharmony_ci    'Agent: nod2\r\n' +
1171cb0ef41Sopenharmony_ci    'X-CRASH: ';
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  // /, Host, localhost, Agent, node, X-CRASH, a...
1201cb0ef41Sopenharmony_ci  const currentSize = 1 + 4 + 9 + 5 + 4 + 7;
1211cb0ef41Sopenharmony_ci  headers = fillHeaders(headers, currentSize);
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  const server = http.createServer(common.mustNotCall());
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  server.once('clientError', common.mustCall((err) => {
1261cb0ef41Sopenharmony_ci    assert.strictEqual(err.code, 'HPE_HEADER_OVERFLOW');
1271cb0ef41Sopenharmony_ci  }));
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  server.listen(0, common.mustCall(() => {
1301cb0ef41Sopenharmony_ci    const client = net.connect(server.address().port);
1311cb0ef41Sopenharmony_ci    client.on('connect', () => {
1321cb0ef41Sopenharmony_ci      writeHeaders(client, headers);
1331cb0ef41Sopenharmony_ci      client.resume();
1341cb0ef41Sopenharmony_ci    });
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci    finished(client, common.mustCall(() => {
1371cb0ef41Sopenharmony_ci      server.close(test3);
1381cb0ef41Sopenharmony_ci    }));
1391cb0ef41Sopenharmony_ci  }));
1401cb0ef41Sopenharmony_ci});
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ciconst test3 = common.mustCall(() => {
1431cb0ef41Sopenharmony_ci  console.log('test3');
1441cb0ef41Sopenharmony_ci  let headers =
1451cb0ef41Sopenharmony_ci    'GET / HTTP/1.1\r\n' +
1461cb0ef41Sopenharmony_ci    'Host: localhost\r\n' +
1471cb0ef41Sopenharmony_ci    'Agent: nod3\r\n' +
1481cb0ef41Sopenharmony_ci    'X-CRASH: ';
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci  // /, Host, localhost, Agent, node, X-CRASH, a...
1511cb0ef41Sopenharmony_ci  const currentSize = 1 + 4 + 9 + 5 + 4 + 7;
1521cb0ef41Sopenharmony_ci  headers = fillHeaders(headers, currentSize, true);
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  console.log('writing', headers.length);
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci  const server = http.createServer(common.mustCall((req, res) => {
1571cb0ef41Sopenharmony_ci    res.end('hello from test3 server');
1581cb0ef41Sopenharmony_ci    server.close();
1591cb0ef41Sopenharmony_ci  }));
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci  server.on('clientError', (err) => {
1621cb0ef41Sopenharmony_ci    console.log(err.code);
1631cb0ef41Sopenharmony_ci    if (err.code === 'HPE_HEADER_OVERFLOW') {
1641cb0ef41Sopenharmony_ci      console.log(err.rawPacket.toString('hex'));
1651cb0ef41Sopenharmony_ci    }
1661cb0ef41Sopenharmony_ci  });
1671cb0ef41Sopenharmony_ci  server.on('clientError', common.mustNotCall());
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  server.listen(0, common.mustCall(() => {
1701cb0ef41Sopenharmony_ci    const client = net.connect(server.address().port);
1711cb0ef41Sopenharmony_ci    client.on('connect', () => {
1721cb0ef41Sopenharmony_ci      writeHeaders(client, headers);
1731cb0ef41Sopenharmony_ci      client.resume();
1741cb0ef41Sopenharmony_ci    });
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci    client.pipe(process.stdout);
1771cb0ef41Sopenharmony_ci  }));
1781cb0ef41Sopenharmony_ci});
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_citest1();
181