11cb0ef41Sopenharmony_ci// Flags: --experimental-network-imports --dns-result-order=ipv4first
21cb0ef41Sopenharmony_ciimport * as common from '../common/index.mjs';
31cb0ef41Sopenharmony_ciimport { path, readKey } from '../common/fixtures.mjs';
41cb0ef41Sopenharmony_ciimport { pathToFileURL } from 'url';
51cb0ef41Sopenharmony_ciimport assert from 'assert';
61cb0ef41Sopenharmony_ciimport http from 'http';
71cb0ef41Sopenharmony_ciimport os from 'os';
81cb0ef41Sopenharmony_ciimport util from 'util';
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ciif (!common.hasCrypto) {
111cb0ef41Sopenharmony_ci  common.skip('missing crypto');
121cb0ef41Sopenharmony_ci}
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciconst https = (await import('https')).default;
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciconst createHTTPServer = http.createServer;
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci// Needed to deal w/ test certs
191cb0ef41Sopenharmony_ciprocess.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
201cb0ef41Sopenharmony_ciconst options = {
211cb0ef41Sopenharmony_ci  key: readKey('agent1-key.pem'),
221cb0ef41Sopenharmony_ci  cert: readKey('agent1-cert.pem')
231cb0ef41Sopenharmony_ci};
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciconst createHTTPSServer = https.createServer.bind(null, options);
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ciconst testListeningOptions = [
291cb0ef41Sopenharmony_ci  {
301cb0ef41Sopenharmony_ci    hostname: 'localhost',
311cb0ef41Sopenharmony_ci    listenOptions: {
321cb0ef41Sopenharmony_ci      host: '127.0.0.1'
331cb0ef41Sopenharmony_ci    }
341cb0ef41Sopenharmony_ci  },
351cb0ef41Sopenharmony_ci];
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ciconst internalInterfaces = Object.values(os.networkInterfaces()).flat().filter(
381cb0ef41Sopenharmony_ci  (iface) => iface?.internal && iface.address && !iface.scopeid
391cb0ef41Sopenharmony_ci);
401cb0ef41Sopenharmony_cifor (const iface of internalInterfaces) {
411cb0ef41Sopenharmony_ci  testListeningOptions.push({
421cb0ef41Sopenharmony_ci    hostname: iface?.family === 'IPv6' ? `[${iface?.address}]` : iface?.address,
431cb0ef41Sopenharmony_ci    listenOptions: {
441cb0ef41Sopenharmony_ci      host: iface?.address,
451cb0ef41Sopenharmony_ci      ipv6Only: iface?.family === 'IPv6'
461cb0ef41Sopenharmony_ci    }
471cb0ef41Sopenharmony_ci  });
481cb0ef41Sopenharmony_ci}
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_cifor (const { protocol, createServer } of [
511cb0ef41Sopenharmony_ci  { protocol: 'http:', createServer: createHTTPServer },
521cb0ef41Sopenharmony_ci  { protocol: 'https:', createServer: createHTTPSServer },
531cb0ef41Sopenharmony_ci]) {
541cb0ef41Sopenharmony_ci  const body = `
551cb0ef41Sopenharmony_ci    export default (a) => () => a;
561cb0ef41Sopenharmony_ci    export let url = import.meta.url;
571cb0ef41Sopenharmony_ci  `;
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci  const base = 'http://127.0.0.1';
601cb0ef41Sopenharmony_ci  for (const { hostname, listenOptions } of testListeningOptions) {
611cb0ef41Sopenharmony_ci    const host = new URL(base);
621cb0ef41Sopenharmony_ci    host.protocol = protocol;
631cb0ef41Sopenharmony_ci    host.hostname = hostname;
641cb0ef41Sopenharmony_ci    // /not-found is a 404
651cb0ef41Sopenharmony_ci    // ?redirect causes a redirect, no body. JSON.parse({status:number,location:string})
661cb0ef41Sopenharmony_ci    // ?mime sets the content-type, string
671cb0ef41Sopenharmony_ci    // ?body sets the body, string
681cb0ef41Sopenharmony_ci    const server = createServer(function(_req, res) {
691cb0ef41Sopenharmony_ci      const url = new URL(_req.url, host);
701cb0ef41Sopenharmony_ci      const redirect = url.searchParams.get('redirect');
711cb0ef41Sopenharmony_ci      if (url.pathname === '/not-found') {
721cb0ef41Sopenharmony_ci        res.writeHead(404);
731cb0ef41Sopenharmony_ci        res.end();
741cb0ef41Sopenharmony_ci        return;
751cb0ef41Sopenharmony_ci      }
761cb0ef41Sopenharmony_ci      if (redirect) {
771cb0ef41Sopenharmony_ci        const { status, location } = JSON.parse(redirect);
781cb0ef41Sopenharmony_ci        res.writeHead(status, {
791cb0ef41Sopenharmony_ci          location
801cb0ef41Sopenharmony_ci        });
811cb0ef41Sopenharmony_ci        res.end();
821cb0ef41Sopenharmony_ci        return;
831cb0ef41Sopenharmony_ci      }
841cb0ef41Sopenharmony_ci      res.writeHead(200, {
851cb0ef41Sopenharmony_ci        'content-type': url.searchParams.get('mime') || 'text/javascript'
861cb0ef41Sopenharmony_ci      });
871cb0ef41Sopenharmony_ci      res.end(url.searchParams.get('body') || body);
881cb0ef41Sopenharmony_ci    });
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci    const listen = util.promisify(server.listen.bind(server));
911cb0ef41Sopenharmony_ci    await listen({
921cb0ef41Sopenharmony_ci      ...listenOptions,
931cb0ef41Sopenharmony_ci      port: 0
941cb0ef41Sopenharmony_ci    });
951cb0ef41Sopenharmony_ci    const url = new URL(host);
961cb0ef41Sopenharmony_ci    url.port = server?.address()?.port;
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci    const ns = await import(url.href);
991cb0ef41Sopenharmony_ci    assert.strict.deepStrictEqual(Object.keys(ns), ['default', 'url']);
1001cb0ef41Sopenharmony_ci    const obj = {};
1011cb0ef41Sopenharmony_ci    assert.strict.equal(ns.default(obj)(), obj);
1021cb0ef41Sopenharmony_ci    assert.strict.equal(ns.url, url.href);
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci    // Redirects have same import.meta.url but different cache
1051cb0ef41Sopenharmony_ci    // entry on Web
1061cb0ef41Sopenharmony_ci    const redirect = new URL(url.href);
1071cb0ef41Sopenharmony_ci    redirect.searchParams.set('redirect', JSON.stringify({
1081cb0ef41Sopenharmony_ci      status: 302,
1091cb0ef41Sopenharmony_ci      location: url.href
1101cb0ef41Sopenharmony_ci    }));
1111cb0ef41Sopenharmony_ci    const redirectedNS = await import(redirect.href);
1121cb0ef41Sopenharmony_ci    assert.strict.deepStrictEqual(
1131cb0ef41Sopenharmony_ci      Object.keys(redirectedNS),
1141cb0ef41Sopenharmony_ci      ['default', 'url']
1151cb0ef41Sopenharmony_ci    );
1161cb0ef41Sopenharmony_ci    assert.strict.notEqual(redirectedNS.default, ns.default);
1171cb0ef41Sopenharmony_ci    assert.strict.equal(redirectedNS.url, url.href);
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci    // Redirects have the same import.meta.url but different cache
1201cb0ef41Sopenharmony_ci    // entry on Web
1211cb0ef41Sopenharmony_ci    const relativeAfterRedirect = new URL(url.href + 'foo/index.js');
1221cb0ef41Sopenharmony_ci    const redirected = new URL(url.href + 'bar/index.js');
1231cb0ef41Sopenharmony_ci    redirected.searchParams.set('body', 'export let relativeDepURL = (await import("./baz.js")).url');
1241cb0ef41Sopenharmony_ci    relativeAfterRedirect.searchParams.set('redirect', JSON.stringify({
1251cb0ef41Sopenharmony_ci      status: 302,
1261cb0ef41Sopenharmony_ci      location: redirected.href
1271cb0ef41Sopenharmony_ci    }));
1281cb0ef41Sopenharmony_ci    const relativeAfterRedirectedNS = await import(relativeAfterRedirect.href);
1291cb0ef41Sopenharmony_ci    assert.strict.equal(
1301cb0ef41Sopenharmony_ci      relativeAfterRedirectedNS.relativeDepURL,
1311cb0ef41Sopenharmony_ci      url.href + 'bar/baz.js'
1321cb0ef41Sopenharmony_ci    );
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci    const crossProtocolRedirect = new URL(url.href);
1351cb0ef41Sopenharmony_ci    crossProtocolRedirect.searchParams.set('redirect', JSON.stringify({
1361cb0ef41Sopenharmony_ci      status: 302,
1371cb0ef41Sopenharmony_ci      location: 'data:text/javascript,'
1381cb0ef41Sopenharmony_ci    }));
1391cb0ef41Sopenharmony_ci    await assert.rejects(
1401cb0ef41Sopenharmony_ci      import(crossProtocolRedirect.href),
1411cb0ef41Sopenharmony_ci      { code: 'ERR_NETWORK_IMPORT_DISALLOWED' }
1421cb0ef41Sopenharmony_ci    );
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci    const deps = new URL(url.href);
1451cb0ef41Sopenharmony_ci    deps.searchParams.set('body', `
1461cb0ef41Sopenharmony_ci      export {data} from 'data:text/javascript,export let data = 1';
1471cb0ef41Sopenharmony_ci      import * as http from ${JSON.stringify(url.href)};
1481cb0ef41Sopenharmony_ci      export {http};
1491cb0ef41Sopenharmony_ci    `);
1501cb0ef41Sopenharmony_ci    const depsNS = await import(deps.href);
1511cb0ef41Sopenharmony_ci    assert.strict.deepStrictEqual(Object.keys(depsNS), ['data', 'http']);
1521cb0ef41Sopenharmony_ci    assert.strict.equal(depsNS.data, 1);
1531cb0ef41Sopenharmony_ci    assert.strict.equal(depsNS.http, ns);
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci    const relativeDeps = new URL(url.href);
1561cb0ef41Sopenharmony_ci    relativeDeps.searchParams.set('body', `
1571cb0ef41Sopenharmony_ci      import * as http from "./";
1581cb0ef41Sopenharmony_ci      export {http};
1591cb0ef41Sopenharmony_ci    `);
1601cb0ef41Sopenharmony_ci    const relativeDepsNS = await import(relativeDeps.href);
1611cb0ef41Sopenharmony_ci    assert.strict.deepStrictEqual(Object.keys(relativeDepsNS), ['http']);
1621cb0ef41Sopenharmony_ci    assert.strict.equal(relativeDepsNS.http, ns);
1631cb0ef41Sopenharmony_ci    const fileDep = new URL(url.href);
1641cb0ef41Sopenharmony_ci    const { href } = pathToFileURL(path('/es-modules/message.mjs'));
1651cb0ef41Sopenharmony_ci    fileDep.searchParams.set('body', `
1661cb0ef41Sopenharmony_ci      import ${JSON.stringify(href)};
1671cb0ef41Sopenharmony_ci      export default 1;`);
1681cb0ef41Sopenharmony_ci    await assert.rejects(
1691cb0ef41Sopenharmony_ci      import(fileDep.href),
1701cb0ef41Sopenharmony_ci      { code: 'ERR_NETWORK_IMPORT_DISALLOWED' }
1711cb0ef41Sopenharmony_ci    );
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci    const builtinDep = new URL(url.href);
1741cb0ef41Sopenharmony_ci    builtinDep.searchParams.set('body', `
1751cb0ef41Sopenharmony_ci      import 'node:fs';
1761cb0ef41Sopenharmony_ci      export default 1;
1771cb0ef41Sopenharmony_ci    `);
1781cb0ef41Sopenharmony_ci    await assert.rejects(
1791cb0ef41Sopenharmony_ci      import(builtinDep.href),
1801cb0ef41Sopenharmony_ci      { code: 'ERR_NETWORK_IMPORT_DISALLOWED' }
1811cb0ef41Sopenharmony_ci    );
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ci    const unprefixedBuiltinDep = new URL(url.href);
1841cb0ef41Sopenharmony_ci    unprefixedBuiltinDep.searchParams.set('body', `
1851cb0ef41Sopenharmony_ci      import 'fs';
1861cb0ef41Sopenharmony_ci      export default 1;
1871cb0ef41Sopenharmony_ci    `);
1881cb0ef41Sopenharmony_ci    await assert.rejects(
1891cb0ef41Sopenharmony_ci      import(unprefixedBuiltinDep.href),
1901cb0ef41Sopenharmony_ci      { code: 'ERR_NETWORK_IMPORT_DISALLOWED' }
1911cb0ef41Sopenharmony_ci    );
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci    const unsupportedMIME = new URL(url.href);
1941cb0ef41Sopenharmony_ci    unsupportedMIME.searchParams.set('mime', 'application/node');
1951cb0ef41Sopenharmony_ci    unsupportedMIME.searchParams.set('body', '');
1961cb0ef41Sopenharmony_ci    await assert.rejects(
1971cb0ef41Sopenharmony_ci      import(unsupportedMIME.href),
1981cb0ef41Sopenharmony_ci      { code: 'ERR_UNKNOWN_MODULE_FORMAT' }
1991cb0ef41Sopenharmony_ci    );
2001cb0ef41Sopenharmony_ci    const notFound = new URL(url.href);
2011cb0ef41Sopenharmony_ci    notFound.pathname = '/not-found';
2021cb0ef41Sopenharmony_ci    await assert.rejects(
2031cb0ef41Sopenharmony_ci      import(notFound.href),
2041cb0ef41Sopenharmony_ci      { code: 'ERR_MODULE_NOT_FOUND' },
2051cb0ef41Sopenharmony_ci    );
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ci    server.close();
2081cb0ef41Sopenharmony_ci  }
2091cb0ef41Sopenharmony_ci}
210