diff --git a/lib/internal/modules/esm/fetch_module.js b/lib/internal/modules/esm/fetch_module.js index c65587e34c488f..19ff8c4b946346 100644 --- a/lib/internal/modules/esm/fetch_module.js +++ b/lib/internal/modules/esm/fetch_module.js @@ -89,6 +89,28 @@ function createUnzip() { return createUnzip(); } +/** + * Redirection status code as per section 6.4 of RFC 7231: + * https://datatracker.ietf.org/doc/html/rfc7231#section-6.4 + * and RFC 7238: + * https://datatracker.ietf.org/doc/html/rfc7238 + * @param {number} statusCode + * @returns {boolean} + */ +function isRedirect(statusCode) { + switch (statusCode) { + case 300: // Multiple Choices + case 301: // Moved Permanently + case 302: // Found + case 303: // See Other + case 307: // Temporary Redirect + case 308: // Permanent Redirect + return true; + default: + return false; + } +} + /** * @param {URL} parsed * @returns {Promise | CacheEntry} @@ -107,9 +129,8 @@ function fetchWithRedirects(parsed) { // `finally` on network error/timeout. const { 0: res } = await once(req, 'response'); try { - const isRedirect = res.statusCode >= 300 && res.statusCode <= 303; const hasLocation = ObjectPrototypeHasOwnProperty(res.headers, 'location'); - if (isRedirect && hasLocation) { + if (isRedirect(res.statusCode) && hasLocation) { const location = new URL(res.headers.location, parsed); if (location.protocol !== 'http:' && location.protocol !== 'https:') { throw new ERR_NETWORK_IMPORT_DISALLOWED( @@ -127,7 +148,7 @@ function fetchWithRedirects(parsed) { err.message = `Cannot find module '${parsed.href}', HTTP 404`; throw err; } - if (res.statusCode > 303 || res.statusCode < 200) { + if (res.statusCode < 200 || res.statusCode >= 400) { throw new ERR_NETWORK_IMPORT_DISALLOWED( res.headers.location, parsed.href,