Skip to content
Snippets Groups Projects
Commit 613e2c99 authored by Jaime Pérez's avatar Jaime Pérez
Browse files

Stop intercepting exceptions in www/module.php.

The module.php file is the way we allow modules to have their own pages. All those are executed and presented to the user via this script. However, if an exception is thrown by a module, that exception will be captured directly by the module.php script. This prevents us from adding more logic to exception handling, adds code duplication, and makes the exception handling non-uniform, since we could end up handling the same exception differently depending on whether it was thrown by a module or by a regular page.

Now we no longer intercept exceptions in module.php, allowing the exception handler to kick in. That way exceptions are always handled uniformly, and we can also implement additional logic that we may want (i.e. adding a hook to the exception handler so that modules could handle exceptions the way they want).
parent 64142de9
No related branches found
No related tags found
No related merge requests found
...@@ -38,145 +38,134 @@ $mimeTypes = array( ...@@ -38,145 +38,134 @@ $mimeTypes = array(
'xhtml' => 'application/xhtml+xml', 'xhtml' => 'application/xhtml+xml',
); );
try { if (empty($_SERVER['PATH_INFO'])) {
throw new SimpleSAML_Error_NotFound('No PATH_INFO to module.php');
if (empty($_SERVER['PATH_INFO'])) { }
throw new SimpleSAML_Error_NotFound('No PATH_INFO to module.php');
}
$url = $_SERVER['PATH_INFO']; $url = $_SERVER['PATH_INFO'];
assert('substr($url, 0, 1) === "/"'); assert('substr($url, 0, 1) === "/"');
/* clear the PATH_INFO option, so that a script can detect whether it is called with anything following the /* clear the PATH_INFO option, so that a script can detect whether it is called with anything following the
*'.php'-ending. *'.php'-ending.
*/ */
unset($_SERVER['PATH_INFO']); unset($_SERVER['PATH_INFO']);
$modEnd = strpos($url, '/', 1); $modEnd = strpos($url, '/', 1);
if ($modEnd === false) { if ($modEnd === false) {
// the path must always be on the form /module/ // the path must always be on the form /module/
throw new SimpleSAML_Error_NotFound('The URL must at least contain a module name followed by a slash.'); throw new SimpleSAML_Error_NotFound('The URL must at least contain a module name followed by a slash.');
} }
$module = substr($url, 1, $modEnd - 1); $module = substr($url, 1, $modEnd - 1);
$url = substr($url, $modEnd + 1); $url = substr($url, $modEnd + 1);
if ($url === false) { if ($url === false) {
$url = ''; $url = '';
} }
if (!SimpleSAML\Module::isModuleEnabled($module)) { if (!SimpleSAML\Module::isModuleEnabled($module)) {
throw new SimpleSAML_Error_NotFound('The module \''.$module.'\' was either not found, or wasn\'t enabled.'); throw new SimpleSAML_Error_NotFound('The module \''.$module.'\' was either not found, or wasn\'t enabled.');
} }
/* Make sure that the request isn't suspicious (contains references to current directory or parent directory or /* Make sure that the request isn't suspicious (contains references to current directory or parent directory or
* anything like that. Searching for './' in the URL will detect both '../' and './'. Searching for '\' will detect * anything like that. Searching for './' in the URL will detect both '../' and './'. Searching for '\' will detect
* attempts to use Windows-style paths. * attempts to use Windows-style paths.
*/ */
if (strpos($url, '\\') !== false) { if (strpos($url, '\\') !== false) {
throw new SimpleSAML_Error_BadRequest('Requested URL contained a backslash.'); throw new SimpleSAML_Error_BadRequest('Requested URL contained a backslash.');
} elseif (strpos($url, './') !== false) { } elseif (strpos($url, './') !== false) {
throw new SimpleSAML_Error_BadRequest('Requested URL contained \'./\'.'); throw new SimpleSAML_Error_BadRequest('Requested URL contained \'./\'.');
} }
$moduleDir = SimpleSAML\Module::getModuleDir($module).'/www/'; $moduleDir = SimpleSAML\Module::getModuleDir($module).'/www/';
// check for '.php/' in the path, the presence of which indicates that another php-script should handle the request // check for '.php/' in the path, the presence of which indicates that another php-script should handle the request
for ($phpPos = strpos($url, '.php/'); $phpPos !== false; $phpPos = strpos($url, '.php/', $phpPos + 1)) { for ($phpPos = strpos($url, '.php/'); $phpPos !== false; $phpPos = strpos($url, '.php/', $phpPos + 1)) {
$newURL = substr($url, 0, $phpPos + 4); $newURL = substr($url, 0, $phpPos + 4);
$param = substr($url, $phpPos + 4); $param = substr($url, $phpPos + 4);
if (is_file($moduleDir.$newURL)) { if (is_file($moduleDir.$newURL)) {
/* $newPath points to a normal file. Point execution to that file, and /* $newPath points to a normal file. Point execution to that file, and
* save the remainder of the path in PATH_INFO. * save the remainder of the path in PATH_INFO.
*/ */
$url = $newURL; $url = $newURL;
$_SERVER['PATH_INFO'] = $param; $_SERVER['PATH_INFO'] = $param;
break; break;
}
} }
}
$path = $moduleDir.$url; $path = $moduleDir.$url;
if ($path[strlen($path) - 1] === '/') { if ($path[strlen($path) - 1] === '/') {
// path ends with a slash - directory reference. Attempt to find index file in directory // path ends with a slash - directory reference. Attempt to find index file in directory
foreach ($indexFiles as $if) { foreach ($indexFiles as $if) {
if (file_exists($path.$if)) { if (file_exists($path.$if)) {
$path .= $if; $path .= $if;
break; break;
}
} }
} }
}
if (is_dir($path)) { if (is_dir($path)) {
/* Path is a directory - maybe no index file was found in the previous step, or maybe the path didn't end with /* Path is a directory - maybe no index file was found in the previous step, or maybe the path didn't end with
* a slash. Either way, we don't do directory listings. * a slash. Either way, we don't do directory listings.
*/ */
throw new SimpleSAML_Error_NotFound('Directory listing not available.'); throw new SimpleSAML_Error_NotFound('Directory listing not available.');
} }
if (!file_exists($path)) {
// file not found
SimpleSAML\Logger::info('Could not find file \''.$path.'\'.');
throw new SimpleSAML_Error_NotFound('The URL wasn\'t found in the module.');
}
if (preg_match('#\.php$#D', $path)) { if (!file_exists($path)) {
// PHP file - attempt to run it // file not found
SimpleSAML\Logger::info('Could not find file \''.$path.'\'.');
throw new SimpleSAML_Error_NotFound('The URL wasn\'t found in the module.');
}
/* In some environments, $_SERVER['SCRIPT_NAME'] is already set with $_SERVER['PATH_INFO']. Check for that case, if (preg_match('#\.php$#D', $path)) {
* and append script name only if necessary. // PHP file - attempt to run it
*
* Contributed by Travis Hegner.
*/
$script = "/$module/$url";
if (stripos($_SERVER['SCRIPT_NAME'], $script) === false) {
$_SERVER['SCRIPT_NAME'] .= '/'.$module.'/'.$url;
}
require($path); /* In some environments, $_SERVER['SCRIPT_NAME'] is already set with $_SERVER['PATH_INFO']. Check for that case,
exit(); * and append script name only if necessary.
*
* Contributed by Travis Hegner.
*/
$script = "/$module/$url";
if (stripos($_SERVER['SCRIPT_NAME'], $script) === false) {
$_SERVER['SCRIPT_NAME'] .= '/'.$module.'/'.$url;
} }
// some other file type - attempt to serve it require($path);
exit();
}
// some other file type - attempt to serve it
// find MIME type for file, based on extension // find MIME type for file, based on extension
$contentType = null; $contentType = null;
if (preg_match('#\.([^/\.]+)$#D', $path, $type)) { if (preg_match('#\.([^/\.]+)$#D', $path, $type)) {
$type = strtolower($type[1]); $type = strtolower($type[1]);
if (array_key_exists($type, $mimeTypes)) { if (array_key_exists($type, $mimeTypes)) {
$contentType = $mimeTypes[$type]; $contentType = $mimeTypes[$type];
}
} }
}
if ($contentType === null) { if ($contentType === null) {
/* We were unable to determine the MIME type from the file extension. Fall back to mime_content_type (if it /* We were unable to determine the MIME type from the file extension. Fall back to mime_content_type (if it
* exists). * exists).
*/ */
if (function_exists('mime_content_type')) { if (function_exists('mime_content_type')) {
$contentType = mime_content_type($path); $contentType = mime_content_type($path);
} else { } else {
// mime_content_type doesn't exist. Return a default MIME type // mime_content_type doesn't exist. Return a default MIME type
SimpleSAML\Logger::warning('Unable to determine mime content type of file: '.$path); SimpleSAML\Logger::warning('Unable to determine mime content type of file: '.$path);
$contentType = 'application/octet-stream'; $contentType = 'application/octet-stream';
}
} }
}
$contentLength = sprintf('%u', filesize($path)); // force filesize to an unsigned number $contentLength = sprintf('%u', filesize($path)); // force filesize to an unsigned number
header('Content-Type: '.$contentType);
header('Content-Length: '.$contentLength);
header('Cache-Control: public,max-age=86400');
header('Expires: '.gmdate('D, j M Y H:i:s \G\M\T', time() + 10 * 60));
header('Last-Modified: '.gmdate('D, j M Y H:i:s \G\M\T', filemtime($path)));
readfile($path); header('Content-Type: '.$contentType);
exit(); header('Content-Length: '.$contentLength);
} catch (SimpleSAML_Error_Error $e) { header('Cache-Control: public,max-age=86400');
header('Expires: '.gmdate('D, j M Y H:i:s \G\M\T', time() + 10 * 60));
header('Last-Modified: '.gmdate('D, j M Y H:i:s \G\M\T', filemtime($path)));
$e->show(); readfile($path);
} catch (Exception $e) {
$e = new SimpleSAML_Error_Error('UNHANDLEDEXCEPTION', $e);
$e->show();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment