forcedOrigin = $origin !== '' ? $origin : null; } public function __invoke(ServerRequestInterface $request, callable $next) { $origin = $this->resolveOrigin($request); if (strtoupper($request->getMethod()) === 'OPTIONS') { return $this->preflightResponse($origin); } $response = $next($request); return $this->decorateResponse($response, $origin); } /** * @param ResponseInterface|PromiseInterface $response * @return ResponseInterface|PromiseInterface */ private function decorateResponse($response, string $origin) { if ($response instanceof PromiseInterface) { return $response->then(function ($actual) use ($origin) { return $this->decorateResponse($actual, $origin); }); } if ($response instanceof ResponseInterface) { return $this->applyHeaders($response, $origin); } return $response; } private function preflightResponse(string $origin): ResponseInterface { return $this->applyHeaders( Response::plaintext('')->withStatus(204), $origin ); } private function applyHeaders(ResponseInterface $response, string $origin): ResponseInterface { $response = $response ->withHeader('Access-Control-Allow-Origin', $origin) ->withHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS') ->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization') ->withHeader('Access-Control-Max-Age', '86400') ->withHeader('Vary', 'Origin'); if ($origin !== '*') { $response = $response->withHeader('Access-Control-Allow-Credentials', 'true'); } return $response; } private function resolveOrigin(ServerRequestInterface $request): string { if ($this->forcedOrigin !== null) { return $this->forcedOrigin; } $origin = $request->getHeaderLine('Origin'); return $origin !== '' ? $origin : '*'; } }