Move into nested docroot

This commit is contained in:
Rob Davies 2017-02-13 15:31:17 +00:00
parent 83a0d3a149
commit c8b70abde9
13405 changed files with 0 additions and 0 deletions

View file

@ -1,4 +0,0 @@
phpunit.xml
composer.lock
composer.phar
/vendor/

View file

@ -1,13 +0,0 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
before_script: composer install --dev
script: phpunit

View file

@ -1,59 +0,0 @@
# Stack/Cors
Library and middleware enabling cross-origin resource sharing for your
http-{foundation,kernel} using application. It attempts to implement the
[W3C Candidate Recommendation] for cross-origin resource sharing.
[W3C Candidate Recommendation]: http://www.w3.org/TR/cors/
Master [![Build Status](https://secure.travis-ci.org/asm89/stack-cors.png?branch=master)](http://travis-ci.org/asm89/stack-cors)
Develop [![Build Status](https://secure.travis-ci.org/asm89/stack-cors.png?branch=develop)](http://travis-ci.org/asm89/stack-cors)
## Installation
Require `asm89/stack-cors` using composer.
## Usage
Stack middleware:
```php
<?php
use Asm89\Stack\Cors;
$app = new Cors($app, array(
// you can use array('*') to allow any headers
'allowedHeaders' => array('x-allowed-header', 'x-other-allowed-header'),
// you can use array('*') to allow any methods
'allowedMethods' => array('DELETE', 'GET', 'POST', 'PUT'),
// you can use array('*') to allow requests from any origin
'allowedOrigins' => array('localhost'),
'exposedHeaders' => false,
'maxAge' => false,
'supportsCredentials' => false,
));
```
Or use the library:
```php
<?php
use Asm89\Stack\CorsService;
$cors = new CorsService(array(
'allowedHeaders' => array('x-allowed-header', 'x-other-allowed-header'),
'allowedMethods' => array('DELETE', 'GET', 'POST', 'PUT'),
'allowedOrigins' => array('localhost'),
'exposedHeaders' => false,
'maxAge' => false,
'supportsCredentials' => false,
));
$cors->addActualRequestHeaders(Response $response, $origin);
$cors->handlePreflightRequest(Request $request);
$cors->isActualRequestAllowed(Request $request);
$cors->isCorsRequest(Request $request);
$cors->isPreflightRequest(Request $request);
```

View file

@ -1,22 +0,0 @@
{
"name": "asm89/stack-cors",
"description": "Cross-origin resource sharing library and stack middleware",
"keywords": ["stack", "cors"],
"homepage": "https://github.com/asm89/stack-cors",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Alexander",
"email": "iam.asm89@gmail.com"
}
],
"require": {
"php": ">=5.3.2",
"symfony/http-foundation": "~2.1|~3.0",
"symfony/http-kernel": "~2.1|~3.0"
},
"autoload": {
"psr-0": { "Asm89\\Stack": "src/" }
}
}

View file

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="test/bootstrap.php"
>
<testsuites>
<testsuite name="Stack Cors Test Suite">
<directory>./test/Asm89/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">./src/</directory>
</whitelist>
</filter>
</phpunit>

View file

@ -1,55 +0,0 @@
<?php
namespace Asm89\Stack;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class Cors implements HttpKernelInterface
{
/**
* @var \Symfony\Component\HttpKernel\HttpKernelInterface
*/
private $app;
/**
* @var \Asm89\Stack\CorsService
*/
private $cors;
private $defaultOptions = array(
'allowedHeaders' => array(),
'allowedMethods' => array(),
'allowedOrigins' => array(),
'exposedHeaders' => false,
'maxAge' => false,
'supportsCredentials' => false,
);
public function __construct(HttpKernelInterface $app, array $options = array())
{
$this->app = $app;
$this->cors = new CorsService(array_merge($this->defaultOptions, $options));
}
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
if ( ! $this->cors->isCorsRequest($request)) {
return $this->app->handle($request, $type, $catch);
}
if ($this->cors->isPreflightRequest($request)) {
return $this->cors->handlePreflightRequest($request);
}
if ( ! $this->cors->isActualRequestAllowed($request)) {
return new Response('Not allowed.', 403);
}
$response = $this->app->handle($request, $type, $catch);
return $this->cors->addActualRequestHeaders($response, $request);
}
}

View file

@ -1,178 +0,0 @@
<?php
namespace Asm89\Stack;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class CorsService
{
private $options;
public function __construct(array $options = array())
{
$this->options = $this->normalizeOptions($options);
}
private function normalizeOptions(array $options = array())
{
$options += array(
'allowedOrigins' => array(),
'supportsCredentials' => false,
'allowedHeaders' => array(),
'exposedHeaders' => array(),
'allowedMethods' => array(),
'maxAge' => 0,
);
// normalize array('*') to true
if (in_array('*', $options['allowedOrigins'])) {
$options['allowedOrigins'] = true;
}
if (in_array('*', $options['allowedHeaders'])) {
$options['allowedHeaders'] = true;
} else {
$options['allowedHeaders'] = array_map('strtolower', $options['allowedHeaders']);
}
if (in_array('*', $options['allowedMethods'])) {
$options['allowedMethods'] = true;
} else {
$options['allowedMethods'] = array_map('strtoupper', $options['allowedMethods']);
}
return $options;
}
public function isActualRequestAllowed(Request $request)
{
return $this->checkOrigin($request);
}
public function isCorsRequest(Request $request)
{
return $request->headers->has('Origin');
}
public function isPreflightRequest(Request $request)
{
return $this->isCorsRequest($request)
&&$request->getMethod() === 'OPTIONS'
&& $request->headers->has('Access-Control-Request-Method');
}
public function addActualRequestHeaders(Response $response, Request $request)
{
if ( ! $this->checkOrigin($request)) {
return $response;
}
$response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
if ( ! $response->headers->has('Vary')) {
$response->headers->set('Vary', 'Origin');
} else {
$response->headers->set('Vary', $response->headers->get('Vary') . ', Origin');
}
if ($this->options['supportsCredentials']) {
$response->headers->set('Access-Control-Allow-Credentials', 'true');
}
if ($this->options['exposedHeaders']) {
$response->headers->set('Access-Control-Expose-Headers', implode(', ', $this->options['exposedHeaders']));
}
return $response;
}
public function handlePreflightRequest(Request $request)
{
if (true !== $check = $this->checkPreflightRequestConditions($request)) {
return $check;
}
return $this->buildPreflightCheckResponse($request);
}
private function buildPreflightCheckResponse(Request $request)
{
$response = new Response();
if ($this->options['supportsCredentials']) {
$response->headers->set('Access-Control-Allow-Credentials', 'true');
}
$response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
if ($this->options['maxAge']) {
$response->headers->set('Access-Control-Max-Age', $this->options['maxAge']);
}
$allowMethods = $this->options['allowedMethods'] === true
? strtoupper($request->headers->get('Access-Control-Request-Method'))
: implode(', ', $this->options['allowedMethods']);
$response->headers->set('Access-Control-Allow-Methods', $allowMethods);
$allowHeaders = $this->options['allowedHeaders'] === true
? strtoupper($request->headers->get('Access-Control-Request-Headers'))
: implode(', ', $this->options['allowedHeaders']);
$response->headers->set('Access-Control-Allow-Headers', $allowHeaders);
return $response;
}
private function checkPreflightRequestConditions(Request $request)
{
if ( ! $this->checkOrigin($request)) {
return $this->createBadRequestResponse(403, 'Origin not allowed');
}
if ( ! $this->checkMethod($request)) {
return $this->createBadRequestResponse(405, 'Method not allowed');
}
$requestHeaders = array();
// if allowedHeaders has been set to true ('*' allow all flag) just skip this check
if ($this->options['allowedHeaders'] !== true && $request->headers->has('Access-Control-Request-Headers')) {
$headers = strtolower($request->headers->get('Access-Control-Request-Headers'));
$requestHeaders = explode(',', $headers);
foreach ($requestHeaders as $header) {
if ( ! in_array(trim($header), $this->options['allowedHeaders'])) {
return $this->createBadRequestResponse(403, 'Header not allowed');
}
}
}
return true;
}
private function createBadRequestResponse($code, $reason = '')
{
return new Response($reason, $code);
}
private function checkOrigin(Request $request) {
if ($this->options['allowedOrigins'] === true) {
// allow all '*' flag
return true;
}
$origin = $request->headers->get('Origin');
return in_array($origin, $this->options['allowedOrigins']);
}
private function checkMethod(Request $request) {
if ($this->options['allowedMethods'] === true) {
// allow all '*' flag
return true;
}
$requestMethod = strtoupper($request->headers->get('Access-Control-Request-Method'));
return in_array($requestMethod, $this->options['allowedMethods']);
}
}

View file

@ -1,395 +0,0 @@
<?php
namespace Asm89\Stack;
use PHPUnit_Framework_TestCase;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class CorsTest extends PHPUnit_Framework_TestCase
{
/**
* @test
*/
public function it_does_not_modify_on_a_request_without_origin()
{
$app = $this->createStackedApp();
$unmodifiedResponse = new Response();
$response = $app->handle(new Request());
$this->assertEquals($unmodifiedResponse->headers, $response->headers);
}
/**
* @test
*/
public function it_returns_403_on_valid_actual_request_with_origin_not_allowed()
{
$app = $this->createStackedApp(array('allowedOrigins' => array('notlocalhost')));
$request = $this->createValidActualRequest();
$response = $app->handle($request);
$this->assertEquals(403, $response->getStatusCode());
}
/**
* @test
*/
public function it_returns_allow_origin_header_on_valid_actual_request()
{
$app = $this->createStackedApp();
$request = $this->createValidActualRequest();
$response = $app->handle($request);
$this->assertTrue($response->headers->has('Access-Control-Allow-Origin'));
$this->assertEquals('localhost', $response->headers->get('Access-Control-Allow-Origin'));
}
/**
* @test
*/
public function it_returns_allow_origin_header_on_allow_all_origin_request()
{
$app = $this->createStackedApp(array('allowedOrigins' => array('*')));
$request = new Request();
$request->headers->set('Origin', 'http://localhost');
$response = $app->handle($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertTrue($response->headers->has('Access-Control-Allow-Origin'));
$this->assertEquals('http://localhost', $response->headers->get('Access-Control-Allow-Origin'));
}
/**
* @test
*/
public function it_returns_allow_headers_header_on_allow_all_headers_request()
{
$app = $this->createStackedApp(array('allowedHeaders' => array('*')));
$request = $this->createValidPreflightRequest();
$request->headers->set('Access-Control-Request-Headers', 'Foo, BAR');
$response = $app->handle($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('FOO, BAR', $response->headers->get('Access-Control-Allow-Headers'));
}
/**
* @test
*/
public function it_does_not_return_allow_origin_header_on_valid_actual_request_with_origin_not_allowed()
{
$app = $this->createStackedApp(array('allowedOrigins' => array('notlocalhost')));
$request = $this->createValidActualRequest();
$response = $app->handle($request);
$this->assertFalse($response->headers->has('Access-Control-Allow-Origin'));
}
/**
* @test
*/
public function it_sets_allow_credentials_header_when_flag_is_set_on_valid_actual_request()
{
$app = $this->createStackedApp(array('supportsCredentials' => true));
$request = $this->createValidActualRequest();
$response = $app->handle($request);
$this->assertTrue($response->headers->has('Access-Control-Allow-Credentials'));
$this->assertEquals('true', $response->headers->get('Access-Control-Allow-Credentials'));
}
/**
* @test
*/
public function it_does_not_set_allow_credentials_header_when_flag_is_not_set_on_valid_actual_request()
{
$app = $this->createStackedApp();
$request = $this->createValidActualRequest();
$response = $app->handle($request);
$this->assertFalse($response->headers->has('Access-Control-Allow-Credentials'));
}
/**
* @test
*/
public function it_sets_exposed_headers_when_configured_on_actual_request()
{
$app = $this->createStackedApp(array('exposedHeaders' => array('x-exposed-header', 'x-another-exposed-header')));
$request = $this->createValidActualRequest();
$response = $app->handle($request);
$this->assertTrue($response->headers->has('Access-Control-Expose-Headers'));
$this->assertEquals('x-exposed-header, x-another-exposed-header', $response->headers->get('Access-Control-Expose-Headers'));
}
/**
* @test
* @see http://www.w3.org/TR/cors/index.html#resource-implementation
*/
public function it_adds_a_vary_header()
{
$app = $this->createStackedApp();
$request = $this->createValidActualRequest();
$response = $app->handle($request);
$this->assertTrue($response->headers->has('Vary'));
$this->assertEquals('Origin', $response->headers->get('Vary'));
}
/**
* @test
* @see http://www.w3.org/TR/cors/index.html#resource-implementation
*/
public function it_appends_an_existing_vary_header()
{
$app = $this->createStackedApp(array(), array('Vary' => 'Content-Type'));
$request = $this->createValidActualRequest();
$response = $app->handle($request);
$this->assertTrue($response->headers->has('Vary'));
$this->assertEquals('Content-Type, Origin', $response->headers->get('Vary'));
}
/**
* @test
*/
public function it_returns_access_control_headers_on_cors_request()
{
$app = $this->createStackedApp();
$request = new Request();
$request->headers->set('Origin', 'localhost');
$response = $app->handle($request);
$this->assertTrue($response->headers->has('Access-Control-Allow-Origin'));
$this->assertEquals('localhost', $response->headers->get('Access-Control-Allow-Origin'));
}
/**
* @test
*/
public function it_returns_access_control_headers_on_valid_preflight_request()
{
$app = $this->createStackedApp();
$request = $this->createValidPreflightRequest();
$response = $app->handle($request);
$this->assertTrue($response->headers->has('Access-Control-Allow-Origin'));
$this->assertEquals('localhost', $response->headers->get('Access-Control-Allow-Origin'));
}
/**
* @test
*/
public function it_returns_403_on_valid_preflight_request_with_origin_not_allowed()
{
$app = $this->createStackedApp(array('allowedOrigins' => array('notlocalhost')));
$request = $this->createValidPreflightRequest();
$response = $app->handle($request);
$this->assertEquals(403, $response->getStatusCode());
}
/**
* @test
*/
public function it_does_not_modify_request_with_origin_not_allowed()
{
$passedOptions = array(
'allowedOrigins' => array('notlocalhost'),
);
$service = new CorsService($passedOptions);
$request = $this->createValidActualRequest();
$response = new Response();
$service->addActualRequestHeaders($response, $request);
$this->assertEquals($response, new Response());
}
/**
* @test
*/
public function it_returns_405_on_valid_preflight_request_with_method_not_allowed()
{
$app = $this->createStackedApp(array('allowedMethods' => array('put')));
$request = $this->createValidPreflightRequest();
$response = $app->handle($request);
$this->assertEquals(405, $response->getStatusCode());
}
/**
* @test
*/
public function it_allow_methods_on_valid_preflight_request()
{
$app = $this->createStackedApp(array('allowedMethods' => array('get', 'put')));
$request = $this->createValidPreflightRequest();
$response = $app->handle($request);
$this->assertTrue($response->headers->has('Access-Control-Allow-Methods'));
// it will uppercase the methods
$this->assertEquals('GET, PUT', $response->headers->get('Access-Control-Allow-Methods'));
}
/**
* @test
*/
public function it_returns_valid_preflight_request_with_allow_methods_all()
{
$app = $this->createStackedApp(array('allowedMethods' => array('*')));
$request = $this->createValidPreflightRequest();
$response = $app->handle($request);
$this->assertTrue($response->headers->has('Access-Control-Allow-Methods'));
// it will return the Access-Control-Request-Method pass in the request
$this->assertEquals('GET', $response->headers->get('Access-Control-Allow-Methods'));
}
/**
* @test
*/
public function it_returns_403_on_valid_preflight_request_with_one_of_the_requested_headers_not_allowed()
{
$app = $this->createStackedApp();
$request = $this->createValidPreflightRequest();
$request->headers->set('Access-Control-Request-Headers', 'x-not-allowed-header');
$response = $app->handle($request);
$this->assertEquals(403, $response->getStatusCode());
}
/**
* @test
*/
public function it_returns_ok_on_valid_preflight_request_with_requested_headers_allowed()
{
$app = $this->createStackedApp();
$requestHeaders = 'X-Allowed-Header, x-other-allowed-header';
$request = $this->createValidPreflightRequest();
$request->headers->set('Access-Control-Request-Headers', $requestHeaders);
$response = $app->handle($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertTrue($response->headers->has('Access-Control-Allow-Headers'));
// the response will have the "allowedHeaders" value passed to Cors rather than the request one
$this->assertEquals('x-allowed-header, x-other-allowed-header', $response->headers->get('Access-Control-Allow-Headers'));
}
/**
* @test
*/
public function it_sets_allow_credentials_header_when_flag_is_set_on_valid_preflight_request()
{
$app = $this->createStackedApp(array('supportsCredentials' => true));
$request = $this->createValidPreflightRequest();
$response = $app->handle($request);
$this->assertTrue($response->headers->has('Access-Control-Allow-Credentials'));
$this->assertEquals('true', $response->headers->get('Access-Control-Allow-Credentials'));
}
/**
* @test
*/
public function it_does_not_set_allow_credentials_header_when_flag_is_not_set_on_valid_preflight_request()
{
$app = $this->createStackedApp();
$request = $this->createValidPreflightRequest();
$response = $app->handle($request);
$this->assertFalse($response->headers->has('Access-Control-Allow-Credentials'));
}
/**
* @test
*/
public function it_sets_max_age_when_set()
{
$app = $this->createStackedApp(array('maxAge' => 42));
$request = $this->createValidPreflightRequest();
$response = $app->handle($request);
$this->assertTrue($response->headers->has('Access-Control-Max-Age'));
$this->assertEquals(42, $response->headers->get('Access-Control-Max-Age'));
}
private function createValidActualRequest()
{
$request = new Request();
$request->headers->set('Origin', 'localhost');
return $request;
}
private function createValidPreflightRequest()
{
$request = new Request();
$request->headers->set('Origin', 'localhost');
$request->headers->set('Access-Control-Request-Method', 'get');
$request->setMethod('OPTIONS');
return $request;
}
private function createStackedApp(array $options = array(), array $responseHeaders = array())
{
$passedOptions = array_merge(array(
'allowedHeaders' => array('x-allowed-header', 'x-other-allowed-header'),
'allowedMethods' => array('delete', 'get', 'post', 'put'),
'allowedOrigins' => array('localhost'),
'exposedHeaders' => false,
'maxAge' => false,
'supportsCredentials' => false,
),
$options
);
return new Cors(new MockApp($responseHeaders), $passedOptions);
}
}
class MockApp implements HttpKernelInterface
{
private $responseHeaders;
public function __construct(array $responseHeaders)
{
$this->responseHeaders = $responseHeaders;
}
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
$response = new Response();
$response->headers->add($this->responseHeaders);
return $response;
}
}

View file

@ -1,10 +0,0 @@
<?php
if (file_exists($file = __DIR__.'/../vendor/autoload.php')) {
$loader = require_once $file;
$loader->add('Asm89\Stack', __DIR__);
$loader->add('Asm89\Stack', __DIR__ . '/../src');
} else {
throw new RuntimeException('Install dependencies to run test suite.');
}