Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
localhost {
php_server {
worker index.php
}

log {
level ERROR
output stderr
}

encode gzip

redir /.well-known/carddav /remote.php/dav 301
redir /.well-known/caldav /remote.php/dav 301

# Rule: Maps most RFC 8615 compliant well-known URIs to our main frontend controller (/index.php) by default
@wellKnown {
path "/.well-known/"
not {
path /.well-known/acme-challenge
path /.well-known/pki-validation
}
}
rewrite @wellKnown /index.php

rewrite /ocm-provider/ /index.php

@forbidden {
path /.htaccess
path /data/*
path /config/*
path /db_structure
path /.xml
path /README
path /3rdparty/*
path /lib/*
path /templates/*
path /occ
path /build
path /tests
path /console.php
path /autotest
path /issue
path /indi
path /db_
path /console
}
respond @forbidden 404
}
2 changes: 2 additions & 0 deletions cron.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
try {
require_once __DIR__ . '/lib/base.php';

OC::init();

if (isset($argv[1]) && ($argv[1] === '-h' || $argv[1] === '--help')) {
echo 'Description:
Run the background job routine
Expand Down
165 changes: 92 additions & 73 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,90 +19,109 @@
use OCP\Template\ITemplateManager;
use Psr\Log\LoggerInterface;

try {
require_once __DIR__ . '/lib/base.php';
require_once __DIR__ . '/lib/base.php';

OC::handleRequest();
} catch (ServiceUnavailableException $ex) {
Server::get(LoggerInterface::class)->error($ex->getMessage(), [
'app' => 'index',
'exception' => $ex,
]);

//show the user a detailed error page
Server::get(ITemplateManager::class)->printExceptionErrorPage($ex, 503);
} catch (HintException $ex) {
$handler = static function () {
try {
Server::get(ITemplateManager::class)->printErrorPage($ex->getMessage(), $ex->getHint(), 503);
} catch (Exception $ex2) {
OC::init();
OC::handleRequest();
} catch (ServiceUnavailableException $ex) {
Server::get(LoggerInterface::class)->error($ex->getMessage(), [
'app' => 'index',
'exception' => $ex,
]);

//show the user a detailed error page
Server::get(ITemplateManager::class)->printExceptionErrorPage($ex, 503);
} catch (HintException $ex) {
try {
Server::get(ITemplateManager::class)->printErrorPage($ex->getMessage(), $ex->getHint(), 503);
} catch (Exception $ex2) {
try {
Server::get(LoggerInterface::class)->error($ex->getMessage(), [
'app' => 'index',
'exception' => $ex,
]);
Server::get(LoggerInterface::class)->error($ex2->getMessage(), [
'app' => 'index',
'exception' => $ex2,
]);
} catch (Throwable $e) {
// no way to log it properly - but to avoid a white page of death we try harder and ignore this one here
}

//show the user a detailed error page
Server::get(ITemplateManager::class)->printExceptionErrorPage($ex, 500);
}
} catch (LoginException $ex) {
$request = Server::get(IRequest::class);
/**
* Routes with the @CORS annotation and other API endpoints should
* not return a webpage, so we only print the error page when html is accepted,
* otherwise we reply with a JSON array like the SecurityMiddleware would do.
*/
if (stripos($request->getHeader('Accept'), 'html') === false) {
http_response_code(401);
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['message' => $ex->getMessage()]);
exit();
}
Server::get(ITemplateManager::class)->printErrorPage($ex->getMessage(), $ex->getMessage(), 401);
} catch (MaxDelayReached $ex) {
$request = Server::get(IRequest::class);
/**
* Routes with the @CORS annotation and other API endpoints should
* not return a webpage, so we only print the error page when html is accepted,
* otherwise we reply with a JSON array like the BruteForceMiddleware would do.
*/
if (stripos($request->getHeader('Accept'), 'html') === false) {
http_response_code(429);
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['message' => $ex->getMessage()]);
exit();
}
http_response_code(429);
Server::get(ITemplateManager::class)->printGuestPage('core', '429');
} catch (Exception $ex) {
Server::get(LoggerInterface::class)->error($ex->getMessage(), [
'app' => 'index',
'exception' => $ex,
]);

//show the user a detailed error page
Server::get(ITemplateManager::class)->printExceptionErrorPage($ex, 500);
} catch (Error $ex) {
try {
Server::get(LoggerInterface::class)->error($ex->getMessage(), [
'app' => 'index',
'exception' => $ex,
]);
Server::get(LoggerInterface::class)->error($ex2->getMessage(), [
'app' => 'index',
'exception' => $ex2,
]);
} catch (Throwable $e) {
// no way to log it properly - but to avoid a white page of death we try harder and ignore this one here
}
} catch (Error $e) {
http_response_code(500);
header('Content-Type: text/plain; charset=utf-8');
print("Internal Server Error\n\n");
print("The server encountered an internal error and was unable to complete your request.\n");
print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n");
print("More details can be found in the webserver log.\n");

//show the user a detailed error page
throw $ex;
}
Server::get(ITemplateManager::class)->printExceptionErrorPage($ex, 500);
}
} catch (LoginException $ex) {
$request = Server::get(IRequest::class);
/**
* Routes with the @CORS annotation and other API endpoints should
* not return a webpage, so we only print the error page when html is accepted,
* otherwise we reply with a JSON array like the SecurityMiddleware would do.
*/
if (stripos($request->getHeader('Accept'), 'html') === false) {
http_response_code(401);
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['message' => $ex->getMessage()]);
exit();
}
Server::get(ITemplateManager::class)->printErrorPage($ex->getMessage(), $ex->getMessage(), 401);
} catch (MaxDelayReached $ex) {
$request = Server::get(IRequest::class);
/**
* Routes with the @CORS annotation and other API endpoints should
* not return a webpage, so we only print the error page when html is accepted,
* otherwise we reply with a JSON array like the BruteForceMiddleware would do.
*/
if (stripos($request->getHeader('Accept'), 'html') === false) {
http_response_code(429);
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['message' => $ex->getMessage()]);
exit();
}
http_response_code(429);
Server::get(ITemplateManager::class)->printGuestPage('core', '429');
} catch (Exception $ex) {
Server::get(LoggerInterface::class)->error($ex->getMessage(), [
'app' => 'index',
'exception' => $ex,
]);
};

//show the user a detailed error page
Server::get(ITemplateManager::class)->printExceptionErrorPage($ex, 500);
} catch (Error $ex) {
try {
Server::get(LoggerInterface::class)->error($ex->getMessage(), [
'app' => 'index',
'exception' => $ex,
]);
} catch (Error $e) {
http_response_code(500);
header('Content-Type: text/plain; charset=utf-8');
print("Internal Server Error\n\n");
print("The server encountered an internal error and was unable to complete your request.\n");
print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n");
print("More details can be found in the webserver log.\n");
if (function_exists('frankenphp_handle_request')) {
$maxRequests = (int)($_SERVER['MAX_REQUESTS'] ?? 0);
for ($nbRequests = 0; !$maxRequests || $nbRequests < $maxRequests; ++$nbRequests) {
$keepRunning = \frankenphp_handle_request($handler);

throw $ex;
// Call the garbage collector to reduce the chances of it being triggered in the middle of a page generation
gc_collect_cycles();

if (!$keepRunning) {
break;
}
}
Server::get(ITemplateManager::class)->printExceptionErrorPage($ex, 500);
} else {
$handler();
}
72 changes: 41 additions & 31 deletions lib/base.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,6 @@ class OC {
* the app path list is empty or contains an invalid path
*/
public static function initPaths(): void {
if (defined('PHPUNIT_CONFIG_DIR')) {
self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
} elseif (defined('PHPUNIT_RUN') && PHPUNIT_RUN && is_dir(OC::$SERVERROOT . '/tests/config/')) {
self::$configDir = OC::$SERVERROOT . '/tests/config/';
} elseif ($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
self::$configDir = rtrim($dir, '/') . '/';
} else {
self::$configDir = OC::$SERVERROOT . '/config/';
}
self::$config = new \OC\Config(self::$configDir);

OC::$SUBURI = str_replace('\\', '/', substr(realpath($_SERVER['SCRIPT_FILENAME'] ?? ''), strlen(OC::$SERVERROOT)));
/**
* FIXME: The following lines are required because we can't yet instantiate
Expand Down Expand Up @@ -145,7 +134,7 @@ public static function initPaths(): void {
// Resolve /nextcloud to /nextcloud/ to ensure to always have a trailing
// slash which is required by URL generation.
if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT
&& substr($_SERVER['REQUEST_URI'], -1) !== '/') {
&& substr($_SERVER['REQUEST_URI'], -1) !== '/') {
header('Location: ' . \OC::$WEBROOT . '/');
exit();
}
Expand All @@ -165,6 +154,7 @@ public static function initPaths(): void {
OC::$APPSROOTS[] = ['path' => OC::$SERVERROOT . '/apps', 'url' => '/apps', 'writable' => true];
}


if (empty(OC::$APPSROOTS)) {
throw new \RuntimeException('apps directory not found! Please put the Nextcloud apps folder in the Nextcloud folder'
. '. You can also configure the location in the config.php file.');
Expand Down Expand Up @@ -643,12 +633,7 @@ private static function addSecurityHeaders(): void {
}
}

public static function init(): void {
// First handle PHP configuration and copy auth headers to the expected
// $_SERVER variable before doing anything Server object related
self::setRequiredIniValues();
self::handleAuthHeaders();

public static function boot(): void {
// prevent any XML processing from loading external entities
libxml_set_external_entity_loader(static function () {
return null;
Expand All @@ -671,15 +656,32 @@ public static function init(): void {
self::$composerAutoloader = require_once OC::$SERVERROOT . '/lib/composer/autoload.php';
self::$composerAutoloader->setApcuPrefix(null);

// setup 3rdparty autoloader
$vendorAutoLoad = OC::$SERVERROOT . '/3rdparty/autoload.php';
if (!file_exists($vendorAutoLoad)) {
throw new \RuntimeException('Composer autoloader not found, unable to continue. Check the folder "3rdparty". Running "git submodule update --init" will initialize the git submodule that handles the subfolder "3rdparty".');
}
require_once $vendorAutoLoad;

$loaderEnd = microtime(true);

// load configs
if (defined('PHPUNIT_CONFIG_DIR')) {
self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/';
} elseif (defined('PHPUNIT_RUN') && PHPUNIT_RUN && is_dir(OC::$SERVERROOT . '/tests/config/')) {
self::$configDir = OC::$SERVERROOT . '/tests/config/';
} elseif ($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
self::$configDir = rtrim($dir, '/') . '/';
} else {
self::$configDir = OC::$SERVERROOT . '/config/';
}
self::$config = new \OC\Config(self::$configDir);

// Enable lazy loading if activated
\OC\AppFramework\Utility\SimpleContainer::$useLazyObjects = (bool)self::$config->getValue('enable_lazy_objects', true);

try {
self::initPaths();
// setup 3rdparty autoloader
$vendorAutoLoad = OC::$SERVERROOT . '/3rdparty/autoload.php';
if (!file_exists($vendorAutoLoad)) {
throw new \RuntimeException('Composer autoloader not found, unable to continue. Check the folder "3rdparty". Running "git submodule update --init" will initialize the git submodule that handles the subfolder "3rdparty".');
}
require_once $vendorAutoLoad;
} catch (\RuntimeException $e) {
if (!self::$CLI) {
http_response_code(503);
Expand All @@ -689,15 +691,24 @@ public static function init(): void {
print($e->getMessage());
exit();
}
$loaderEnd = microtime(true);

// Enable lazy loading if activated
\OC\AppFramework\Utility\SimpleContainer::$useLazyObjects = (bool)self::$config->getValue('enable_lazy_objects', true);
//$eventLogger = Server::get(\OCP\Diagnostics\IEventLogger::class);
//$eventLogger->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
//$eventLogger->start('init', 'Initialize');
}

public static function init(): void {
// First handle PHP configuration and copy auth headers to the expected
// $_SERVER variable before doing anything Server object related
self::setRequiredIniValues();
self::handleAuthHeaders();

// setup the basic server
// set up the basic server
self::$server = new \OC\Server(\OC::$WEBROOT, self::$config);
self::$server->boot();

$loaderStart = microtime(true);

try {
$profiler = new BuiltInProfiler(
Server::get(IConfig::class),
Expand All @@ -713,8 +724,7 @@ public static function init(): void {
}

$eventLogger = Server::get(\OCP\Diagnostics\IEventLogger::class);
$eventLogger->log('autoloader', 'Autoloader', $loaderStart, $loaderEnd);
$eventLogger->start('boot', 'Initialize');
$eventLogger->start('init', 'Initialize');

// Override php.ini and log everything if we're troubleshooting
if (self::$config->getValue('loglevel') === ILogger::DEBUG) {
Expand Down Expand Up @@ -1285,4 +1295,4 @@ protected static function tryAppAPILogin(OCP\IRequest $request): bool {
}
}

OC::init();
OC::boot();
2 changes: 2 additions & 0 deletions lib/private/Route/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ public function create($name,
* @return array
*/
public function findMatchingRoute(string $url): array {
$url = str_replace('index.php', '', $url);
$this->eventLogger->start('route:match', 'Match route');
if (str_starts_with($url, '/apps/')) {
// empty string / 'apps' / $app / rest of the route
Expand Down Expand Up @@ -277,6 +278,7 @@ public function findMatchingRoute(string $url): array {
$this->loadRoutes();
}


$this->eventLogger->start('route:url:match', 'Symfony url matcher call');
$matcher = new UrlMatcher($this->root, $this->context);
try {
Expand Down
Loading
Loading