From 8589f0a6e479ef31df1fd13a4edf3fc26c8c0ee6 Mon Sep 17 00:00:00 2001 From: Dorian Niemiec Date: Tue, 27 Aug 2024 18:03:47 +0200 Subject: [PATCH] Changed URL parser from WHATWG to custom one and adapted code accordingly --- src/handlers/requestHandler.js | 4 +++- src/middleware/redirectTrailingSlashes.js | 4 ++-- src/middleware/rewriteURL.js | 13 +++++++++---- src/middleware/urlSanitizer.js | 11 ++++++++--- src/middleware/webRootPostfixes.js | 17 +++++++++++------ src/utils/legacyModWrapper.js | 14 ++++---------- src/utils/{urlParserLegacy.js => urlParser.js} | 0 ...rlParserLegacy.test.js => urlParser.test.js} | 4 ++-- 8 files changed, 39 insertions(+), 28 deletions(-) rename src/utils/{urlParserLegacy.js => urlParser.js} (100%) rename tests/utils/{urlParserLegacy.test.js => urlParser.test.js} (96%) diff --git a/src/handlers/requestHandler.js b/src/handlers/requestHandler.js index 53ec7a1..1581143 100644 --- a/src/handlers/requestHandler.js +++ b/src/handlers/requestHandler.js @@ -8,6 +8,8 @@ const fixNodeMojibakeURL = require("../utils/urlMojibakeFixer.js"); const ipMatch = require("../utils/ipMatch.js"); const matchHostname = require("../utils/matchHostname.js"); const generateServerString = require("../utils/generateServerString.js"); +const parseURL = require("../utils/urlParser.js"); + let serverconsole = {}; let middleware = []; @@ -695,7 +697,7 @@ function requestHandler(req, res) { } try { - req.parsedURL = new URL( + req.parsedURL = parseURL( req.url, "http" + (req.socket.encrypted ? "s" : "") + diff --git a/src/middleware/redirectTrailingSlashes.js b/src/middleware/redirectTrailingSlashes.js index 472eefb..843cfc9 100644 --- a/src/middleware/redirectTrailingSlashes.js +++ b/src/middleware/redirectTrailingSlashes.js @@ -20,8 +20,8 @@ module.exports = (req, res, logFacilities, config, next) => { res.redirect( req.originalParsedURL.pathname + "/" + - req.parsedURL.search + - req.parsedURL.hash, + (req.parsedURL.search ? req.parsedURL.search : "") + + (req.parsedURL.hash ? req.parsedURL.hash : ""), ); } }); diff --git a/src/middleware/rewriteURL.js b/src/middleware/rewriteURL.js index 8e01274..4702657 100644 --- a/src/middleware/rewriteURL.js +++ b/src/middleware/rewriteURL.js @@ -3,6 +3,7 @@ const createRegex = require("../utils/createRegex.js"); const ipMatch = require("../utils/ipMatch.js"); const sanitizeURL = require("../utils/urlSanitizer.js"); const matchHostname = require("../utils/matchHostname.js"); +const parseURL = require("../utils/urlParser.js"); module.exports = (req, res, logFacilities, config, next) => { try { @@ -90,7 +91,7 @@ module.exports = (req, res, logFacilities, config, next) => { logFacilities.resmessage(`URL rewritten: ${req.url} => ${rewrittenURL}`); req.url = rewrittenURL; try { - req.parsedURL = new URL( + req.parsedURL = parseURL( req.url, `http${req.socket.encrypted ? "s" : ""}://${ req.headers.host @@ -110,7 +111,9 @@ module.exports = (req, res, logFacilities, config, next) => { config.allowDoubleSlashes, ); const preparedReqUrl2 = - req.parsedURL.pathname + req.parsedURL.search + req.parsedURL.hash; + req.parsedURL.pathname + + (req.parsedURL.search ? req.parsedURL.search : "") + + (req.parsedURL.hash ? req.parsedURL.hash : ""); if ( req.url != preparedReqUrl2 || @@ -124,13 +127,15 @@ module.exports = (req, res, logFacilities, config, next) => { return; } else if (sHref != req.parsedURL.pathname) { var rewrittenAgainURL = - sHref + req.parsedURL.search + req.parsedURL.hash; + sHref + + (req.parsedURL.search ? req.parsedURL.search : "") + + (req.parsedURL.hash ? req.parsedURL.hash : ""); logFacilities.resmessage( "URL sanitized: " + req.url + " => " + rewrittenAgainURL, ); req.url = rewrittenAgainURL; try { - req.parsedURL = new URL( + req.parsedURL = parseURL( req.url, `http${req.socket.encrypted ? "s" : ""}://${ req.headers.host diff --git a/src/middleware/urlSanitizer.js b/src/middleware/urlSanitizer.js index cf866cf..9321a0e 100644 --- a/src/middleware/urlSanitizer.js +++ b/src/middleware/urlSanitizer.js @@ -1,4 +1,5 @@ const sanitizeURL = require("../utils/urlSanitizer.js"); +const parseURL = require("../utils/urlParser.js"); module.exports = (req, res, logFacilities, config, next) => { // Sanitize URL @@ -7,17 +8,21 @@ module.exports = (req, res, logFacilities, config, next) => { config.allowDoubleSlashes, ); let preparedReqUrl = - req.parsedURL.pathname + req.parsedURL.search + req.parsedURL.hash; + req.parsedURL.pathname + + (req.parsedURL.search ? req.parsedURL.search : "") + + (req.parsedURL.hash ? req.parsedURL.hash : ""); // Check if URL is "dirty" if (req.parsedURL.pathname != sanitizedHref && !req.isProxy) { let sanitizedURL = - sanitizedHref + req.parsedURL.search + req.parsedURL.hash; + sanitizedHref + + (req.parsedURL.search ? req.parsedURL.search : "") + + (req.parsedURL.hash ? req.parsedURL.hash : ""); logFacilities.resmessage(`URL sanitized: ${req.url} => ${sanitizedURL}`); if (config.rewriteDirtyURLs) { req.url = sanitizedURL; try { - req.parsedURL = new URL( + req.parsedURL = parseURL( req.url, `http${req.socket.encrypted ? "s" : ""}://${ req.headers.host diff --git a/src/middleware/webRootPostfixes.js b/src/middleware/webRootPostfixes.js index 6317237..819fd21 100644 --- a/src/middleware/webRootPostfixes.js +++ b/src/middleware/webRootPostfixes.js @@ -1,6 +1,7 @@ const createRegex = require("../utils/createRegex.js"); const ipMatch = require("../utils/ipMatch.js"); const sanitizeURL = require("../utils/urlSanitizer.js"); +const parseURL = require("../utils/urlParser.js"); module.exports = (req, res, logFacilities, config, next) => { const matchHostname = (hostname) => { @@ -30,8 +31,8 @@ module.exports = (req, res, logFacilities, config, next) => { if (!req.isProxy) { let preparedReqUrl3 = config.allowPostfixDoubleSlashes ? req.parsedURL.pathname.replace(/\/+/, "/") + - req.parsedURL.search + - req.parsedURL.hash + (req.parsedURL.search ? req.parsedURL.search : "") + + (req.parsedURL.hash ? req.parsedURL.hash : "") : req.url; let urlWithPostfix = preparedReqUrl3; let postfixPrefix = ""; @@ -78,7 +79,7 @@ module.exports = (req, res, logFacilities, config, next) => { ); req.url = urlWithPostfix; try { - req.parsedURL = new URL( + req.parsedURL = parseURL( req.url, `http${req.socket.encrypted ? "s" : ""}://${ req.headers.host @@ -98,7 +99,9 @@ module.exports = (req, res, logFacilities, config, next) => { config.allowDoubleSlashes, ); const preparedReqUrl2 = - req.parsedURL.pathname + req.parsedURL.search + req.parsedURL.hash; + req.parsedURL.pathname + + (req.parsedURL.search ? req.parsedURL.search : "") + + (req.parsedURL.hash ? req.parsedURL.hash : ""); if ( req.url != preparedReqUrl2 || @@ -112,13 +115,15 @@ module.exports = (req, res, logFacilities, config, next) => { return; } else if (sHref != req.parsedURL.pathname) { let rewrittenAgainURL = - sHref + req.parsedURL.search + req.parsedURL.hash; + sHref + + (req.parsedURL.search ? req.parsedURL.search : "") + + (req.parsedURL.hash ? req.parsedURL.hash : ""); logFacilities.resmessage( `URL sanitized: ${req.url} => ${rewrittenAgainURL}`, ); req.url = rewrittenAgainURL; try { - req.parsedURL = new URL( + req.parsedURL = parseURL( req.url, `http${req.socket.encrypted ? "s" : ""}://${ req.headers.host diff --git a/src/utils/legacyModWrapper.js b/src/utils/legacyModWrapper.js index c01029b..12994e0 100644 --- a/src/utils/legacyModWrapper.js +++ b/src/utils/legacyModWrapper.js @@ -1,4 +1,3 @@ -const parseURL = require("../utils/urlParserLegacy.js"); let formidable = undefined; try { formidable = require("formidable"); @@ -8,16 +7,11 @@ try { }; } -const legacyParsedURLSymbol = Symbol("legacyParsedURL"); - module.exports = (legacyMod) => { const legacyModHandler = new legacyMod(); let middleware = (req, res, logFacilities, config, next) => { - if (!req[legacyParsedURLSymbol]) - req[legacyParsedURLSymbol] = parseURL(req.url); - - let ext = req[legacyParsedURLSymbol].pathname.match(/[^/]\.([^.]+)$/); + let ext = req.parsedURL.pathname.match(/[^/]\.([^.]+)$/); if (!ext) ext = ""; // Function to parse incoming POST data from the request @@ -66,10 +60,10 @@ module.exports = (legacyMod) => { res, // res logFacilities, // serverconsole res.responseEnd, // responseEnd - req[legacyParsedURLSymbol].pathname, // href + req.parsedURL.pathname, // href ext, // ext - req[legacyParsedURLSymbol], // uobject - req[legacyParsedURLSymbol].search, // search + req.parsedURL, // uobject + req.parsedURL.search, // search "index.html", // defaultpage config.users, // users config.page404, // page404 diff --git a/src/utils/urlParserLegacy.js b/src/utils/urlParser.js similarity index 100% rename from src/utils/urlParserLegacy.js rename to src/utils/urlParser.js diff --git a/tests/utils/urlParserLegacy.test.js b/tests/utils/urlParser.test.js similarity index 96% rename from tests/utils/urlParserLegacy.test.js rename to tests/utils/urlParser.test.js index 7edf724..f5953aa 100644 --- a/tests/utils/urlParserLegacy.test.js +++ b/tests/utils/urlParser.test.js @@ -1,6 +1,6 @@ -const parseURL = require("../../src/utils/urlParserLegacy.js"); +const parseURL = require("../../src/utils/urlParser.js"); -describe("URL parser (for SVR.JS 2.x and 3.x mods)", () => { +describe("URL parser", () => { test("should parse a simple URL", () => { const parsedUrl = parseURL("http://example.com"); expect(parsedUrl.protocol).toBe("http:");