From 3d575a4f1bd197c3ce669758a2a3c763462a883a Mon Sep 17 00:00:00 2001 From: Kid <44045911+kidonng@users.noreply.github.com> Date: Sat, 9 Jul 2022 08:01:28 +0800 Subject: [PATCH] esm: treat `307` and `308` as redirects in HTTPS imports Per RFC 7231 and 7238, HTTP `307` and `308` status code are also for redirect responses. Fixes: https://github.com/nodejs/node/issues/43679 Refs: https://datatracker.ietf.org/doc/html/rfc7231#section-6.4.7 Refs: https://datatracker.ietf.org/doc/html/rfc7238 PR-URL: https://github.com/nodejs/node/pull/43689 Reviewed-By: Geoffrey Booth Reviewed-By: Zijian Liu Reviewed-By: LiviaMedeiros Reviewed-By: Antoine du Hamel Reviewed-By: Jacob Smith --- lib/internal/modules/esm/fetch_module.js | 27 +++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) 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,