private function respond($fileInfo, Request $request, Response $response) { // If the file doesn't exist don't bother to do anything else so the // HTTP server can send a 404 and/or allow handlers further down the chain // a chance to respond. if (empty($fileInfo->exists)) { return; } switch ($request->getMethod()) { case "GET": case "HEAD": break; case "OPTIONS": $response->setStatus(HTTP_STATUS["OK"]); $response->setHeader("Allow", "GET, HEAD, OPTIONS"); $response->setHeader("Accept-Ranges", "bytes"); $response->setHeader("Aerys-Generic-Response", "enable"); return; default: $response->setStatus(HTTP_STATUS["METHOD_NOT_ALLOWED"]); $response->setHeader("Allow", "GET, HEAD, OPTIONS"); $response->setHeader("Aerys-Generic-Response", "enable"); return; } $precondition = $this->checkPreconditions($request, $fileInfo->mtime, $fileInfo->etag); switch ($precondition) { case self::PRECOND_NOT_MODIFIED: $response->setStatus(HTTP_STATUS["NOT_MODIFIED"]); $lastModifiedHttpDate = \gmdate('D, d M Y H:i:s', $fileInfo->mtime) . " GMT"; $response->setHeader("Last-Modified", $lastModifiedHttpDate); if ($fileInfo->etag) { $response->setHeader("Etag", $fileInfo->etag); } $response->end(); return; case self::PRECOND_FAILED: $response->setStatus(HTTP_STATUS["PRECONDITION_FAILED"]); $response->end(); return; case self::PRECOND_IF_RANGE_FAILED: // Return this so the resulting generator will be auto-resolved return $this->doNonRangeResponse($fileInfo, $response); } if (!($rangeHeader = $request->getHeader("Range"))) { // Return this so the resulting generator will be auto-resolved return $this->doNonRangeResponse($fileInfo, $response); } if ($range = $this->normalizeByteRanges($fileInfo->size, $rangeHeader)) { // Return this so the resulting generator will be auto-resolved return $this->doRangeResponse($range, $fileInfo, $response); } // If we're still here this is the only remaining response we can send $response->setStatus(HTTP_STATUS["REQUESTED_RANGE_NOT_SATISFIABLE"]); $response->setHeader("Content-Range", "*/{$fileInfo->size}"); $response->end(); }
public function __invoke(Request $req, Response $res) { $headers = $req->getAllHeaders(); unset($headers["accept-encoding"]); $connection = $headers["connection"]; unset($headers["connection"]); foreach ($connection as $value) { foreach (explode(",", strtolower($value)) as $type) { $type = trim($type); if ($type == "upgrade") { $headers["connection"][0] = "upgrade"; } else { unset($headers[$type]); } } } if ($this->headers) { if (is_callable($this->headers)) { $headers = ($this->headers)($headers); } else { $headers = $this->headers + $headers; } } $promise = $this->client->request((new \Amp\Artax\Request())->setMethod($req->getMethod())->setUri($this->target . $req->getUri())->setAllHeaders($headers)->setBody((yield $req->getBody()))); // no async sending possible :-( [because of redirects] $promise->watch(function ($update) use($req, $res, &$hasBody, &$status, &$zlib) { list($type, $data) = $update; if ($type == Notify::RESPONSE_HEADERS) { $headers = array_change_key_case($data["headers"], CASE_LOWER); foreach ($data["headers"] as $header => $values) { foreach ($values as $value) { $res->addHeader($header, $value); } } $res->setStatus($status = $data["status"]); $res->setReason($data["reason"]); if (isset($headers["content-encoding"]) && strcasecmp(trim(current($headers["content-encoding"])), 'gzip') === 0) { $zlib = inflate_init(ZLIB_ENCODING_GZIP); } $hasBody = true; } if ($type == Notify::RESPONSE_BODY_DATA) { if ($zlib) { $data = inflate_add($zlib, $data); } $res->stream($data); } if ($type == Notify::RESPONSE) { if (!$hasBody) { foreach ($data->getAllHeaders() as $header => $values) { foreach ($values as $value) { $res->addHeader($header, $value); } } $res->setStatus($status = $data->getStatus()); $res->setReason($data->getReason()); } if ($status == 101) { $req->setLocalVar("aerys.reverse.socket", $update["export_socket"]()); } $res->end($zlib ? inflate_add("", ZLIB_FINISH) : null); } }); (yield $promise); }