mirror of
https://github.com/codeigniter4/CodeIgniter4.git
synced 2025-02-20 11:44:28 +08:00
feat: add HTTP\Cors class
This commit is contained in:
parent
39210beb13
commit
fd25f15255
102
app/Config/Cors.php
Normal file
102
app/Config/Cors.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
/**
|
||||
* Cross-Origin Resource Sharing (CORS) Configuration
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||
*/
|
||||
class Cors extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* Origins for the `Access-Control-Allow-Origin` header.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
||||
*
|
||||
* E.g.:
|
||||
* - ['http://localhost:8080']
|
||||
* - ['https://www.example.com']
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $allowedOrigins = [];
|
||||
|
||||
/**
|
||||
* Origin regex patterns for the `Access-Control-Allow-Origin` header.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
||||
*
|
||||
* NOTE: You must set `\A` (beginning with) and `\z` (ending with) in patterns,
|
||||
* otherwise you will give access from unintended external domains.
|
||||
* E.g., if you set '!\w+\.example\.com!', 'www.example.com.evil.site'
|
||||
* is permitted.
|
||||
*
|
||||
* E.g.:
|
||||
* - ['!\Ahttps://\w+\.example\.com\z!']
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $allowedOriginsPatterns = [];
|
||||
|
||||
/**
|
||||
* Weather to send the `Access-Control-Allow-Credentials` header.
|
||||
*
|
||||
* The Access-Control-Allow-Credentials response header tells browsers whether
|
||||
* the server allows cross-origin HTTP requests to include credentials.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
|
||||
*/
|
||||
public bool $supportsCredentials = false;
|
||||
|
||||
/**
|
||||
* Set headers to allow.
|
||||
*
|
||||
* The Access-Control-Allow-Headers response header is used in response to
|
||||
* a preflight request which includes the Access-Control-Request-Headers to
|
||||
* indicate which HTTP headers can be used during the actual request.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $allowedHeaders = [];
|
||||
|
||||
/**
|
||||
* Set headers to expose.
|
||||
*
|
||||
* The Access-Control-Expose-Headers response header allows a server to
|
||||
* indicate which response headers should be made available to scripts running
|
||||
* in the browser, in response to a cross-origin request.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $exposedHeaders = [];
|
||||
|
||||
/**
|
||||
* Set methods to allow.
|
||||
*
|
||||
* The Access-Control-Allow-Methods response header specifies one or more
|
||||
* methods allowed when accessing a resource in response to a preflight
|
||||
* request.
|
||||
*
|
||||
* E.g.:
|
||||
* - ['GET', 'POST', 'PUT', 'DELETE']
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $allowedMethods = [];
|
||||
|
||||
/**
|
||||
* Set how many seconds the results of a preflight request can be cached.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
|
||||
*/
|
||||
public int $maxAge = 7200;
|
||||
}
|
219
system/HTTP/Cors.php
Normal file
219
system/HTTP/Cors.php
Normal file
@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\HTTP;
|
||||
|
||||
use CodeIgniter\Exceptions\ConfigException;
|
||||
use Config\Cors as CorsConfig;
|
||||
|
||||
/**
|
||||
* Cross-Origin Resource Sharing (CORS)
|
||||
*
|
||||
* @see \CodeIgniter\HTTP\CorsTest
|
||||
*/
|
||||
class Cors
|
||||
{
|
||||
/**
|
||||
* @var array{
|
||||
* allowedOrigins: list<string>,
|
||||
* allowedOriginsPatterns: list<string>,
|
||||
* supportsCredentials: bool,
|
||||
* allowedHeaders: list<string>,
|
||||
* exposedHeaders: list<string>,
|
||||
* allowedMethods: list<string>,
|
||||
* maxAge: int,
|
||||
* }
|
||||
*/
|
||||
private array $config = [
|
||||
'allowedOrigins' => [],
|
||||
'allowedOriginsPatterns' => [],
|
||||
'supportsCredentials' => false,
|
||||
'allowedHeaders' => [],
|
||||
'exposedHeaders' => [],
|
||||
'allowedMethods' => [],
|
||||
'maxAge' => 7200,
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array{
|
||||
* allowedOrigins?: list<string>,
|
||||
* allowedOriginsPatterns?: list<string>,
|
||||
* supportsCredentials?: bool,
|
||||
* allowedHeaders?: list<string>,
|
||||
* exposedHeaders?: list<string>,
|
||||
* allowedMethods?: list<string>,
|
||||
* maxAge?: int,
|
||||
* }|CorsConfig|null $config
|
||||
*/
|
||||
public function __construct($config = null)
|
||||
{
|
||||
$config ??= config(CorsConfig::class);
|
||||
if ($config instanceof CorsConfig) {
|
||||
$config = (array) $config;
|
||||
}
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
|
||||
public function isPreflightRequest(IncomingRequest $request): bool
|
||||
{
|
||||
return $request->is('OPTIONS')
|
||||
&& $request->hasHeader('Access-Control-Request-Method');
|
||||
}
|
||||
|
||||
public function handlePreflightRequest(RequestInterface $request, ResponseInterface $response): ResponseInterface
|
||||
{
|
||||
$response->setStatusCode(204);
|
||||
|
||||
$this->setAllowOrigin($request, $response);
|
||||
|
||||
if ($response->hasHeader('Access-Control-Allow-Origin')) {
|
||||
$this->setAllowHeaders($response);
|
||||
$this->setAllowMethods($response);
|
||||
$this->setAllowMaxAge($response);
|
||||
$this->setAllowCredentials($response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function setAllowOrigin(RequestInterface $request, ResponseInterface $response): void
|
||||
{
|
||||
$originCount = count($this->config['allowedOrigins']);
|
||||
$originPatternCount = count($this->config['allowedOriginsPatterns']);
|
||||
|
||||
if (in_array('*', $this->config['allowedOrigins'], true) && $originCount > 1) {
|
||||
throw new ConfigException(
|
||||
"If wildcard is specified, you must set `'allowedOrigins' => ['*']`."
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
$originCount === 1 && $this->config['allowedOrigins'][0] === '*'
|
||||
&& $this->config['supportsCredentials']
|
||||
) {
|
||||
throw new ConfigException(
|
||||
'When responding to a credentialed request, the server must not specify the "*" wildcard for the Access-Control-Allow-Origin response-header value.'
|
||||
);
|
||||
}
|
||||
|
||||
if ($originCount === 1 && $originPatternCount === 0) {
|
||||
$response->setHeader('Access-Control-Allow-Origin', $this->config['allowedOrigins'][0]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$origin = $request->getHeaderLine('Origin');
|
||||
|
||||
if ($originCount > 1 && in_array($origin, $this->config['allowedOrigins'], true)) {
|
||||
$response->setHeader('Access-Control-Allow-Origin', $origin);
|
||||
$response->appendHeader('Vary', 'Origin');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($originPatternCount > 0) {
|
||||
foreach ($this->config['allowedOriginsPatterns'] as $pattern) {
|
||||
if (preg_match($pattern, $origin)) {
|
||||
$response->setHeader('Access-Control-Allow-Origin', $origin);
|
||||
$response->appendHeader('Vary', 'Origin');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function setAllowHeaders(ResponseInterface $response): void
|
||||
{
|
||||
if (
|
||||
in_array('*', $this->config['allowedHeaders'], true)
|
||||
&& count($this->config['allowedHeaders']) > 1
|
||||
) {
|
||||
throw new ConfigException(
|
||||
"If wildcard is specified, you must set `'allowedHeaders' => ['*']`."
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
$this->config['allowedHeaders'][0] === '*'
|
||||
&& $this->config['supportsCredentials']
|
||||
) {
|
||||
throw new ConfigException(
|
||||
'When responding to a credentialed request, the server must not specify the "*" wildcard for the Access-Control-Allow-Headers response-header value.'
|
||||
);
|
||||
}
|
||||
|
||||
$response->setHeader(
|
||||
'Access-Control-Allow-Headers',
|
||||
implode(', ', $this->config['allowedHeaders'])
|
||||
);
|
||||
}
|
||||
|
||||
private function setAllowMethods(ResponseInterface $response): void
|
||||
{
|
||||
if (
|
||||
in_array('*', $this->config['allowedMethods'], true)
|
||||
&& count($this->config['allowedMethods']) > 1
|
||||
) {
|
||||
throw new ConfigException(
|
||||
"If wildcard is specified, you must set `'allowedMethods' => ['*']`."
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
$this->config['allowedMethods'][0] === '*'
|
||||
&& $this->config['supportsCredentials']
|
||||
) {
|
||||
throw new ConfigException(
|
||||
'When responding to a credentialed request, the server must not specify the "*" wildcard for the Access-Control-Allow-Methods response-header value.'
|
||||
);
|
||||
}
|
||||
|
||||
$response->setHeader(
|
||||
'Access-Control-Allow-Methods',
|
||||
implode(', ', $this->config['allowedMethods'])
|
||||
);
|
||||
}
|
||||
|
||||
private function setAllowMaxAge(ResponseInterface $response): void
|
||||
{
|
||||
$response->setHeader('Access-Control-Max-Age', (string) $this->config['maxAge']);
|
||||
}
|
||||
|
||||
private function setAllowCredentials(ResponseInterface $response): void
|
||||
{
|
||||
if ($this->config['supportsCredentials']) {
|
||||
$response->setHeader('Access-Control-Allow-Credentials', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
public function addResponseHeaders(RequestInterface $request, ResponseInterface $response): ResponseInterface
|
||||
{
|
||||
$this->setAllowOrigin($request, $response);
|
||||
|
||||
if ($response->hasHeader('Access-Control-Allow-Origin')) {
|
||||
$this->setAllowCredentials($response);
|
||||
$this->setExposeHeaders($response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function setExposeHeaders(ResponseInterface $response): void
|
||||
{
|
||||
if ($this->config['exposedHeaders'] !== []) {
|
||||
$response->setHeader(
|
||||
'Access-Control-Expose-Headers',
|
||||
implode(', ', $this->config['exposedHeaders'])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
513
tests/system/HTTP/CorsTest.php
Normal file
513
tests/system/HTTP/CorsTest.php
Normal file
@ -0,0 +1,513 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\HTTP;
|
||||
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use Config\Cors as CorsConfig;
|
||||
use Config\Services;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @group Others
|
||||
*/
|
||||
final class CorsTest extends CIUnitTestCase
|
||||
{
|
||||
private function createCors(?CorsConfig $config = null): Cors
|
||||
{
|
||||
$config ??= new CorsConfig();
|
||||
|
||||
return new Cors($config);
|
||||
}
|
||||
|
||||
public function testInstantiate()
|
||||
{
|
||||
$cors = $this->createCors();
|
||||
|
||||
$this->assertInstanceOf(Cors::class, $cors);
|
||||
}
|
||||
|
||||
public function testIsPreflightRequestTrue()
|
||||
{
|
||||
$cors = $this->createCors();
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('OPTIONS')
|
||||
->setHeader('Access-Control-Request-Method', 'PUT');
|
||||
|
||||
$this->assertTrue($cors->isPreflightRequest($request));
|
||||
}
|
||||
|
||||
public function testIsPreflightRequestFalse()
|
||||
{
|
||||
$cors = $this->createCors();
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('OPTIONS');
|
||||
|
||||
$this->assertFalse($cors->isPreflightRequest($request));
|
||||
}
|
||||
|
||||
private function createRequest(): RequestInterface
|
||||
{
|
||||
return Services::incomingrequest(null, false);
|
||||
}
|
||||
|
||||
private function createCorsConfig(): CorsConfig
|
||||
{
|
||||
$config = new CorsConfig();
|
||||
|
||||
$config->allowedHeaders = ['X-API-KEY', 'X-Requested-With', 'Content-Type', 'Accept'];
|
||||
$config->allowedMethods = ['PUT'];
|
||||
$config->maxAge = 3600;
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function testHandlePreflightRequestSingleAllowedOrigin()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['http://localhost:8080'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('OPTIONS')
|
||||
->setHeader('Access-Control-Request-Method', 'PUT')
|
||||
->setHeader('Origin', 'http://localhost:8080');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->handlePreflightRequest($request, $response);
|
||||
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Origin',
|
||||
'http://localhost:8080'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Headers',
|
||||
'X-API-KEY, X-Requested-With, Content-Type, Accept'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Methods',
|
||||
'PUT'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Credentials')
|
||||
);
|
||||
}
|
||||
|
||||
private function assertHeader(ResponseInterface $response, string $name, string $value): void
|
||||
{
|
||||
$this->assertSame($value, $response->getHeaderLine($name));
|
||||
}
|
||||
|
||||
public function testHandlePreflightRequestMultipleAllowedOriginsAllowed()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['https://example.com', 'https://api.example.com'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('OPTIONS')
|
||||
->setHeader('Access-Control-Request-Method', 'PUT')
|
||||
->setHeader('Origin', 'https://api.example.com');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->handlePreflightRequest($request, $response);
|
||||
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Origin',
|
||||
'https://api.example.com'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Headers',
|
||||
'X-API-KEY, X-Requested-With, Content-Type, Accept'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Methods',
|
||||
'PUT'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Vary',
|
||||
'Origin'
|
||||
);
|
||||
}
|
||||
|
||||
public function testHandlePreflightRequestMultipleAllowedOriginsAllowedAlreadyVary()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['https://example.com', 'https://api.example.com'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('OPTIONS')
|
||||
->setHeader('Access-Control-Request-Method', 'PUT')
|
||||
->setHeader('Origin', 'https://api.example.com');
|
||||
|
||||
$response = Services::response(null, false)
|
||||
->setHeader('Vary', 'Accept-Language');
|
||||
|
||||
$response = $cors->handlePreflightRequest($request, $response);
|
||||
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Origin',
|
||||
'https://api.example.com'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Headers',
|
||||
'X-API-KEY, X-Requested-With, Content-Type, Accept'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Methods',
|
||||
'PUT'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Vary',
|
||||
'Accept-Language, Origin'
|
||||
);
|
||||
}
|
||||
|
||||
public function testHandlePreflightRequestMultipleAllowedOriginsNotAllowed()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['https://example.com', 'https://api.example.com'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('OPTIONS')
|
||||
->setHeader('Access-Control-Request-Method', 'PUT')
|
||||
->setHeader('Origin', 'https://bad.site.com');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->handlePreflightRequest($request, $response);
|
||||
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Origin')
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Headers')
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Methods')
|
||||
);
|
||||
}
|
||||
|
||||
public function testHandlePreflightRequestAllowedOriginsPatternsAllowed()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOriginsPatterns = ['!\Ahttps://\w+\.example\.com\z!'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('OPTIONS')
|
||||
->setHeader('Access-Control-Request-Method', 'PUT')
|
||||
->setHeader('Origin', 'https://api.example.com');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->handlePreflightRequest($request, $response);
|
||||
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Origin',
|
||||
'https://api.example.com'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Headers',
|
||||
'X-API-KEY, X-Requested-With, Content-Type, Accept'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Methods',
|
||||
'PUT'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Vary',
|
||||
'Origin'
|
||||
);
|
||||
}
|
||||
|
||||
public function testHandlePreflightRequestAllowedOriginsPatternsNotAllowed()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOriginsPatterns = ['!\Ahttps://\w+\.example\.com\z!'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('OPTIONS')
|
||||
->setHeader('Access-Control-Request-Method', 'PUT')
|
||||
->setHeader('Origin', 'https://bad.site.com');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->handlePreflightRequest($request, $response);
|
||||
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Origin')
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Headers')
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Methods')
|
||||
);
|
||||
}
|
||||
|
||||
public function testHandlePreflightRequestSingleAllowedOriginWithCredentials()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['http://localhost:8080'];
|
||||
$config->supportsCredentials = true;
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('OPTIONS')
|
||||
->setHeader('Access-Control-Request-Method', 'PUT')
|
||||
->setHeader('Origin', 'http://localhost:8080');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->handlePreflightRequest($request, $response);
|
||||
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Origin',
|
||||
'http://localhost:8080'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Headers',
|
||||
'X-API-KEY, X-Requested-With, Content-Type, Accept'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Methods',
|
||||
'PUT'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Credentials',
|
||||
'true'
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddResponseHeadersSingleAllowedOriginSimpleRequest()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['http://localhost:8080'];
|
||||
$config->allowedMethods = ['GET', 'POST', 'PUT'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('GET')
|
||||
->setHeader('Origin', 'http://localhost:8080');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->addResponseHeaders($request, $response);
|
||||
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Origin',
|
||||
'http://localhost:8080'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Headers')
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Methods')
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Credentials')
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddResponseHeadersSingleAllowedOriginRealRequest()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['http://localhost:8080'];
|
||||
$config->allowedMethods = ['GET', 'POST', 'PUT'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('POST')
|
||||
->setHeader('Origin', 'http://localhost:8080');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->addResponseHeaders($request, $response);
|
||||
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Origin',
|
||||
'http://localhost:8080'
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddResponseHeadersSingleAllowedOriginWithCredentials()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['http://localhost:8080'];
|
||||
$config->supportsCredentials = true;
|
||||
$config->allowedMethods = ['GET'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('GET')
|
||||
->setHeader('Cookie', 'pageAccess=2')
|
||||
->setHeader('Origin', 'http://localhost:8080');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->addResponseHeaders($request, $response);
|
||||
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Origin',
|
||||
'http://localhost:8080'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Credentials',
|
||||
'true'
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddResponseHeadersSingleAllowedOriginWithExposeHeaders()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['http://localhost:8080'];
|
||||
$config->allowedMethods = ['GET'];
|
||||
$config->exposedHeaders = ['Content-Length', 'X-Kuma-Revision'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('GET')
|
||||
->setHeader('Origin', 'http://localhost:8080');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->addResponseHeaders($request, $response);
|
||||
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Origin',
|
||||
'http://localhost:8080'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Expose-Headers',
|
||||
'Content-Length, X-Kuma-Revision'
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddResponseHeadersMultipleAllowedOriginsAllowed()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['https://example.com', 'https://api.example.com'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('PUT')
|
||||
->setHeader('Origin', 'https://api.example.com');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->addResponseHeaders($request, $response);
|
||||
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Origin',
|
||||
'https://api.example.com'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Vary',
|
||||
'Origin'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Headers')
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Methods')
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddResponseHeadersMultipleAllowedOriginsAllowedAlreadyVary()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['https://example.com', 'https://api.example.com'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('PUT')
|
||||
->setHeader('Origin', 'https://api.example.com');
|
||||
|
||||
$response = Services::response(null, false)
|
||||
->setHeader('Vary', 'Accept-Language');
|
||||
|
||||
$response = $cors->addResponseHeaders($request, $response);
|
||||
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Access-Control-Allow-Origin',
|
||||
'https://api.example.com'
|
||||
);
|
||||
$this->assertHeader(
|
||||
$response,
|
||||
'Vary',
|
||||
'Accept-Language, Origin'
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddResponseHeadersMultipleAllowedOriginsNotAllowed()
|
||||
{
|
||||
$config = $this->createCorsConfig();
|
||||
$config->allowedOrigins = ['https://example.com', 'https://api.example.com'];
|
||||
$cors = $this->createCors($config);
|
||||
|
||||
$request = $this->createRequest()
|
||||
->withMethod('PUT')
|
||||
->setHeader('Origin', 'https://bad.site.com');
|
||||
|
||||
$response = Services::response(null, false);
|
||||
|
||||
$response = $cors->addResponseHeaders($request, $response);
|
||||
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Origin')
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Headers')
|
||||
);
|
||||
$this->assertFalse(
|
||||
$response->hasHeader('Access-Control-Allow-Methods')
|
||||
);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user