public function __invoke($application, $response) { if ($response instanceof JsonResponse && ($payload = $response->getPayload()) instanceof \stdClass) { if ($this->forwardHasHappened && !isset($payload->redirect)) { $payload->url = $application->getPresenter()->link('this'); } $this->httpResponse->addHeader('Vary', 'X-Requested-With'); } }
public function __invoke($application, $response) { if ($response instanceof JsonResponse && ($payload = $response->getPayload()) instanceof \stdClass) { if (!$this->forwardHasHappened && isset($payload->redirect)) { $url = new Http\UrlScript($payload->redirect); $url->setScriptPath($this->httpRequest->url->scriptPath); $httpRequest = new Http\Request($url); if ($this->router->match($httpRequest) !== NULL) { $prop = new Property($application, 'httpRequest'); $prop->setAccessible(TRUE); $prop->setValue($application, $httpRequest); $application->run(); exit; } } elseif ($this->forwardHasHappened && !isset($payload->redirect)) { $payload->redirect = $application->getPresenter()->link('this'); } $this->httpResponse->addHeader('Vary', 'X-Requested-With'); } }
/** * @return Nette\Application\IResponse */ public function run(Application\Request $request) { try { // STARTUP $this->request = $request; $this->payload = new \stdClass(); $this->setParent($this->getParent(), $request->getPresenterName()); if (!$this->httpResponse->isSent()) { $this->httpResponse->addHeader('Vary', 'X-Requested-With'); } $this->initGlobalParameters(); $this->checkRequirements($this->getReflection()); $this->startup(); if (!$this->startupCheck) { $class = $this->getReflection()->getMethod('startup')->getDeclaringClass()->getName(); throw new Nette\InvalidStateException("Method {$class}::startup() or its descendant doesn't call parent::startup()."); } // calls $this->action<Action>() $this->tryCall($this->formatActionMethod($this->action), $this->params); // autoload components foreach ($this->globalParams as $id => $foo) { $this->getComponent($id, FALSE); } if ($this->autoCanonicalize) { $this->canonicalize(); } if ($this->httpRequest->isMethod('head')) { $this->terminate(); } // SIGNAL HANDLING // calls $this->handle<Signal>() $this->processSignal(); // RENDERING VIEW $this->beforeRender(); // calls $this->render<View>() $this->tryCall($this->formatRenderMethod($this->view), $this->params); $this->afterRender(); // save component tree persistent state $this->saveGlobalState(); if ($this->isAjax()) { $this->payload->state = $this->getGlobalState(); } // finish template rendering $this->sendTemplate(); } catch (Application\AbortException $e) { // continue with shutting down if ($this->isAjax()) { try { $hasPayload = (array) $this->payload; unset($hasPayload['state']); if ($this->response instanceof Responses\TextResponse && $this->isControlInvalid()) { $this->snippetMode = TRUE; $this->response->send($this->httpRequest, $this->httpResponse); $this->sendPayload(); } elseif (!$this->response && $hasPayload) { // back compatibility for use terminate() instead of sendPayload() $this->sendPayload(); } } catch (Application\AbortException $e) { } } if ($this->hasFlashSession()) { $this->getFlashSession()->setExpiration($this->response instanceof Responses\RedirectResponse ? '+ 30 seconds' : '+ 3 seconds'); } // SHUTDOWN $this->onShutdown($this, $this->response); $this->shutdown($this->response); return $this->response; } }
/** * Sends response to output. * @return void */ public function send(Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse) { $lastMTime = \filemtime($this->getFile()); // Pokud je povoleno cachovani, podrzim to po dobu 14ti dnu (nebo dokud se soubor zmeni) if ($this->isCachingAllowed()) { $httpResponse->setExpiration(time() + 60 * 60 * 24 * 14); $cachedTime = $httpRequest->getHeader('If-Modified-Since'); if ($cachedTime >= $lastMTime) { $httpResponse->setCode(304); return; } } if (!$this->dontSetContentType) { $httpResponse->setContentType($this->getContentType()); } $httpResponse->addHeader("Last-Modified", gmdate("U", $lastMTime)); $httpResponse->setHeader('Content-Disposition', $this->getContentDisposition() . '; filename="' . $this->getName() . '"'); $filesize = $length = filesize($this->getFile()); //$handle = fopen($this->getFile(), 'r'); if (false && $this->resuming) { $httpResponse->setHeader('Accept-Ranges', 'bytes'); $range = $httpRequest->getHeader('Range'); if ($range !== NULL) { $range = substr($range, 6); // 6 == strlen('bytes=') list($start, $end) = explode('-', $range); if ($start == NULL) { $start = 0; } if ($end == NULL) { $end = $filesize - 1; } if ($start < 0 || $end <= $start || $end > $filesize - 1) { $httpResponse->setCode(416); // requested range not satisfiable return; } $httpResponse->setCode(206); $httpResponse->setHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $filesize); $length = $end - $start + 1; fseek($handle, $start); } else { $httpResponse->setHeader('Content-Range', 'bytes 0-' . ($filesize - 1) . '/' . $filesize); } } $httpResponse->setHeader('Content-Length', $length); readfile($this->getFile()); //while(!feof($handle)) { // echo fread($handle, 4e6); //} //fclose($handle); }
/** * @param IHttpRequest $httpRequest * @param IHttpResponse $httpResponse */ public function send(IHttpRequest $httpRequest, IHttpResponse $httpResponse) { $httpResponse->addHeader(self::HADER_MESSAGE, $this->message); $httpResponse->setCode($this->code); }
/** * @return Nette\Application\IResponse */ protected function process(Nette\Application\Request $request) { // Query output content type ------------------------------------------- // Accept header is comma separated fallback sequence // @todo sequence should be actually sorted by the degree of specificity // @todo make support for version options (ie. application/json;version=2) // see: RESTful Web Services Cookbook page 250 $cTypes = preg_split('/,/', $this->httpRequest->getHeader('Accept'), 0, PREG_SPLIT_NO_EMPTY); foreach ($cTypes as $cType) { // We ignore all the options $cType = preg_replace('/;.*/', '', $cType); if (strcasecmp($cType, 'text/html') === 0 || strcmp($cType, '*/*') === 0) { $this->outputContentType = 'text/html'; $this->httpResponse->setContentType('text/html', 'utf-8'); break; } elseif (strcasecmp($cType, 'application/json') === 0) { $this->outputContentType = 'application/json'; $this->httpResponse->setContentType('application/json', 'utf-8'); break; } } if ($this->outputContentType === NULL) { $this->terminateWithError(self::ERROR_INVALID_REQUEST, "Accept header is missing or not satisfiable.", 406); } // Process Content-Language header ------------------------------------- // Process Authorization header ---------------------------------------- if (($authHeader = $this->httpRequest->getHeader('Authorization')) !== NULL) { if (preg_match('/^Bearer\\s([^\\s,;]+)/i', $authHeader, $matches)) { $tokenHash = $matches[1]; // If connection is not secured return error and invalidate sent token // just in case if (!$request->hasFlag(Nette\Application\Request::SECURED) && $this->isInProductionMode()) { $this->tokenManager->invalidateToken($tokenHash); $this->terminateWithError(self::ERROR_INVALID_REQUEST, "Secured connection required", 400); } if (!$this->attemptLogger->getRemainingAttempts(self::ATTEMPT_IP_TOKEN, $this->httpRequest->getRemoteAddress())) { $this->terminateWithError(OAuth2ResourceProvider::ERROR_MAXIMUM_ATTEMPTS_EXCEEDED, 'Maximum number of authorization attempts exceeded.', 403); } $token = $this->tokenManager->getToken($tokenHash); if (!$token) { $this->attemptLogger->logFail(self::ATTEMPT_IP_TOKEN, $this->httpRequest->getRemoteAddress()); $this->httpResponse->addHeader('WWW-Authenticate', 'Bearer realm="' . $this->link() . '"'); $this->terminateWithError(OAuth2ResourceProvider::ERROR_INVALID_GRANT, 'Given authorization token is not valid.', 401); } $this->attemptLogger->logSuccess(self::ATTEMPT_IP_TOKEN, $this->httpRequest->getRemoteAddress()); if (isset($token->parameters->userIdentity)) { $this->user->login(User::AUTHN_METHOD_INVALID, User::AUTHN_SOURCE_ALL, $token->parameters->userIdentity); } if (isset($token->parameters->client)) { $this->client = $token->parameters->client; } } } // Find request handler ------------------------------------------------ // Gather resource path $parameters = $request->getParameters(); $resourcePath = isset($parameters[self::PARAM_KEY_PATH]) ? trim($parameters[self::PARAM_KEY_PATH]) : NULL; if (!$resourcePath) { $this->terminateWithError(self::ERROR_INVALID_REQUEST, "No resource path given.", 400); } // Request router expects leading slash if ($resourcePath[0] != '/') { $resourcePath = "/{$resourcePath}"; } // Request router: find resource handler try { /** @var vBuilder\RestApi\Request */ $this->resourceRequest = $handlerRequest = $this->requestRouter->createRequest($this->httpRequest->getMethod(), $resourcePath); } catch (RequestException $e) { $this->terminateWithError(self::ERROR_INVALID_REQUEST, $e->getMessage(), $e->getCode() == RequestException::METHOD_NOT_ALLOWED ? 405 : 404); } // Request authorization ----------------------------------------------- $handlerMethodAnnotations = $handlerRequest->getMethodReflection()->getAnnotations(); if (!isset($handlerMethodAnnotations['NoAuthorization']) || !$handlerMethodAnnotations['NoAuthorization'][0]) { if (!$this->client) { $this->httpResponse->addHeader('WWW-Authenticate', 'Bearer realm="' . $this->link() . '"'); $this->terminateWithError(self::ERROR_UNAUTHORIZED, 'Requested resource requires authorization. Please add Authorization header with correct security token.', 401); } } // Decode POST data ---------------------------------------------------- if ($this->httpRequest->isPost()) { $cType = $this->httpRequest->getHeader('Content-Type'); if (strcasecmp($cType, 'application/json') === 0) { try { $this->postData = Nette\Utils\Json::decode(file_get_contents('php://input'), Nette\Utils\Json::FORCE_ARRAY); } catch (Nette\Utils\JsonException $e) { $this->terminateWithError(self::ERROR_INVALID_REQUEST, "Malformed POST data (JSON expected).", 400); } } elseif (strcasecmp($cType, 'application/x-www-form-urlencoded') === 0) { $this->postData = $this->httpRequest->getPost(); } elseif ($cType === NULL) { $this->terminateWithError(self::ERROR_INVALID_REQUEST, "Missing Content-Type header, which is mandatory for POST requests.", 400); } else { $this->terminateWithError(self::ERROR_INVALID_REQUEST, "Request content type of POST data is not supported.", 415); } } // Create resource instance and prepare all dependencies --------------- $class = $handlerRequest->getResourceClassName(); $resource = new $class(); $resource->presenter = $this; $this->systemContainer->callInjects($resource); // Prepare and order invoke parameters --------------------------------- $mReflection = $handlerRequest->getMethodReflection(); $invokeParams = array(); $requestParams = $handlerRequest->getParameters(); $definedParams = $mReflection->getParameters(); $index = 0; foreach ($definedParams as $pReflection) { $index++; // Parameter not given in URL? if (!isset($requestParams[$pReflection->getName()])) { // Default value where available if ($pReflection->isDefaultValueAvailable()) { $invokeParams[$pReflection->getName()] = $pReflection->getDefaultValue(); continue; } $this->terminateWithError(self::ERROR_INVALID_REQUEST, "Missing #{$index} parameter for resource handler {$class}::" . $mReflection->getName() . '().', 400); } $invokeParams[$pReflection->getName()] = $requestParams[$pReflection->getName()]; } // Perform startup $resource->startup(); // Invoke handler method on resource instance $responsePayload = $mReflection->invokeArgs($resource, $invokeParams); // Automatically set HTTP 204 No Content if necessary if ($responsePayload === NULL && $this->httpResponse->getCode() == 200) { $this->httpResponse->setCode(204); } return $responsePayload === NULL ? $this->createResponse() : $this->createResponse($responsePayload); }