Example #1
0
 /**
  * Prepares and returns the array with the FastCGI environment variables.
  *
  * @param \AppserverIo\Psr\HttpMessage\RequestInterface          $request        A request object
  * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext A requests context instance
  *
  * @return array The array with the prepared FastCGI environment variables
  */
 protected function prepareEnvironment(RequestInterface $request, RequestContextInterface $requestContext)
 {
     // prepare the Fast-CGI environment variables
     $environment = array(ServerVars::GATEWAY_INTERFACE => 'FastCGI/1.0', ServerVars::REQUEST_METHOD => $requestContext->getServerVar(ServerVars::REQUEST_METHOD), ServerVars::SCRIPT_FILENAME => $requestContext->getServerVar(ServerVars::SCRIPT_FILENAME), ServerVars::QUERY_STRING => $requestContext->getServerVar(ServerVars::QUERY_STRING), ServerVars::SCRIPT_NAME => $requestContext->getServerVar(ServerVars::SCRIPT_NAME), ServerVars::REQUEST_URI => $requestContext->getServerVar(ServerVars::REQUEST_URI), ServerVars::DOCUMENT_ROOT => $requestContext->getServerVar(ServerVars::DOCUMENT_ROOT), ServerVars::SERVER_PROTOCOL => $requestContext->getServerVar(ServerVars::SERVER_PROTOCOL), ServerVars::HTTPS => $requestContext->getServerVar(ServerVars::HTTPS), ServerVars::SERVER_SOFTWARE => $requestContext->getServerVar(ServerVars::SERVER_SOFTWARE), ServerVars::REMOTE_ADDR => $requestContext->getServerVar(ServerVars::REMOTE_ADDR), ServerVars::REMOTE_PORT => $requestContext->getServerVar(ServerVars::REMOTE_PORT), ServerVars::SERVER_ADDR => $requestContext->getServerVar(ServerVars::SERVER_ADDR), ServerVars::SERVER_PORT => $requestContext->getServerVar(ServerVars::SERVER_PORT), ServerVars::SERVER_NAME => $requestContext->getServerVar(ServerVars::SERVER_NAME));
     // if we found a redirect status, add it to the environment variables
     if ($requestContext->hasServerVar(ServerVars::REDIRECT_STATUS)) {
         $environment[ServerVars::REDIRECT_STATUS] = $requestContext->getServerVar(ServerVars::REDIRECT_STATUS);
     }
     // if we found a redirect URL, add it to the environment variables
     if ($requestContext->hasServerVar(ServerVars::REDIRECT_URL)) {
         $environment[ServerVars::REDIRECT_URL] = $requestContext->getServerVar(ServerVars::REDIRECT_URL);
     }
     // if we found a redirect URI, add it to the environment variables
     if ($requestContext->hasServerVar(ServerVars::REDIRECT_URI)) {
         $environment[ServerVars::REDIRECT_URI] = $requestContext->getServerVar(ServerVars::REDIRECT_URI);
     }
     // if we found a Content-Type header, add it to the environment variables
     if ($request->hasHeader(Protocol::HEADER_CONTENT_TYPE)) {
         $environment['CONTENT_TYPE'] = $request->getHeader(Protocol::HEADER_CONTENT_TYPE);
     }
     // if we found a Content-Length header, add it to the environment variables
     if ($request->hasHeader(Protocol::HEADER_CONTENT_LENGTH)) {
         $environment['CONTENT_LENGTH'] = $request->getHeader(Protocol::HEADER_CONTENT_LENGTH);
     }
     // create an HTTP_ environment variable for each header
     foreach ($request->getHeaders() as $key => $value) {
         $environment['HTTP_' . str_replace('-', '_', strtoupper($key))] = $value;
     }
     // create an HTTP_ environment variable for each server environment variable
     foreach ($requestContext->getEnvVars() as $key => $value) {
         $environment[$key] = $value;
     }
     // return the prepared environment
     return $environment;
 }
Example #2
0
 /**
  * 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']);
         }
     }
 }
Example #3
0
 /**
  * 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;
 }
Example #4
0
 /**
  * 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 $request \AppserverIo\Psr\HttpMessage\ResponseInterface
      */
     // check if shutdown hook is comming
     if (ModuleHooks::SHUTDOWN === $hook) {
         return $this->shutdown($request, $response);
     }
     // if wrong hook is comming do nothing
     if (ModuleHooks::REQUEST_POST !== $hook) {
         return;
     }
     // set request context as member ref
     $this->requestContext = $requestContext;
     // set req and res internally
     $this->request = $request;
     $this->response = $response;
     // check if server handler sais php modules should react on this request as file handler
     if ($requestContext->getServerVar(ServerVars::SERVER_HANDLER) === self::MODULE_NAME) {
         // check if file does not exist
         if (!$requestContext->hasServerVar(ServerVars::SCRIPT_FILENAME)) {
             // send 404
             $response->setStatusCode(404);
             throw new ModuleException(null, 404);
         }
         // init script filename var
         $scriptFilename = $requestContext->getServerVar(ServerVars::SCRIPT_FILENAME);
         /**
          * Check if script name exists on filesystem
          * This is necessary because of seq faults if a non existing file will be required.
          */
         if (!file_exists($scriptFilename)) {
             // send 404
             $response->setStatusCode(404);
             throw new ModuleException(null, 404);
         }
         /**
          * todo: fill up those server vars in future when mod auth is present
          *
          * PHP_AUTH_DIGEST
          * PHP_AUTH_USER
          * PHP_AUTH_PW
          */
         // prepare modules specific server vars
         $this->prepareServerVars();
         // initialize the globals $_SERVER, $_REQUEST, $_POST, $_GET, $_COOKIE, $_FILES and set the headers
         $this->initGlobals();
         // start new php process
         $process = new ProcessThread($scriptFilename, $this->globals, $this->uploadedFiles);
         // start process
         $process->start(PTHREADS_INHERIT_ALL | PTHREADS_ALLOW_HEADERS);
         // wait for process to finish
         $process->join();
         // check if process fatal error occurred so throw module exception because the modules process class
         // is not responsible for set correct headers and messages for error's in module context
         if ($lastError = $process->getLastError()) {
             // check if last error was a fatal one
             if ($lastError['type'] === E_ERROR || $lastError['type'] === E_USER_ERROR) {
                 // check if output buffer was set by the application executed by the php process
                 // so do not override content by exception stack trace
                 if (strlen($errorMessage = $process->getOutputBuffer()) === 0) {
                     $errorMessage = 'PHP Fatal error: ' . $lastError['message'] . ' in ' . $lastError['file'] . ' on line ' . $lastError['line'];
                 }
                 // set internal server error code with error message to exception
                 throw new ModuleException($errorMessage, 500);
             }
         }
         // prepare response
         $this->prepareResponse($process);
         // store the file's contents in the response
         $response->appendBodyStream($process->getOutputBuffer());
         // set response state to be dispatched after this without calling other modules process
         $response->setState(HttpResponseStates::DISPATCH);
     }
 }
Example #5
0
 /**
  * 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 integer                                                $hook           The current hook to process logic for
  *
  * @return boolean
  * @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 default access definitions
     $accesses = $this->accesses;
     // check if there are some volatile access definitions so use them and override global accesses
     if ($requestContext->hasModuleVar(ModuleVars::VOLATILE_ACCESSES)) {
         // reset by volatile accesses
         $accesses = $requestContext->getModuleVar(ModuleVars::VOLATILE_ACCESSES);
     }
     // generally everything is not allowed
     $allowed = false;
     if (isset($accesses['allow'])) {
         // check allow accesses information if something matches
         foreach ($accesses['allow'] as $accessData) {
             // we are optimistic an initial say data will match
             $matchAllow = true;
             // check if accessData matches server vars
             foreach ($accessData as $serverVar => $varPattern) {
                 // check if server var exists
                 if ($requestContext->hasServerVar($serverVar)) {
                     // check if pattern matches
                     if (!preg_match('/' . $varPattern . '/', $requestContext->getServerVar($serverVar))) {
                         $matchAllow = false;
                         // break here if anything not matches
                         break;
                     }
                 }
             }
             if ($matchAllow) {
                 // set allowed flag true
                 $allowed = true;
                 // break here cause' we found an allowed access
                 break;
             }
         }
     }
     if (isset($accesses['deny'])) {
         // check deny accesses information if something matches
         foreach ($accesses['deny'] as $accessData) {
             // initial nothing denies the request
             $matchDeny = false;
             // check if accessData matches server vars
             foreach ($accessData as $serverVar => $varPattern) {
                 // check if server var exists
                 if ($requestContext->hasServerVar($serverVar)) {
                     // check if pattern matches
                     if (preg_match('/' . $varPattern . '/', $requestContext->getServerVar($serverVar))) {
                         $matchDeny = true;
                         // break here if anything matches
                         break;
                     }
                 }
             }
             if ($matchDeny) {
                 // set allowed flag false
                 $allowed = false;
                 // break here cause' we found an allowed access
                 break;
             }
         }
     }
     // check if it's finally not allowed
     if (!$allowed) {
         throw new ModuleException('This request is forbidden', 403);
     }
 }