142 lines
3.4 KiB
PHP
142 lines
3.4 KiB
PHP
<?php
|
|
|
|
namespace Illuminate\Http\Middleware;
|
|
|
|
use Closure;
|
|
use Fruitcake\Cors\CorsService;
|
|
use Illuminate\Contracts\Container\Container;
|
|
use Illuminate\Http\Request;
|
|
|
|
class HandleCors
|
|
{
|
|
/**
|
|
* The container instance.
|
|
*
|
|
* @var \Illuminate\Contracts\Container\Container
|
|
*/
|
|
protected $container;
|
|
|
|
/**
|
|
* The CORS service instance.
|
|
*
|
|
* @var \Fruitcake\Cors\CorsService
|
|
*/
|
|
protected $cors;
|
|
|
|
/**
|
|
* All of the registered skip callbacks.
|
|
*
|
|
* @var array<int, \Closure(\Illuminate\Http\Request): bool>
|
|
*/
|
|
protected static $skipCallbacks = [];
|
|
|
|
/**
|
|
* Create a new middleware instance.
|
|
*
|
|
* @param \Illuminate\Contracts\Container\Container $container
|
|
* @param \Fruitcake\Cors\CorsService $cors
|
|
*/
|
|
public function __construct(Container $container, CorsService $cors)
|
|
{
|
|
$this->container = $container;
|
|
$this->cors = $cors;
|
|
}
|
|
|
|
/**
|
|
* Handle the incoming request.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @param \Closure $next
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function handle($request, Closure $next)
|
|
{
|
|
foreach (static::$skipCallbacks as $callback) {
|
|
if ($callback($request)) {
|
|
return $next($request);
|
|
}
|
|
}
|
|
|
|
if (! $this->hasMatchingPath($request)) {
|
|
return $next($request);
|
|
}
|
|
|
|
$this->cors->setOptions($this->container['config']->get('cors', []));
|
|
|
|
if ($this->cors->isPreflightRequest($request)) {
|
|
$response = $this->cors->handlePreflightRequest($request);
|
|
|
|
$this->cors->varyHeader($response, 'Access-Control-Request-Method');
|
|
|
|
return $response;
|
|
}
|
|
|
|
$response = $next($request);
|
|
|
|
if ($request->getMethod() === 'OPTIONS') {
|
|
$this->cors->varyHeader($response, 'Access-Control-Request-Method');
|
|
}
|
|
|
|
return $this->cors->addActualRequestHeaders($response, $request);
|
|
}
|
|
|
|
/**
|
|
* Get the path from the configuration to determine if the CORS service should run.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return bool
|
|
*/
|
|
protected function hasMatchingPath(Request $request): bool
|
|
{
|
|
$paths = $this->getPathsByHost($request->getHost());
|
|
|
|
foreach ($paths as $path) {
|
|
if ($path !== '/') {
|
|
$path = trim($path, '/');
|
|
}
|
|
|
|
if ($request->fullUrlIs($path) || $request->is($path)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get the CORS paths for the given host.
|
|
*
|
|
* @param string $host
|
|
* @return array
|
|
*/
|
|
protected function getPathsByHost(string $host)
|
|
{
|
|
$paths = $this->container['config']->get('cors.paths', []);
|
|
|
|
return $paths[$host] ?? array_filter($paths, function ($path) {
|
|
return is_string($path);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Register a callback that instructs the middleware to be skipped.
|
|
*
|
|
* @param \Closure $callback
|
|
* @return void
|
|
*/
|
|
public static function skipWhen(Closure $callback)
|
|
{
|
|
static::$skipCallbacks[] = $callback;
|
|
}
|
|
|
|
/**
|
|
* Flush the middleware's global state.
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function flushState()
|
|
{
|
|
static::$skipCallbacks = [];
|
|
}
|
|
}
|