11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ciif (!common.hasCrypto)
51cb0ef41Sopenharmony_ci  common.skip('missing crypto');
61cb0ef41Sopenharmony_ciconst assert = require('assert');
71cb0ef41Sopenharmony_ciconst net = require('net');
81cb0ef41Sopenharmony_ciconst http2 = require('http2');
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ciconst {
111cb0ef41Sopenharmony_ci  HTTP2_HEADER_METHOD,
121cb0ef41Sopenharmony_ci  HTTP2_HEADER_AUTHORITY,
131cb0ef41Sopenharmony_ci  HTTP2_HEADER_SCHEME,
141cb0ef41Sopenharmony_ci  HTTP2_HEADER_PATH,
151cb0ef41Sopenharmony_ci  NGHTTP2_CONNECT_ERROR,
161cb0ef41Sopenharmony_ci  NGHTTP2_REFUSED_STREAM
171cb0ef41Sopenharmony_ci} = http2.constants;
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ciconst server = net.createServer(common.mustCall((socket) => {
201cb0ef41Sopenharmony_ci  let data = '';
211cb0ef41Sopenharmony_ci  socket.setEncoding('utf8');
221cb0ef41Sopenharmony_ci  socket.on('data', (chunk) => data += chunk);
231cb0ef41Sopenharmony_ci  socket.on('end', common.mustCall(() => {
241cb0ef41Sopenharmony_ci    assert.strictEqual(data, 'hello');
251cb0ef41Sopenharmony_ci  }));
261cb0ef41Sopenharmony_ci  socket.on('close', common.mustCall());
271cb0ef41Sopenharmony_ci  socket.end('hello');
281cb0ef41Sopenharmony_ci}));
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ciserver.listen(0, common.mustCall(() => {
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci  const port = server.address().port;
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci  const proxy = http2.createServer();
351cb0ef41Sopenharmony_ci  proxy.on('stream', common.mustCall((stream, headers) => {
361cb0ef41Sopenharmony_ci    if (headers[HTTP2_HEADER_METHOD] !== 'CONNECT') {
371cb0ef41Sopenharmony_ci      stream.close(NGHTTP2_REFUSED_STREAM);
381cb0ef41Sopenharmony_ci      return;
391cb0ef41Sopenharmony_ci    }
401cb0ef41Sopenharmony_ci    const auth = new URL(`tcp://${headers[HTTP2_HEADER_AUTHORITY]}`);
411cb0ef41Sopenharmony_ci    assert.strictEqual(auth.hostname, 'localhost');
421cb0ef41Sopenharmony_ci    assert.strictEqual(+auth.port, port);
431cb0ef41Sopenharmony_ci    const socket = net.connect(auth.port, auth.hostname, () => {
441cb0ef41Sopenharmony_ci      stream.respond();
451cb0ef41Sopenharmony_ci      socket.pipe(stream);
461cb0ef41Sopenharmony_ci      stream.pipe(socket);
471cb0ef41Sopenharmony_ci    });
481cb0ef41Sopenharmony_ci    socket.on('close', common.mustCall());
491cb0ef41Sopenharmony_ci    socket.on('error', (error) => {
501cb0ef41Sopenharmony_ci      stream.close(NGHTTP2_CONNECT_ERROR);
511cb0ef41Sopenharmony_ci    });
521cb0ef41Sopenharmony_ci  }));
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci  proxy.listen(0, () => {
551cb0ef41Sopenharmony_ci    const client = http2.connect(`http://localhost:${proxy.address().port}`);
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci    // Confirm that :authority is required and :scheme & :path are forbidden
581cb0ef41Sopenharmony_ci    assert.throws(
591cb0ef41Sopenharmony_ci      () => client.request({
601cb0ef41Sopenharmony_ci        [HTTP2_HEADER_METHOD]: 'CONNECT'
611cb0ef41Sopenharmony_ci      }),
621cb0ef41Sopenharmony_ci      {
631cb0ef41Sopenharmony_ci        code: 'ERR_HTTP2_CONNECT_AUTHORITY',
641cb0ef41Sopenharmony_ci        message: ':authority header is required for CONNECT requests'
651cb0ef41Sopenharmony_ci      }
661cb0ef41Sopenharmony_ci    );
671cb0ef41Sopenharmony_ci    assert.throws(
681cb0ef41Sopenharmony_ci      () => client.request({
691cb0ef41Sopenharmony_ci        [HTTP2_HEADER_METHOD]: 'CONNECT',
701cb0ef41Sopenharmony_ci        [HTTP2_HEADER_AUTHORITY]: `localhost:${port}`,
711cb0ef41Sopenharmony_ci        [HTTP2_HEADER_SCHEME]: 'http'
721cb0ef41Sopenharmony_ci      }),
731cb0ef41Sopenharmony_ci      {
741cb0ef41Sopenharmony_ci        code: 'ERR_HTTP2_CONNECT_SCHEME',
751cb0ef41Sopenharmony_ci        message: 'The :scheme header is forbidden for CONNECT requests'
761cb0ef41Sopenharmony_ci      }
771cb0ef41Sopenharmony_ci    );
781cb0ef41Sopenharmony_ci    assert.throws(
791cb0ef41Sopenharmony_ci      () => client.request({
801cb0ef41Sopenharmony_ci        [HTTP2_HEADER_METHOD]: 'CONNECT',
811cb0ef41Sopenharmony_ci        [HTTP2_HEADER_AUTHORITY]: `localhost:${port}`,
821cb0ef41Sopenharmony_ci        [HTTP2_HEADER_PATH]: '/'
831cb0ef41Sopenharmony_ci      }),
841cb0ef41Sopenharmony_ci      {
851cb0ef41Sopenharmony_ci        code: 'ERR_HTTP2_CONNECT_PATH',
861cb0ef41Sopenharmony_ci        message: 'The :path header is forbidden for CONNECT requests'
871cb0ef41Sopenharmony_ci      }
881cb0ef41Sopenharmony_ci    );
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci    // valid CONNECT request
911cb0ef41Sopenharmony_ci    const req = client.request({
921cb0ef41Sopenharmony_ci      [HTTP2_HEADER_METHOD]: 'CONNECT',
931cb0ef41Sopenharmony_ci      [HTTP2_HEADER_AUTHORITY]: `localhost:${port}`,
941cb0ef41Sopenharmony_ci    });
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci    req.on('response', common.mustCall());
971cb0ef41Sopenharmony_ci    let data = '';
981cb0ef41Sopenharmony_ci    req.setEncoding('utf8');
991cb0ef41Sopenharmony_ci    req.on('data', (chunk) => data += chunk);
1001cb0ef41Sopenharmony_ci    req.on('end', common.mustCall(() => {
1011cb0ef41Sopenharmony_ci      assert.strictEqual(data, 'hello');
1021cb0ef41Sopenharmony_ci      client.close();
1031cb0ef41Sopenharmony_ci      proxy.close();
1041cb0ef41Sopenharmony_ci      server.close();
1051cb0ef41Sopenharmony_ci    }));
1061cb0ef41Sopenharmony_ci    req.end('hello');
1071cb0ef41Sopenharmony_ci  });
1081cb0ef41Sopenharmony_ci}));
109