/** * Implements module logic for given hook * * @param \AppserverIo\Psr\HttpMessage\RequestInterface $request A request object * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $response A response object * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext A requests context instance * @param int $hook The current hook to process logic for * * @return bool * @throws \AppserverIo\Server\Exceptions\ModuleException */ public function process(RequestInterface $request, ResponseInterface $response, RequestContextInterface $requestContext, $hook) { /** * @var $request \AppserverIo\Psr\HttpMessage\RequestInterface */ /** * @var $response \AppserverIo\Psr\HttpMessage\ResponseInterface */ // if false hook is comming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } // load the locations $locations = $this->locations; // check if there are some volatile location definitions so use them and override global locations if ($requestContext->hasModuleVar(ModuleVars::VOLATILE_LOCATIONS)) { $locations = $requestContext->getModuleVar(ModuleVars::VOLATILE_LOCATIONS); } // query whether we've locations configured or not if (sizeof($locations) === 0) { return; } // initialize the array for the handlers $handlers = array(); // initialize the array for the headers $headers = array(); // load the actual request URI without query string $uriWithoutQueryString = $requestContext->getServerVar(ServerVars::X_REQUEST_URI); // process the all locations found for this request foreach ($locations as $location) { // query whether the location matches the acutal request URI if (preg_match('/' . $location['condition'] . '/', $uriWithoutQueryString)) { // query whether the location has file handlers configured for the actual URI if (isset($location['params'])) { // iterate over all params and try to set as server var via mapping foreach ($location['params'] as $paramName => $paramValue) { // check if server var mapping exists if (isset($this->paramServerVarsMap[$paramName])) { // check if documentRoot is changed if ($this->paramServerVarsMap[$paramName] === ServerVars::DOCUMENT_ROOT) { // check if relative path is given and make is absolute by using cwd as prefix if (substr($paramValue, 0, 1) !== "/") { $paramValue = getcwd() . DIRECTORY_SEPARATOR . $paramValue; } } // set server var $requestContext->setServerVar($this->paramServerVarsMap[$paramName], $paramValue); } } } // query whether the location has file handlers configured for the actual URI if (isset($location['handlers'])) { $handlers = array_merge($handlers, $location['handlers']); } // merge headers information to volatile headers if exists if (isset($location['headers']) && is_array($location['headers'])) { $volatileHeaders = array(); if ($requestContext->hasModuleVar(ModuleVars::VOLATILE_HEADERS)) { $volatileHeaders = $requestContext->getModuleVar(ModuleVars::VOLATILE_HEADERS); } $headers = array_merge_recursive($volatileHeaders, $location['headers']); } } } // add the handlers we have (if any) if (sizeof($handlers) !== 0) { $requestContext->setModuleVar(ModuleVars::VOLATILE_HANDLERS, $handlers); } // add the headers we have (if any) if (sizeof($headers) !== 0) { $requestContext->setModuleVar(ModuleVars::VOLATILE_HEADERS, $headers); } }
/** * Implements module logic for given hook * * @param \AppserverIo\Psr\HttpMessage\RequestInterface $request A request object * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $response A response object * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext A requests context instance * @param int $hook The current hook to process logic for * * @return bool * @throws \AppserverIo\Server\Exceptions\ModuleException */ public function process(RequestInterface $request, ResponseInterface $response, RequestContextInterface $requestContext, $hook) { // if false hook is coming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } // set req and res object internally $this->request = $request; $this->response = $response; // get server context to local var $serverContext = $this->getServerContext(); // Get the authentications locally so we do not mess with inter-request configuration $authenticationSets = array(); // check if there are some volatile rewrite map definitions so add them if ($requestContext->hasModuleVar(ModuleVars::VOLATILE_AUTHENTICATIONS)) { $authenticationSets[] = $requestContext->getModuleVar(ModuleVars::VOLATILE_AUTHENTICATIONS); } // get the global authentications last, as volatile authentications are prefered here as more specific configurations can lessen security $authenticationSets[] = $this->authentications; // get system logger $systemLogger = $serverContext->getLogger(LoggerUtils::SYSTEM); // check authentication information if something matches foreach ($authenticationSets as $authenticationSet) { foreach ($authenticationSet as $uriPattern => $data) { // check if pattern matches uri if (preg_match('/' . $uriPattern . '/', $requestContext->getServerVar(ServerVars::X_REQUEST_URI))) { try { // append the document root to the authentication params $data['documentRoot'] = $requestContext->getServerVar(ServerVars::DOCUMENT_ROOT); // create a local type instance, initialize and authenticate the request $typeInstance = $this->getAuthenticationInstance($uriPattern, $data); $typeInstance->init($request, $response); $typeInstance->authenticate($response); // set authenticated username as a server var $requestContext->setServerVar(ServerVars::REMOTE_USER, $typeInstance->getUsername()); // break out because everything is fine at this point break; } catch (\Exception $e) { // log exception as warning to not end up with a 500 response which is not wanted here $systemLogger->warning($e->getMessage()); } // throw exception for auth required throw new ModuleException(null, 401); } } } }
/** * Expands request context on given request constellation (uri) based on file handler configuration * * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext The request context instance * * @return void */ public function populateRequestContext(RequestContextInterface $requestContext) { // get local refs $serverContext = $this->getServerContext(); // get document root $documentRoot = $requestContext->getServerVar(ServerVars::DOCUMENT_ROOT); // load the default handlers $handlers = $serverContext->getServerConfig()->getHandlers(); // check if there are some volatile location definitions so use them and merge with global locations if ($requestContext->hasModuleVar(ModuleVars::VOLATILE_HANDLERS)) { $handlers = array_merge($handlers, $requestContext->getModuleVar(ModuleVars::VOLATILE_HANDLERS)); } // get uri without querystring // Just make sure that you check for the existence of the query string first, as it might not be set $uriWithoutQueryString = parse_url($requestContext->getServerVar(ServerVars::X_REQUEST_URI), PHP_URL_PATH); // check if uri without query string is just "/" if ($uriWithoutQueryString === '/' && $requestContext->hasServerVar(ServerVars::SERVER_WELCOME_PAGE_TEMPLATE_PATH)) { // in this case we will set welcome page template to be errors template if ($welcomePageTemplate = $requestContext->getServerVar(ServerVars::SERVER_WELCOME_PAGE_TEMPLATE_PATH)) { $requestContext->setServerVar(ServerVars::SERVER_ERRORS_PAGE_TEMPLATE_PATH, $welcomePageTemplate); } } // split all path parts got from uri without query string $pathParts = explode('/', $uriWithoutQueryString); // init vars for path parsing $possibleValidPathExtension = ''; $possibleValidPath = ''; $pathInfo = ''; $validDir = null; $scriptName = null; $scriptFilename = null; // note: only if file extension hits a filehandle info it will be possible to set path info etc... // iterate through all dirs beginning at 1 because 0 is always empty in this case for ($i = 1; $i < count($pathParts); ++$i) { // check if no script name was found yet if (!$scriptName) { // append valid path $possibleValidPath .= DIRECTORY_SEPARATOR . $pathParts[$i]; // get possible extension $possibleValidPathExtension = pathinfo($possibleValidPath, PATHINFO_EXTENSION); // check if dir does not exists if (!is_dir($documentRoot . $possibleValidPath)) { // check if its not a existing file if (!is_file($documentRoot . $possibleValidPath)) { // check if file handler is defined for that virtual file if (isset($handlers['.' . $possibleValidPathExtension])) { // set script name for further processing as script aspect $scriptName = $possibleValidPath; } } else { // set script name $scriptName = $possibleValidPath; // set script filename $scriptFilename = $documentRoot . $scriptName; } } else { // save valid dir for indexed surfing later on $validDir = $possibleValidPath; } } else { // else build up path info $pathInfo .= DIRECTORY_SEPARATOR . $pathParts[$i]; } } // set special server var for requested file $requestContext->setServerVar(ServerVars::REQUEST_FILENAME, $documentRoot . $possibleValidPath); // set specific script name server var if exists if ($scriptName) { $requestContext->setServerVar(ServerVars::SCRIPT_NAME, $scriptName); } // check if requested file is on filesystem and set it to be valid script filename if ($scriptFilename) { $requestContext->setServerVar(ServerVars::SCRIPT_FILENAME, $scriptFilename); } // if path info is set put it into server vars if (strlen($pathInfo) > 0) { // set path info vars $requestContext->setServerVar(ServerVars::PATH_INFO, $pathInfo); $requestContext->setServerVar(ServerVars::PATH_TRANSLATED, $documentRoot . $pathInfo); } // first check if wildcard file handler was registered if (isset($handlers['.*'])) { // set wildcard filehandler which will overload all specific filehandlers at this point $possibleValidPathExtension = '*'; } // check if file handler is defined for that script and expand request context if (isset($handlers['.' . $possibleValidPathExtension])) { // set the file handler to use for modules being able to react on this setting $requestContext->setServerVar(ServerVars::SERVER_HANDLER, $handlers['.' . $possibleValidPathExtension]['name']); // if file handler params are given, set them as module var if (isset($handlers['.' . $possibleValidPathExtension]['params'])) { $requestContext->setModuleVar(ModuleVars::VOLATILE_FILE_HANDLER_VARIABLES, $handlers['.' . $possibleValidPathExtension]['params']); } } }
/** * Implements module logic for given hook * * @param \AppserverIo\Psr\HttpMessage\RequestInterface $request A request object * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $response A response object * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext A requests context instance * @param int $hook The current hook to process logic for * * @return bool * @throws \AppserverIo\Server\Exceptions\ModuleException */ public function process(RequestInterface $request, ResponseInterface $response, RequestContextInterface $requestContext, $hook) { // if false hook is coming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } // set req and res object internally $this->request = $request; $this->response = $response; // get server context to local var $serverContext = $this->getServerContext(); // Get the authentications locally so we do not mess with inter-request configuration $authenticationSets = array(); // check if there are some volatile rewrite map definitions so add them if ($requestContext->hasModuleVar(ModuleVars::VOLATILE_AUTHENTICATIONS)) { $authenticationSets[] = $requestContext->getModuleVar(ModuleVars::VOLATILE_AUTHENTICATIONS); } // get the global authentications last, as volatile authentications are prefered here as more specific configurations can lessen security $authenticationSets[] = $this->authentications; // get system logger $systemLogger = $serverContext->getLogger(LoggerUtils::SYSTEM); // check authentication information if something matches foreach ($authenticationSets as $authenticationSet) { foreach ($authenticationSet as $uriPattern => $data) { // check if pattern matches uri if (preg_match('/' . $uriPattern . '/', $requestContext->getServerVar(ServerVars::X_REQUEST_URI))) { // set type Instance to local ref $typeInstance = $this->getAuthenticationInstance($uriPattern, $data); // check if auth header is not set in coming request headers if (!$request->hasHeader(Protocol::HEADER_AUTHORIZATION)) { // send header for challenge authentication against client $response->addHeader(Protocol::HEADER_WWW_AUTHENTICATE, $typeInstance->getAuthenticateHeader()); // throw exception for auth required throw new ModuleException(null, 401); } // init type instance by request $typeInstance->init($request->getHeader(Protocol::HEADER_AUTHORIZATION), $request->getMethod()); try { // check if auth works if ($typeInstance->authenticate()) { // set server vars $requestContext->setServerVar(ServerVars::REMOTE_USER, $typeInstance->getUsername()); // break out because everything is fine at this point break; } } catch (\Exception $e) { // log exception as warning to not end up with a 500 response which is not wanted here $systemLogger->warning($e->getMessage()); } // send header for challenge authentication against client $response->addHeader(Protocol::HEADER_WWW_AUTHENTICATE, $typeInstance->getAuthenticateHeader()); // throw exception for auth required throw new ModuleException(null, 401); } } } }
/** * Implement's module logic for given hook * * @param \AppserverIo\Psr\HttpMessage\RequestInterface $request A request object * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $response A response object * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext A requests context instance * @param int $hook The current hook to process logic for * * @return bool * @throws \AppserverIo\Server\Exceptions\ModuleException */ public function process(RequestInterface $request, ResponseInterface $response, RequestContextInterface $requestContext, $hook) { // In php an interface is, by definition, a fixed contract. It is immutable. // So we have to declair the right ones afterwards... /** * @var $request \AppserverIo\Psr\HttpMessage\RequestInterface */ /** * @var $response \AppserverIo\Psr\HttpMessage\ResponseInterface */ // if false hook is comming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } // set req and res object internally $this->request = $request; $this->response = $response; // get document root $documentRoot = $requestContext->getServerVar(ServerVars::DOCUMENT_ROOT); // get url $url = parse_url($requestContext->getServerVar(ServerVars::X_REQUEST_URI), PHP_URL_PATH); // get query string with asterisk $queryString = strstr($requestContext->getServerVar(ServerVars::X_REQUEST_URI), '?'); // get read path to requested uri $realPath = $documentRoot . $url; // check if it's a dir if (is_dir($realPath) || $url === '/') { // check if uri has trailing slash if (substr($url, -1) !== '/') { // set enhance uri with trailing slash to response $response->addHeader(Protocol::HEADER_LOCATION, $url . '/' . $queryString); // send redirect status $response->setStatusCode(301); // set response state to be dispatched after this without calling other modules process $response->setState(HttpResponseStates::DISPATCH); } else { // check directory index definitions foreach ($this->getDirectoryIndex() as $index) { // check if defined index files are found in directory if (is_file($realPath . $index)) { // reset uri with indexed filename $requestContext->setServerVar(ServerVars::X_REQUEST_URI, $url . $index . $queryString); // break out if index file was found return true; } } } } return true; }
/** * Initiates the module * * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext The request's context * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $response The response instance * @param array $serverBackreferences Server backreferences * * @throws \InvalidArgumentException * * @return boolean */ public function apply(RequestContextInterface $requestContext, ResponseInterface $response, array $serverBackreferences) { // First of all we have to resolve the target string with the backreferences of the matching condition // Separate the keys from the values so we can use them in str_replace // And also mix in the server's backreferences for good measure $this->matchingBackreferences = array_merge($this->matchingBackreferences, $serverBackreferences); $backreferenceHolders = array_keys($this->matchingBackreferences); $backreferenceValues = array_values($this->matchingBackreferences); // If we got a target map (flag "M") we have to resolve the target string we have to use first // The following checks will be treated as an additional condition if (array_key_exists(RuleFlags::MAP, $this->sortedFlags) && !empty($this->sortedFlags[RuleFlags::MAP])) { // Get our map key for better readability $mapKey = str_replace(array_keys($this->matchingBackreferences), $this->matchingBackreferences, $this->sortedFlags[RuleFlags::MAP]); // Still here? That sounds good. Get the needed target string now if (isset($this->target[$mapKey])) { $this->target = $this->target[$mapKey]; } else { // Empty string, we will do nothing with this rule $this->target = ''; // Also clear any L-flag we might find, we could not find what we are looking for so we should not end if (array_key_exists(RuleFlags::LAST, $this->sortedFlags)) { unset($this->sortedFlags[RuleFlags::LAST]); } } } // Back to our rule... // If the target string is empty we do not have to do anything if (!empty($this->target)) { // Just make sure that you check for the existence of the query string first, as it might not be set $queryFreeRequestUri = $requestContext->getServerVar(ServerVars::X_REQUEST_URI); if ($requestContext->hasServerVar(ServerVars::QUERY_STRING)) { $queryFreeRequestUri = str_replace('?' . $requestContext->getServerVar(ServerVars::QUERY_STRING), '', $queryFreeRequestUri); // Set the "redirect" query string as a backup as we might change the original $requestContext->setServerVar('REDIRECT_QUERY_STRING', $requestContext->getServerVar(ServerVars::QUERY_STRING)); } $requestContext->setServerVar('REDIRECT_URL', $queryFreeRequestUri); // Substitute the backreferences in our operation $this->target = str_replace($backreferenceHolders, $backreferenceValues, $this->target); // We have to find out what type of rule we got here if (is_readable($this->target)) { // We have an absolute file path! $this->type = 'absolute'; // Set the REQUEST_FILENAME path $requestContext->setServerVar(ServerVars::REQUEST_FILENAME, $this->target); } elseif (filter_var($this->target, FILTER_VALIDATE_URL) !== false) { // We have a complete URL! $this->type = 'url'; } else { // Last but not least we might have gotten a relative path (most likely) // Build up the REQUEST_FILENAME from DOCUMENT_ROOT and X_REQUEST_URI (without the query string) $this->type = 'relative'; // Setting the X_REQUEST_URI for internal communication // Requested uri always has to begin with a slash $this->target = '/' . ltrim($this->target, '/'); $requestContext->setServerVar(ServerVars::X_REQUEST_URI, $this->target); // Only change the query string if we have one in our target string if (strpos($this->target, '?') !== false) { $requestContext->setServerVar(ServerVars::QUERY_STRING, substr(strstr($this->target, '?'), 1)); } } // do we have to make a redirect? // if so we have to have to set the status code accordingly and dispatch the response if (array_key_exists(RuleFlags::REDIRECT, $this->sortedFlags)) { $this->prepareRedirect($requestContext, $response); } // Lets tell them that we successfully made a redirect $requestContext->setServerVar(ServerVars::REDIRECT_STATUS, '200'); } // If we got the "LAST"-flag we have to end here, so return false if (array_key_exists(RuleFlags::LAST, $this->sortedFlags)) { return false; } // Still here? That sounds good return true; }
/** * Implements module logic for given hook * * @param \AppserverIo\Psr\HttpMessage\RequestInterface $request A request object * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $response A response object * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext A requests context instance * @param int $hook The current hook to process logic for * * @return bool * @throws \AppserverIo\Server\Exceptions\ModuleException */ public function process(RequestInterface $request, ResponseInterface $response, RequestContextInterface $requestContext, $hook) { // if false hook is comming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } // set req and res object internally $this->request = $request; $this->response = $response; $virtualHosts = $this->getServerContext()->getServerConfig()->getVirtualHosts(); $serverName = $requestContext->getServerVar(ServerVars::SERVER_NAME); // check if current host matches any virtual host configuration if (isset($virtualHosts[$serverName])) { // read out params $params = $virtualHosts[$serverName]['params']; // iterate over all params and try to set as server var via mapping foreach ($params as $paramName => $paramValue) { // check if server var mapping exists if (isset($this->paramServerVarsMap[$paramName])) { // check if documentRoot is changed if ($this->paramServerVarsMap[$paramName] === ServerVars::DOCUMENT_ROOT) { // check if relative path is given and make is absolute by using cwd as prefix if (substr($paramValue, 0, 1) !== "/") { $paramValue = getcwd() . DIRECTORY_SEPARATOR . $paramValue; } } // set server var $requestContext->setServerVar($this->paramServerVarsMap[$paramName], $paramValue); } } // Add the headers we have (if any) to the configuration's headers pool if (!empty($virtualHosts[$serverName]['headers'])) { // Set the rewrites we encountered as a temporary module var $requestContext->setModuleVar(ModuleVars::VOLATILE_HEADERS, $virtualHosts[$serverName]['headers']); } // Add the rewrites we have (if any) to the configuration's rewrite pool if (!empty($virtualHosts[$serverName]['rewrites'])) { // Set the rewrites we encountered as a temporary module var $requestContext->setModuleVar(ModuleVars::VOLATILE_REWRITES, $virtualHosts[$serverName]['rewrites']); } // Add the environment vars we have (if any) to the configuration's environment variable pool if (!empty($virtualHosts[$serverName]['environmentVariables'])) { // Set the environment variables we encountered as a temporary module var $requestContext->setModuleVar(ModuleVars::VOLATILE_ENVIRONMENT_VARIABLES, $virtualHosts[$serverName]['environmentVariables']); } // Add the accesses (if any) to the configuration's access pool if (!empty($virtualHosts[$serverName]['accesses'])) { // Set the environment variables we encountered as a temporary module var $requestContext->setModuleVar(ModuleVars::VOLATILE_ACCESSES, $virtualHosts[$serverName]['accesses']); } // add the analytics (if any) to the configuration's analytics pool if (!empty($virtualHosts[$serverName]['analytics'])) { // set the analytics we encountered as a temporary module var $requestContext->setModuleVar(ModuleVars::VOLATILE_ANALYTICS, $virtualHosts[$serverName]['analytics']); } // Add the locations we have (if any) to the configuration's location pool if (!empty($virtualHosts[$serverName]['locations'])) { // Set the locations we encountered as a temporary module var $requestContext->setModuleVar(ModuleVars::VOLATILE_LOCATIONS, $virtualHosts[$serverName]['locations']); } // Add the rewriteMaps we have (if any) to the configuration's rewriteMaps pool if (!empty($virtualHosts[$serverName]['rewriteMaps'])) { // Set the rewriteMaps we encountered as a temporary module var $requestContext->setModuleVar(ModuleVars::VOLATILE_REWRITE_MAPS, $virtualHosts[$serverName]['rewriteMaps']); } // Add the authentications we have (if any) to the configuration's authentications pool if (!empty($virtualHosts[$serverName]['authentications'])) { // Set the authentications we encountered as a temporary module var $requestContext->setModuleVar(ModuleVars::VOLATILE_AUTHENTICATIONS, $virtualHosts[$serverName]['authentications']); } } }