/** * Copies the values from the request handler back to the passed HTTP response instance. * * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $httpResponse A HTTP response object * * @return void */ public function copyToHttpResponse(ResponseInterface $httpResponse) { // copy response values to the HTTP response $httpResponse->setStatusCode($this->statusCode); $httpResponse->setStatusReasonPhrase($this->statusReasonPhrase); $httpResponse->setVersion($this->version); $httpResponse->setState($this->state); // copy the body content to the HTTP response $httpResponse->appendBodyStream($this->bodyStream); // copy headers to the HTTP response foreach ($this->headers as $headerName => $headerValue) { $httpResponse->addHeader($headerName, $headerValue); } // copy cookies to the HTTP response $httpResponse->setCookies($this->cookies); // query whether an exception has been thrown, if yes, re-throw it if ($this->exception instanceof \Exception) { throw $this->exception; } }
/** * 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) { try { // 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 */ // if false hook is coming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } // check if server handler sais php modules should react on this request as file handler if ($requestContext->getServerVar(ServerVars::SERVER_HANDLER) !== self::MODULE_NAME) { return; } // check if file does not exist if (!$requestContext->hasServerVar(ServerVars::SCRIPT_FILENAME)) { $response->setStatusCode(404); throw new ModuleException(null, 404); } // create a new the FastCGI client/connection $fastCgiConnection = $this->getFastCgiClient($requestContext)->connect(); // prepare the Fast-CGI environment variables $environment = $this->prepareEnvironment($request, $requestContext); // rewind the body stream $bodyStream = $request->getBodyStream(); rewind($bodyStream); // initialize a new FastCGI request instance $fastCgiRequest = $fastCgiConnection->newRequest($environment, $bodyStream); // process the request $rawResponse = $fastCgiConnection->request($fastCgiRequest); // format the raw response $fastCgiResponse = $this->formatResponse($rawResponse->content); // set the Fast-CGI response value in the WebServer response $response->setStatusCode($fastCgiResponse['statusCode']); $response->appendBodyStream($fastCgiResponse['body']); // set the headers found in the Fast-CGI response if (array_key_exists('headers', $fastCgiResponse)) { foreach ($fastCgiResponse['headers'] as $headerName => $headerValue) { // if found an array, e. g. for the Set-Cookie header, we add each value if (is_array($headerValue)) { foreach ($headerValue as $value) { $response->addHeader($headerName, $value, true); } } else { $response->addHeader($headerName, $headerValue); } } } // add the X-Powered-By header $response->addHeader(Protocol::HEADER_X_POWERED_BY, __CLASS__); // set response state to be dispatched after this without calling other modules process $response->setState(HttpResponseStates::DISPATCH); } catch (\Exception $e) { // catch all exceptions throw new ModuleException($e->getMessage(), $e->getCode()); } }
/** * Copies the values from the request handler back to the passed HTTP response instance. * * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $httpResponse A HTTP response object * * @return void */ public function copyToHttpResponse(ResponseInterface $httpResponse) { // create a local copy of the response $servletResponse = $this->servletResponse; // copy response values to the HTTP response $httpResponse->setStatusCode($servletResponse->getStatusCode()); $httpResponse->setStatusReasonPhrase($servletResponse->getStatusReasonPhrase()); $httpResponse->setVersion($servletResponse->getVersion()); $httpResponse->setState($servletResponse->getState()); // copy the body content to the HTTP response $httpResponse->appendBodyStream($servletResponse->getBodyStream()); // copy headers to the HTTP response foreach ($servletResponse->getHeaders() as $headerName => $headerValue) { $httpResponse->addHeader($headerName, $headerValue); } // copy cookies to the HTTP response $httpResponse->setCookies($servletResponse->getCookies()); }
/** * 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; } // make request context available for usage in template $this->requestContext = $requestContext; // query whether the auto index module is available if ($this->getRequestContext()->hasServerVar(ServerVars::SERVER_AUTO_INDEX) === false) { return; } // query whether the auto index module is available and enabled if ($this->getRequestContext()->getServerVar(ServerVars::SERVER_AUTO_INDEX) === ServerVars::VALUE_AUTO_INDEX_OFF) { return; } // stop processing if file handler will not be core in case that location module // has changed the server handler to be proxy, fastcgi or what ever. if ($requestContext->getServerVar(ServerVars::SERVER_HANDLER) !== 'core') { return; } // now load the URL without path information and query string $url = $this->getUrl(); // query whether the URL ends with a slash if ($url[strlen($url) - 1] !== '/') { return; } // query whether an existing path is requested if (is_dir($realPath = $this->getRealPath()) === false) { return; } // load the auto index template if available $autoIndexTemplatePath = $this->getRequestContext()->getServerVar(ServerVars::SERVER_AUTO_INDEX_TEMPLATE_PATH); // query whether a template is configured and available if ($autoIndexTemplatePath && is_file($autoIndexTemplatePath)) { // render errors page ob_start(); require $autoIndexTemplatePath; $autoIndexPage = ob_get_clean(); } else { // initialize the directory listing content $directoryListing = '<tr><th>Name</th><th>Last Modified</th><th>Size</th></tr>'; // query whether if we've parent directory or not if ($this->hasParent($realPath)) { $directoryListing .= sprintf('<tr><td colspan="3"><a href="%s">Parent Directory</a></td></tr>', $this->getParentLink()); } // append the found files + directories to the directory listing foreach ($this->getDirectoryContent($realPath) as $directory) { // append the file or directory to the directory listing $directoryListing .= sprintf('<tr><td><a href="%s">%s</a></td><td>%s</td><td>%d</td></tr>', $this->getLink($directory), $this->getName($directory), $this->getDate($directory), $this->getFilesize($directory)); } // concatenate the elements of the auto index page $autoIndexPage = sprintf('<!DOCTYPE html><html><head><title>Index of %s</title></head><body><h1>Index of %s</h1><table>%s</table></body></html>', $this->getUri(), $this->getUri(), $directoryListing); } // append errors page to response body $response->appendBodyStream($autoIndexPage); // set the Content-Type to text/html $response->addHeader(Protocol::HEADER_CONTENT_TYPE, 'text/html'); // set response state to be dispatched after this without calling other modules process $response->setState(HttpResponseStates::DISPATCH); }
/** * 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) { // In php an interface is, by definition, a fixed contract. It is immutable. // So we have to declare the right ones afterwards... /** * @var $request \AppserverIo\Psr\HttpMessage\RequestInterface */ /** * @var $response \AppserverIo\Psr\HttpMessage\ResponseInterface */ // if false hook is coming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } // check if core module should still handle this request // maybe later on this can be overwritten by another core module for some reasons if ($requestContext->getServerVar(ServerVars::SERVER_HANDLER) !== self::MODULE_NAME) { // stop processing return; } // populates request context for possible script calling based on file handler configurations $this->populateRequestContext($requestContext); // check if file handler is not core module anymore if ($requestContext->getServerVar(ServerVars::SERVER_HANDLER) !== self::MODULE_NAME) { // stop processing return; } // if existing file should be served if ($requestContext->hasServerVar(ServerVars::SCRIPT_FILENAME)) { $scriptFilename = $requestContext->getServerVar(ServerVars::SCRIPT_FILENAME); // get file info $fileInfo = new \SplFileInfo($scriptFilename); // build etag $eTag = sprintf('"%x-%x-%x"', $fileInfo->getInode(), $fileInfo->getSize(), (double) str_pad($fileInfo->getMTime(), 16, '0')); // set last modified header $response->addHeader(Protocol::HEADER_LAST_MODIFIED, gmdate(DATE_RFC822, $fileInfo->getMTime())); // set etag header $response->addHeader(Protocol::HEADER_ETAG, $eTag); // set correct mimetype header $response->addHeader(Protocol::HEADER_CONTENT_TYPE, MimeTypes::getMimeTypeByExtension($fileInfo->getExtension())); // caching checks if ($request->hasHeader(Protocol::HEADER_IF_NONE_MATCH) && $request->getHeader(Protocol::HEADER_IF_NONE_MATCH) === $eTag) { // set not modified status without content $response->setStatusCode(304); } else { // serve file by set body stream to file descriptor stream $response->setBodyStream(fopen($scriptFilename, "r")); } // set response state to be dispatched after this without calling other modules process $response->setState(HttpResponseStates::DISPATCH); // if we got here its maybe a directory index surfing request if $validDir is same as uri // todo: implement directory index view and surfing } else { // for now we will throw a 404 as well here for non existing index files in directory throw new ModuleException(sprintf("The requested URL %s was not found on this server.", parse_url($requestContext->getServerVar(ServerVars::X_REQUEST_URI), PHP_URL_PATH)), 404); } }
/** * 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) { // 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 rewrite maps definitions $rewriteMaps = $this->rewriteMaps; // check if there are some volatile rewrite map definitions so add them if ($requestContext->hasModuleVar(ModuleVars::VOLATILE_REWRITE_MAPS)) { $volatileRewriteMaps = $requestContext->getModuleVar(ModuleVars::VOLATILE_REWRITE_MAPS); // merge rewrite maps $rewriteMaps = array_merge($volatileRewriteMaps, $this->rewriteMaps); } // check protocol to be either http or https when secure is going on $protocol = 'http://'; if ($requestContext->getServerVar(ServerVars::HTTPS) === ServerVars::VALUE_HTTPS_ON) { $protocol = 'https://'; } // get clean request path without query string etc... $requestPath = parse_url($requestContext->getServerVar(ServerVars::X_REQUEST_URI), PHP_URL_PATH); // init all rewrite mappers by types and do look up foreach ($rewriteMaps as $rewriteMapType => $rewriteMapParams) { // Include the requested hostname as a param, some mappers might need it $rewriteMapParams['headerHost'] = $request->getHeader(Protocol::HEADER_HOST); // Same for the protocol $rewriteMapParams['protocol'] = $protocol; // Get ourselves a rewriteMapper of the right type $rewriteMapper = new $rewriteMapType($rewriteMapParams); // lookup by request path if ($targetUrl = $rewriteMapper->lookup($requestPath)) { // set enhance uri to response $response->addHeader(Protocol::HEADER_LOCATION, $targetUrl); // send redirect status $response->setStatusCode(301); // add header to be sure that is was us $response->addHeader('X-Rewritten-By', __CLASS__); // set response state to be dispatched after this without calling other modules process $response->setState(HttpResponseStates::DISPATCH); // We found something, stop the loop break; } } return true; }
/** * 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; }
/** * Will prepare a response for a redirect. * This includes setting the new target, the appropriate status code and dispatching it to break the * module chain * * @param \AppserverIo\Server\Interfaces\RequestContextInterface $requestContext The request's context * @param \AppserverIo\Psr\HttpMessage\ResponseInterface $response The response instance to be prepared * * @return void */ protected function prepareRedirect($requestContext, ResponseInterface $response) { // if we got a specific status code we have to filter it and apply it if possible $statusCode = 301; $proposedStatusCode = $this->sortedFlags[RuleFlags::REDIRECT]; if (is_numeric($proposedStatusCode) && $proposedStatusCode >= 300 && $proposedStatusCode < 400) { $statusCode = $proposedStatusCode; } // there might be work to be done depending on whether or not we got a complete URL if ($this->type === 'relative') { $newTarget = $requestContext->getServerVar(ServerVars::REQUEST_SCHEME); $newTarget .= '://'; $newTarget .= $requestContext->getServerVar(ServerVars::HTTP_HOST); $this->target = $newTarget . $this->getTarget(); } // set enhance uri to response $response->addHeader(Protocol::HEADER_LOCATION, $this->target); // send redirect status $response->setStatusCode($statusCode); // set response state to be dispatched after this without calling other modules process $response->setState(HttpResponseStates::DISPATCH); }
/** * Process servlet request. * * @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) { // if false hook is coming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } // check if we are the handler that has to process this request if ($requestContext->getServerVar(ServerVars::SERVER_HANDLER) !== $this->getModuleName()) { return; } // load the application associated with this request $application = $this->findRequestedApplication($requestContext); $application->registerClassLoaders(); // check if the application has already been connected if ($application->isConnected() === false) { throw new \Exception(sprintf('Application %s has not connected yet', $application->getName()), 503); } // create a copy of the valve instances $valves = $this->valves; $handlers = $this->handlers; // create a new request instance from the HTTP request $servletRequest = new Request(); $servletRequest->injectHandlers($handlers); $servletRequest->injectHttpRequest($request); $servletRequest->injectServerVars($requestContext->getServerVars()); $servletRequest->init(); // initialize servlet response $servletResponse = new Response(); $servletResponse->init(); // load the session and the authentication manager $sessionManager = $application->search(SessionManagerInterface::IDENTIFIER); $authenticationManager = $application->search(AuthenticationManagerInterface::IDENTIFIER); // inject the sapplication and servlet response $servletRequest->injectContext($application); $servletRequest->injectResponse($servletResponse); $servletRequest->injectSessionManager($sessionManager); $servletRequest->injectAuthenticationManager($authenticationManager); // prepare the request instance $servletRequest->prepare(); // initialize static request and application context RequestHandler::$requestContext = $servletRequest; RequestHandler::$applicationContext = $application; // process the valves foreach ($valves as $valve) { $valve->invoke($servletRequest, $servletResponse); if ($servletRequest->isDispatched() === true) { break; } } // copy response values to the HTTP response $response->setState($servletResponse->getState()); $response->setVersion($servletResponse->getVersion()); $response->setStatusCode($servletResponse->getStatusCode()); $response->setStatusReasonPhrase($servletResponse->getStatusReasonPhrase()); // copy the body content to the HTTP response $response->appendBodyStream($servletResponse->getBodyStream()); // copy headers to the HTTP response foreach ($servletResponse->getHeaders() as $headerName => $headerValue) { $response->addHeader($headerName, $headerValue); } // copy cookies to the HTTP response $response->setCookies($servletResponse->getCookies()); // append the servlet engine's signature $response->addHeader(Protocol::HEADER_X_POWERED_BY, get_class($this), true); // set response state to be dispatched after this without calling other modules process $response->setState(HttpResponseStates::DISPATCH); }
/** * Process servlet request. * * @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) { try { // if false hook is coming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } // check if we are the handler that has to process this request if ($requestContext->getServerVar(ServerVars::SERVER_HANDLER) !== $this->getModuleName()) { return; } // initialize servlet session, request + response $servletRequest = new Request(); $servletRequest->injectHttpRequest($request); $servletRequest->injectServerVars($requestContext->getServerVars()); // initialize the parts foreach ($request->getParts() as $part) { $servletRequest->addPart(Part::fromHttpRequest($part)); } // set the body content if we can find one if ($request->getHeader(HttpProtocol::HEADER_CONTENT_LENGTH) > 0) { $servletRequest->setBodyStream($request->getBodyContent()); } // prepare the servlet request $this->prepareServletRequest($servletRequest); // initialize the servlet response with the Http response values $servletResponse = new Response(); $servletRequest->injectResponse($servletResponse); // load the application associated with this request $application = $this->findRequestedApplication($requestContext); // prepare and set the applications context path $servletRequest->setContextPath($contextPath = '/' . $application->getName()); $servletRequest->setServletPath(str_replace($contextPath, '', $servletRequest->getServletPath())); // prepare the base modifier which allows our apps to provide a base URL $webappsDir = $this->getServerContext()->getServerConfig()->getDocumentRoot(); $relativeRequestPath = strstr($servletRequest->getServerVar(ServerVars::DOCUMENT_ROOT), $webappsDir); $proposedBaseModifier = str_replace($webappsDir, '', $relativeRequestPath); if (strpos($proposedBaseModifier, $contextPath) === 0) { $servletRequest->setBaseModifier(''); } else { $servletRequest->setBaseModifier($contextPath); } // initialize the request handler instance $dispatched = false; $applicationName = $application->getName(); while ($dispatched === false) { if ($this->requestHandlers[$applicationName][$i = rand(0, 9)]->isWaiting()) { $this->requestHandlers[$applicationName][$i]->handleRequest($servletRequest, $servletResponse); $dispatched = true; break; } } // copy the values from the servlet response back to the HTTP response $response->setStatusCode($servletResponse->getStatusCode()); $response->setStatusReasonPhrase($servletResponse->getStatusReasonPhrase()); $response->setVersion($servletResponse->getVersion()); $response->setState($servletResponse->getState()); // append the content to the body stream $response->appendBodyStream($servletResponse->getBodyStream()); // transform the servlet headers back into HTTP headers $headers = array(); foreach ($servletResponse->getHeaders() as $name => $header) { $headers[$name] = $header; } // set the headers as array (because we don't know if we have to use the append flag) $response->setHeaders($headers); // copy the servlet response cookies back to the HTTP response foreach ($servletResponse->getCookies() as $cookie) { $response->addCookie(unserialize($cookie)); } // set response state to be dispatched after this without calling other modules process $response->setState(HttpResponseStates::DISPATCH); } catch (ModuleException $me) { throw $me; } catch (\Exception $e) { throw new ModuleException($e, 500); } }
/** * 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) { try { // 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 */ // if false hook is coming do nothing if (ModuleHooks::REQUEST_POST !== $hook) { return; } // check if server handler sais php modules should react on this request as file handler if ($requestContext->getServerVar(ServerVars::SERVER_HANDLER) !== self::MODULE_NAME) { return; } // check if file does not exist if ($requestContext->hasServerVar(ServerVars::SCRIPT_FILENAME) === false) { $response->setStatusCode(404); throw new ModuleException(null, 404); } // initialize the event loop $loop = EventLoopFactory::create(); // invoke the FastCGI request $this->getFastCgiClient($requestContext, $loop)->done(function (Client $client) use($request, $requestContext, $response) { // initialize the environment $env = $this->prepareEnvironment($request, $requestContext); // initialize the request $req = $client->newRequest(new RequestParameters($env), new \Crunch\FastCGI\ReaderWriter\StringReader($request->getBodyContent())); // initialize the response handler $responseHandler = function ($res) use($response) { // explode status code, headers and body from the FastCGI response list($statusCode, $headers, $body) = $this->formatResponse($res->getContent()->read()); // set the headers found in the Fast-CGI response foreach ($headers as $headerName => $headerValue) { // if found an array, e. g. for the Set-Cookie header, we add each value if (is_array($headerValue)) { foreach ($headerValue as $value) { $response->addHeader($headerName, $value, true); } } else { $response->addHeader($headerName, $headerValue); } } // initialize the HTTP response with the values $response->appendBodyStream($body); $response->setStatusCode($statusCode); }; // finally send the FastCGI request $x = $client->sendRequest($req)->then($responseHandler); // close the FastCGI connection promise\all([$x])->then(function () use($client) { $client->close(); }); }); // start the event loop $loop->run(); // append the X-Powered-By header $response->addHeader(Protocol::HEADER_X_POWERED_BY, __CLASS__, true); // set response state to be dispatched after this without calling other modules process $response->setState(HttpResponseStates::DISPATCH); } catch (\Exception $e) { // catch all exceptions throw new ModuleException($e->getMessage(), $e->getCode()); } }