From 669b7f4df9a0d11d7e22217616ee8b00aa447eb0 Mon Sep 17 00:00:00 2001 From: Dave MacFarlane Date: Thu, 25 Sep 2025 12:25:01 -0400 Subject: [PATCH] [Core/Refactor] Do not mangle request URI The BaseRouter/Prefix router stripped off the handled part of the URI before passing it to other handlers. The reasoning was that then the modules could treat the request without regard to the location that LORIS is being served for and act as if it's always the root. However, in practice this causes more problems than it solves. The original URI is lost completely, so middleware, error pages, and http headers that may need it do not have access to it without reconstructing it. This updates the handled part of the URI to go into an "unhandledURI" attribute while leaving the request->getURI untouched. Doing so allows us to access the original URI when needed and if ie. you print $request->getURI() in an error message you will get the correct value. --- modules/api/php/module.class.inc | 2 +- modules/biobank/php/endpoint.class.inc | 2 +- modules/biobank/php/module.class.inc | 4 ++-- modules/biobank/php/preparations.class.inc | 2 +- modules/candidate_profile/php/module.class.inc | 2 +- modules/conflict_resolver/php/module.class.inc | 2 +- modules/instruments/php/module.class.inc | 2 +- modules/statistics/php/charts.class.inc | 6 +++++- php/libraries/Module.class.inc | 8 +++++--- src/Router/BaseRouter.php | 8 +++++--- src/Router/ModuleFileRouter.php | 5 ++++- src/Router/PrefixRouter.php | 8 ++++---- 12 files changed, 31 insertions(+), 20 deletions(-) diff --git a/modules/api/php/module.class.inc b/modules/api/php/module.class.inc index a2a9bf54db8..caf227e69c4 100644 --- a/modules/api/php/module.class.inc +++ b/modules/api/php/module.class.inc @@ -68,7 +68,7 @@ class Module extends \Module } // Requests sent to this module must start with /api/$version - $url = $request->getURI()->getPath(); + $url = $request->getAttribute("unhandledURI")->getPath(); $pieces = []; if (preg_match( "/^\/?(v[0-9]+\.[0-9]+\.[0-9]+[^\/]*)\/(.*)/", diff --git a/modules/biobank/php/endpoint.class.inc b/modules/biobank/php/endpoint.class.inc index e8e9b27c6fe..c314385907b 100644 --- a/modules/biobank/php/endpoint.class.inc +++ b/modules/biobank/php/endpoint.class.inc @@ -95,7 +95,7 @@ abstract class Endpoint ServerRequestInterface $request, RequestHandlerInterface $handler ): ResponseInterface { - $path = trim($request->getURI()->getPath(), "/"); + $path = trim($request->getAttribute("unhandledURI")->getPath(), "/"); $pathparts = explode('/', $path); // Check if sub-handlers are supported diff --git a/modules/biobank/php/module.class.inc b/modules/biobank/php/module.class.inc index c26392eb64e..d1c4893d0be 100644 --- a/modules/biobank/php/module.class.inc +++ b/modules/biobank/php/module.class.inc @@ -65,8 +65,8 @@ class Module extends \Module { $this->logger->debug("Module handle function called"); $resp = parent::handle($request); + $path = $request->getAttribute("unhandledURI")->getPath(); if ($resp->getStatusCode() != 404) { - $path = $request->getURI()->getPath(); if (preg_match('/(\.css)$/', $path) == 1) { $resp = $resp->withHeader( "Content-Type", @@ -84,7 +84,7 @@ class Module extends \Module $this->loris = $request->getAttribute("loris"); $pagename = $this->getName(); - $path = trim($request->getURI()->getPath(), "/"); + $path = trim($path, "/"); if ($path == 'optionsendpoint' || $path == 'poolendpoint' || $path == 'containerendpoint' diff --git a/modules/biobank/php/preparations.class.inc b/modules/biobank/php/preparations.class.inc index 170a60a6fd1..2eebf0c113a 100644 --- a/modules/biobank/php/preparations.class.inc +++ b/modules/biobank/php/preparations.class.inc @@ -132,7 +132,7 @@ class Preparations implements RequestHandlerInterface $this->loris = $request->getAttribute("loris"); $db = $this->loris->getDatabaseConnection(); - $endpoint = $request->getURI()->getPath(); + $endpoint = $request->getAttribute("unhandledURI")->getPath(); $pathparts = explode('/', $endpoint); $db->delete( 'biobank_specimen_preparation', diff --git a/modules/candidate_profile/php/module.class.inc b/modules/candidate_profile/php/module.class.inc index d7e27368f2a..799250a6a40 100644 --- a/modules/candidate_profile/php/module.class.inc +++ b/modules/candidate_profile/php/module.class.inc @@ -23,7 +23,7 @@ class Module extends \Module */ public function handle(ServerRequestInterface $request) : ResponseInterface { - $candIDStr = ltrim($request->getURI()->getPath(), '/'); + $candIDStr = ltrim($request->getAttribute("unhandledURI")->getPath(), '/'); try { $candID = new CandID($candIDStr); $candidate = \Candidate::singleton($candID); diff --git a/modules/conflict_resolver/php/module.class.inc b/modules/conflict_resolver/php/module.class.inc index 45598d8bf9a..168161c2d25 100644 --- a/modules/conflict_resolver/php/module.class.inc +++ b/modules/conflict_resolver/php/module.class.inc @@ -58,7 +58,7 @@ class Module extends \Module */ public function handle(ServerRequestInterface $request) : ResponseInterface { - $path = trim($request->getURI()->getPath(), "/"); + $path = trim($request->getAttribute("unhandledURI")->getPath(), "/"); switch ($path) { case 'unresolved': $handler = new Endpoints\Unresolved($this->loris); diff --git a/modules/instruments/php/module.class.inc b/modules/instruments/php/module.class.inc index eae9bdb8490..b22fd0f1803 100644 --- a/modules/instruments/php/module.class.inc +++ b/modules/instruments/php/module.class.inc @@ -57,7 +57,7 @@ class Module extends \Module return $resp; } - $path = $request->getURI()->getPath(); + $path = $request->getAttribute("unhandledURI")->getPath(); $pathComponents = []; // Breakdown path information from the request. diff --git a/modules/statistics/php/charts.class.inc b/modules/statistics/php/charts.class.inc index a47567bc52a..3d27445e2ac 100644 --- a/modules/statistics/php/charts.class.inc +++ b/modules/statistics/php/charts.class.inc @@ -81,7 +81,11 @@ class Charts extends \NDB_Page // Strip any prefix of '/' to ensure that we don't have an empty string // when splitting the path, then there should be exactly 2 parts left, // "charts", and the endpoint requested. - $url = ltrim($request->getURI()->getPath(), '/'); + $url = ltrim( + $request->getAttribute("unhandledURI")->getURI()->getPath(), + '/' + ); + $pathparts = explode('/', $url); if (count($pathparts) != 2) { return new \LORIS\Http\Response\JSON\NotFound(); diff --git a/php/libraries/Module.class.inc b/php/libraries/Module.class.inc index 77269e0874e..2659d1d288e 100644 --- a/php/libraries/Module.class.inc +++ b/php/libraries/Module.class.inc @@ -271,9 +271,11 @@ abstract class Module extends \LORIS\Router\PrefixRouter public function handle(ServerRequestInterface $request) : ResponseInterface { $this->logger->debug("Module handle function called"); - $resp = parent::handle($request); + $moduleURI = $request->getAttribute("unhandledURI"); + $resp = parent::handle($request); + if ($resp->getStatusCode() != 404) { - $path = $request->getURI()->getPath(); + $path = $moduleURI->getPath(); if (preg_match('/(\.css)$/', $path) == 1) { $resp = $resp->withHeader( "Content-Type", @@ -290,7 +292,7 @@ abstract class Module extends \LORIS\Router\PrefixRouter } $pagename = $this->getName(); - $path = trim($request->getURI()->getPath(), "/"); + $path = trim($moduleURI->getPath(), "/"); if (!empty($path)) { // There is a subpage $pagename = explode("/", $path)[0]; diff --git a/src/Router/BaseRouter.php b/src/Router/BaseRouter.php index fd43ceb4468..74f61d8ef3b 100644 --- a/src/Router/BaseRouter.php +++ b/src/Router/BaseRouter.php @@ -54,8 +54,9 @@ public function __construct( */ public function handle(ServerRequestInterface $request) : ResponseInterface { - $uri = $request->getUri(); - $path = $uri->getPath(); + $request = $request->withAttribute("unhandledURI", $request->getURI()); + $uri = $request->getUri(); + $path = $uri->getPath(); // Replace multiple slashes in the URL with a single slash $path = preg_replace("/\/+/", "/", $path); @@ -157,7 +158,8 @@ public function handle(ServerRequestInterface $request) : ResponseInterface $module->setLogger(new \PSR\Log\NullLogger); } $mr = new ModuleRouter($module); - $request = $request->withURI($suburi); + $request = $request->withAttribute("unhandledURI", $suburi); + return $ehandler->process($request, $mr); } // Legacy from .htaccess. A CandID goes to the timepoint_list diff --git a/src/Router/ModuleFileRouter.php b/src/Router/ModuleFileRouter.php index 151b7357946..82aa7732aaa 100644 --- a/src/Router/ModuleFileRouter.php +++ b/src/Router/ModuleFileRouter.php @@ -76,12 +76,15 @@ public function __construct(\Module $module, string $moduledir, string $subdir, */ public function handle(ServerRequestInterface $request) : ResponseInterface { + $uri = $request->getAttribute("unhandledURI"); + $path = !empty($uri) ? $uri->getPath() : $request->getURI()->getPath(); + $fullpath = ( $this->moduledir . "/" . $this->subdir . "/" - . $request->getURI()->getPath() + . $path ); if (is_file($fullpath)) { diff --git a/src/Router/PrefixRouter.php b/src/Router/PrefixRouter.php index b572fbc42af..f4aececf283 100644 --- a/src/Router/PrefixRouter.php +++ b/src/Router/PrefixRouter.php @@ -92,11 +92,11 @@ protected function stripPrefix(string $prefix, URIInterface $uri) : URIInterface */ public function handle(ServerRequestInterface $request) : ResponseInterface { + $uri = $request->getAttribute("unhandledURI"); foreach ($this->paths as $path => $subhandler) { - if ($this->hasPrefix($path, $request->getURI())) { - // Strip the prefix before passing it to the subhandler. - $newURI = $this->stripPrefix($path, $request->getURI()); - $request = $request->withURI($newURI); + if ($this->hasPrefix($path, $uri)) { + $newURI = $this->stripPrefix($path, $uri); + $request = $request->withAttribute("unhandledURI", $newURI); return $subhandler->handle($request); } }