Use alchemy/symfony-cors instead of ApiCorsSubscriber

This commit is contained in:
Benoît Burnichon
2015-11-20 16:37:25 +01:00
parent 8bd4144d38
commit 6847737742
6 changed files with 65 additions and 338 deletions

View File

@@ -40,7 +40,7 @@
"alchemy/oauth2php": "1.0.0", "alchemy/oauth2php": "1.0.0",
"alchemy/phlickr": "0.2.9", "alchemy/phlickr": "0.2.9",
"alchemy/rest-bundle": "master@dev", "alchemy/rest-bundle": "master@dev",
"alchemy/symfony-cors": "master@dev", "alchemy/symfony-cors": "^0.1.0",
"alchemy/task-manager": "2.0.x-dev@dev", "alchemy/task-manager": "2.0.x-dev@dev",
"alchemy/zippy": "0.2.x-dev@dev", "alchemy/zippy": "0.2.x-dev@dev",
"beberlei/assert": "^2.3", "beberlei/assert": "^2.3",

56
composer.lock generated
View File

@@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "9ad403d1241ac6e7c1d6a8ee1a88b562", "hash": "060bc97259e610db725a2f75af4cccc0",
"content-hash": "afa161367fc67b099314aecbff0ab9d8", "content-hash": "691d34f60fc60114d275eab15a3e9de5",
"packages": [ "packages": [
{ {
"name": "alchemy-fr/tcpdf-clone", "name": "alchemy-fr/tcpdf-clone",
@@ -15,6 +15,12 @@
"url": "https://github.com/alchemy-fr/tcpdf-clone.git", "url": "https://github.com/alchemy-fr/tcpdf-clone.git",
"reference": "2ba0248a7187f1626df6c128750650416267f0e7" "reference": "2ba0248a7187f1626df6c128750650416267f0e7"
}, },
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/tcpdf-clone/zipball/2ba0248a7187f1626df6c128750650416267f0e7",
"reference": "2ba0248a7187f1626df6c128750650416267f0e7",
"shasum": ""
},
"require": { "require": {
"php": ">=5.3.0" "php": ">=5.3.0"
}, },
@@ -61,6 +67,10 @@
"qrcode", "qrcode",
"tcpdf" "tcpdf"
], ],
"support": {
"source": "https://github.com/alchemy-fr/tcpdf-clone/tree/6.0.039",
"issues": "https://github.com/alchemy-fr/tcpdf-clone/issues"
},
"time": "2013-10-13 16:11:17" "time": "2013-10-13 16:11:17"
}, },
{ {
@@ -104,7 +114,7 @@
"homepage": "http://www.lickmychip.com/" "homepage": "http://www.lickmychip.com/"
}, },
{ {
"name": "Nicolas Le Goff", "name": "nlegoff",
"email": "legoff.n@gmail.com" "email": "legoff.n@gmail.com"
}, },
{ {
@@ -304,7 +314,7 @@
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/rest-bundle/zipball/7b1c88c02ab8c0d4e997fd61c13c8fd4c3ce5216", "url": "https://api.github.com/repos/alchemy-fr/rest-bundle/zipball/a0e2c2b8a1d2c9c405fc9663b698f56a20831946",
"reference": "7b1c88c02ab8c0d4e997fd61c13c8fd4c3ce5216", "reference": "7b1c88c02ab8c0d4e997fd61c13c8fd4c3ce5216",
"shasum": "" "shasum": ""
}, },
@@ -347,11 +357,11 @@
}, },
{ {
"name": "alchemy/symfony-cors", "name": "alchemy/symfony-cors",
"version": "dev-master", "version": "0.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/alchemy-fr/symfony-cors", "url": "https://github.com/alchemy-fr/symfony-cors",
"reference": "88f2d4089e252153946e283ac89631e78b4d73a5" "reference": "8aafaff26e29fdd57358062d20724109a349def5"
}, },
"require": { "require": {
"symfony/http-kernel": "^2.3.0|^3.0.0" "symfony/http-kernel": "^2.3.0|^3.0.0"
@@ -361,6 +371,11 @@
"silex/silex": "^1.0" "silex/silex": "^1.0"
}, },
"type": "library", "type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.1.x-dev"
}
},
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Alchemy\\Cors\\": "src/Component/", "Alchemy\\Cors\\": "src/Component/",
@@ -383,7 +398,7 @@
} }
], ],
"description": "A library that adds CORS services to Silex/Symfony Applications", "description": "A library that adds CORS services to Silex/Symfony Applications",
"time": "2015-10-12 11:04:31" "time": "2015-11-20 17:55:08"
}, },
{ {
"name": "alchemy/task-manager", "name": "alchemy/task-manager",
@@ -1473,12 +1488,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/igorw/evenement.git", "url": "https://github.com/igorw/evenement.git",
"reference": "v1.0.0" "reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/igorw/evenement/zipball/fa966683e7df3e5dd5929d984a44abfbd6bafe8d", "url": "https://api.github.com/repos/igorw/evenement/zipball/fa966683e7df3e5dd5929d984a44abfbd6bafe8d",
"reference": "v1.0.0", "reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1505,7 +1520,7 @@
"keywords": [ "keywords": [
"event-dispatcher" "event-dispatcher"
], ],
"time": "2012-05-30 08:01:08" "time": "2012-05-30 15:01:08"
}, },
{ {
"name": "facebook/php-sdk", "name": "facebook/php-sdk",
@@ -2631,7 +2646,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-develop": "0.7-dev" "dev-develop": "0.6-dev"
} }
}, },
"autoload": { "autoload": {
@@ -3355,7 +3370,7 @@
], ],
"authors": [ "authors": [
{ {
"name": "Stephen Clay", "name": "Steve Clay",
"email": "steve@mrclay.org", "email": "steve@mrclay.org",
"homepage": "http://www.mrclay.org/", "homepage": "http://www.mrclay.org/",
"role": "Developer" "role": "Developer"
@@ -3541,21 +3556,21 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/romainneutron/Imagine-Silex-Service-Provider.git", "url": "https://github.com/romainneutron/Imagine-Silex-Service-Provider.git",
"reference": "0.1.2" "reference": "a8a7862ae90419f2b23746cd8436c2310e4eb084"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/romainneutron/Imagine-Silex-Service-Provider/zipball/a8a7862ae90419f2b23746cd8436c2310e4eb084", "url": "https://api.github.com/repos/romainneutron/Imagine-Silex-Service-Provider/zipball/a8a7862ae90419f2b23746cd8436c2310e4eb084",
"reference": "0.1.2", "reference": "a8a7862ae90419f2b23746cd8436c2310e4eb084",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"imagine/imagine": "*", "imagine/imagine": "*",
"php": ">=5.3.3", "php": ">=5.3.3",
"silex/silex": ">=1.0,<2.0" "silex/silex": "~1.0"
}, },
"require-dev": { "require-dev": {
"symfony/browser-kit": ">=2.0,<3.0" "symfony/browser-kit": "~2.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -4189,7 +4204,9 @@
"authors": [ "authors": [
{ {
"name": "Fabien Potencier", "name": "Fabien Potencier",
"email": "fabien@symfony.com" "email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
} }
], ],
"description": "Pimple is a simple Dependency Injection Container for PHP 5.3", "description": "Pimple is a simple Dependency Injection Container for PHP 5.3",
@@ -4318,7 +4335,7 @@
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/583b8eba0bcc0ac9aa8e7309e5313c068dbfbe30", "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/e9478830dd1d19ee598ecfb2a6b5e6a4f8f168c2",
"reference": "583b8eba0bcc0ac9aa8e7309e5313c068dbfbe30", "reference": "583b8eba0bcc0ac9aa8e7309e5313c068dbfbe30",
"shasum": "" "shasum": ""
}, },
@@ -4823,7 +4840,7 @@
}, },
{ {
"name": "Phraseanet Team", "name": "Phraseanet Team",
"email": "support@alchemy.fr", "email": "info@alchemy.fr",
"homepage": "http://www.phraseanet.com/" "homepage": "http://www.phraseanet.com/"
} }
], ],
@@ -6215,7 +6232,6 @@
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": { "stability-flags": {
"alchemy/rest-bundle": 20, "alchemy/rest-bundle": 20,
"alchemy/symfony-cors": 20,
"alchemy/task-manager": 20, "alchemy/task-manager": 20,
"alchemy/zippy": 20, "alchemy/zippy": 20,
"goodby/csv": 20, "goodby/csv": 20,

View File

@@ -11,6 +11,8 @@
namespace Alchemy\Phrasea; namespace Alchemy\Phrasea;
use Alchemy\Cors\Options\DefaultProvider;
use Alchemy\CorsProvider\CorsServiceProvider;
use Alchemy\Geonames\GeonamesServiceProvider; use Alchemy\Geonames\GeonamesServiceProvider;
use Alchemy\Phrasea\Application\Helper\AclAware; use Alchemy\Phrasea\Application\Helper\AclAware;
use Alchemy\Phrasea\Application\Helper\ApplicationBoxAware; use Alchemy\Phrasea\Application\Helper\ApplicationBoxAware;
@@ -267,6 +269,29 @@ class Application extends SilexApplication
$this->register(new PluginServiceProvider()); $this->register(new PluginServiceProvider());
$this->register(new PhraseaEventServiceProvider()); $this->register(new PhraseaEventServiceProvider());
$this->register(new ContentNegotiationServiceProvider()); $this->register(new ContentNegotiationServiceProvider());
$this->register(new CorsServiceProvider(), [
'alchemy_cors.debug' => $this['debug'],
'alchemy_cors.cache_path' => function (Application $app) {
return rtrim($app['cache.path'], '/\\') . '/alchemy_cors.cache.php';
},
]);
$this['phraseanet.api_cors.options_provider'] = function (Application $app) {
$paths = [];
if (isset($app['phraseanet.configuration']['api_cors'])) {
$config = $app['phraseanet.configuration']['api_cors'];
if (isset($config['enabled']) && $config['enabled']) {
unset($config['enabled']);
$paths['/api/v\d+/'] = $config;
}
}
return new DefaultProvider($paths, []);
};
$this['alchemy_cors.options_providers'][] = 'phraseanet.api_cors.options_provider';
$this->register(new LocaleServiceProvider()); $this->register(new LocaleServiceProvider());
$this->setupEventDispatcher(); $this->setupEventDispatcher();
$this['phraseanet.exception_handler'] = $this->share(function ($app) { $this['phraseanet.exception_handler'] = $this->share(function ($app) {

View File

@@ -20,7 +20,6 @@ use Alchemy\Phrasea\ControllerProvider\MediaAccessor;
use Alchemy\Phrasea\ControllerProvider\Minifier; use Alchemy\Phrasea\ControllerProvider\Minifier;
use Alchemy\Phrasea\ControllerProvider\Permalink; use Alchemy\Phrasea\ControllerProvider\Permalink;
use Alchemy\Phrasea\Core\Event\ApiResultEvent; use Alchemy\Phrasea\Core\Event\ApiResultEvent;
use Alchemy\Phrasea\Core\Event\Subscriber\ApiCorsSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\ApiExceptionHandlerSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\ApiExceptionHandlerSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\ApiOauth2ErrorsSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\ApiOauth2ErrorsSubscriber;
use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Core\PhraseaEvents;
@@ -30,6 +29,7 @@ use Monolog\Processor\WebProcessor;
use Silex\Application as SilexApplication; use Silex\Application as SilexApplication;
use Silex\Provider\WebProfilerServiceProvider; use Silex\Provider\WebProfilerServiceProvider;
use Sorien\Provider\DoctrineProfilerServiceProvider; use Sorien\Provider\DoctrineProfilerServiceProvider;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@@ -85,7 +85,7 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) {
)); ));
}, PhraseaApplication::EARLY_EVENT); }, PhraseaApplication::EARLY_EVENT);
$app->after(function(Request $request, Response $response) use ($app) { $app->after(function(Request $request, Response $response) {
if ($request->getRequestFormat(Result::FORMAT_JSON) === Result::FORMAT_JSONP && !$response->isOk() && !$response->isServerError()) { if ($request->getRequestFormat(Result::FORMAT_JSON) === Result::FORMAT_JSONP && !$response->isOk() && !$response->isServerError()) {
$response->setStatusCode(200); $response->setStatusCode(200);
} }
@@ -148,7 +148,7 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) {
} }
} }
$app['dispatcher'] = $app->share($app->extend('dispatcher', function ($dispatcher, PhraseaApplication $app) { $app['dispatcher'] = $app->share($app->extend('dispatcher', function (EventDispatcherInterface $dispatcher, PhraseaApplication $app) {
$dispatcher->addSubscriber(new ApiOauth2ErrorsSubscriber($app['phraseanet.exception_handler'], $app['translator'])); $dispatcher->addSubscriber(new ApiOauth2ErrorsSubscriber($app['phraseanet.exception_handler'], $app['translator']));
return $dispatcher; return $dispatcher;
@@ -156,7 +156,6 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) {
$app->after(function (Request $request, Response $response) use ($app) { $app->after(function (Request $request, Response $response) use ($app) {
$app['dispatcher']->dispatch(PhraseaEvents::API_RESULT, new ApiResultEvent($request, $response)); $app['dispatcher']->dispatch(PhraseaEvents::API_RESULT, new ApiResultEvent($request, $response));
}); });
$app['dispatcher']->addSubscriber(new ApiCorsSubscriber($app));
return $app; return $app;
}, isset($environment) ? $environment : PhraseaApplication::ENV_PROD); }, isset($environment) ? $environment : PhraseaApplication::ENV_PROD);

View File

@@ -1,207 +0,0 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Subscriber;
use Alchemy\Phrasea\Application;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
class ApiCorsSubscriber implements EventSubscriberInterface
{
/**
* Simple headers as defined in the spec should always be accepted
*/
protected static $simpleHeaders = [
'accept',
'accept-language',
'content-language',
'origin',
];
private $app;
private $options;
public function __construct(Application $app)
{
$this->app = $app;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 128],
];
}
public function onKernelRequest(GetResponseEvent $event)
{
if (!$this->app['phraseanet.configuration']['api_cors']['enabled']) {
return;
}
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$request = $event->getRequest();
if (!preg_match('{api/v(\d+)}i', $request->getPathInfo() ?: '/')) {
return;
}
// skip if not a CORS request
if (!$request->headers->has('Origin') || $request->headers->get('Origin') == $request->getSchemeAndHttpHost()) {
return;
}
$options = array_merge([
'allow_credentials'=> false,
'allow_origin'=> [],
'allow_headers'=> [],
'allow_methods'=> [],
'expose_headers'=> [],
'max_age'=> 0,
'hosts'=> [],
], $this->app['phraseanet.configuration']['api_cors']);
// skip if the host is not matching
if (!$this->checkHost($request, $options)) {
return;
}
// perform preflight checks
if ('OPTIONS' === $request->getMethod()) {
$event->setResponse($this->getPreflightResponse($request, $options));
return;
}
if (!$this->checkOrigin($request, $options)) {
$response = new Response('', 403, ['Access-Control-Allow-Origin' => 'null']);
$event->setResponse($response);
return;
}
$this->app['dispatcher']->addListener(KernelEvents::RESPONSE, [$this, 'onKernelResponse']);
$this->options = $options;
}
public function onKernelResponse(FilterResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$response = $event->getResponse();
$request = $event->getRequest();
// add CORS response headers
$response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
if ($this->options['allow_credentials']) {
$response->headers->set('Access-Control-Allow-Credentials', 'true');
}
if ($this->options['expose_headers']) {
$response->headers->set('Access-Control-Expose-Headers', strtolower(implode(', ', $this->options['expose_headers'])));
}
}
protected function getPreflightResponse(Request $request, array $options)
{
$response = new Response();
if ($options['allow_credentials']) {
$response->headers->set('Access-Control-Allow-Credentials', 'true');
}
if ($options['allow_methods']) {
$response->headers->set('Access-Control-Allow-Methods', implode(', ', $options['allow_methods']));
}
if ($options['allow_headers']) {
$headers = in_array('*', $options['allow_headers'])
? $request->headers->get('Access-Control-Request-Headers')
: implode(', ', array_map('strtolower', $options['allow_headers']));
$response->headers->set('Access-Control-Allow-Headers', $headers);
}
if ($options['max_age']) {
$response->headers->set('Access-Control-Max-Age', $options['max_age']);
}
if (!$this->checkOrigin($request, $options)) {
$response->headers->set('Access-Control-Allow-Origin', 'null');
return $response;
}
$response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
// check request method
if (!in_array(strtoupper($request->headers->get('Access-Control-Request-Method')), $options['allow_methods'], true)) {
$response->setStatusCode(405);
return $response;
}
/**
* We have to allow the header in the case-set as we received it by the client.
* Firefox f.e. sends the LINK method as "Link", and we have to allow it like this or the browser will deny the
* request.
*/
if (!in_array($request->headers->get('Access-Control-Request-Method'), $options['allow_methods'], true)) {
$options['allow_methods'][] = $request->headers->get('Access-Control-Request-Method');
$response->headers->set('Access-Control-Allow-Methods', implode(', ', $options['allow_methods']));
}
// check request headers
$headers = $request->headers->get('Access-Control-Request-Headers');
if ($options['allow_headers'] !== true && $headers) {
$headers = trim(strtolower($headers));
foreach (preg_split('{, *}', $headers) as $header) {
if (in_array($header, self::$simpleHeaders, true)) {
continue;
}
if (!in_array($header, $options['allow_headers'], true)) {
$response->setStatusCode(400);
$response->setContent('Unauthorized header '.$header);
break;
}
}
}
return $response;
}
protected function checkOrigin(Request $request, array $options)
{
// check origin
$origin = $request->headers->get('Origin');
if (in_array('*', $options['allow_origin']) || in_array($origin, $options['allow_origin'])) {
return true;
}
return false;
}
protected function checkHost(Request $request, array $options)
{
if (count($options['hosts']) === 0) {
return true;
}
foreach ($options['hosts'] as $hostRegexp) {
if (preg_match('{'.$hostRegexp.'}i', $request->getHost())) {
return true;
}
}
return false;
}
}

View File

@@ -1,106 +0,0 @@
<?php
namespace Alchemy\Tests\Phrasea\Core\Event\Subscriber;
use Alchemy\Phrasea\Application;
use Symfony\Component\HttpKernel\Client;
use Alchemy\Phrasea\Core\Event\Subscriber\ApiCorsSubscriber;
class ApiCorsSubscriberTest extends \PHPUnit_Framework_TestCase
{
private $origin = 'http://dev.phrasea.net';
public function testHostRestriction()
{
$response = $this->request(['enabled' => true, 'hosts' => ['http://api.domain.com']]);
$this->assertArrayNotHasKey('access-control-allow-origin', $response->headers->all());
$response = $this->request(['enabled' => true, 'hosts' => ['localhost']]);
$this->assertArrayHasKey('access-control-allow-origin', $response->headers->all());
}
public function testExposeHeaders()
{
$response = $this->request(
['enabled' => true, 'allow_origin' => ['*'], 'expose_headers' => ['HTTP_X_CUSTOM']],
'GET'
);
$this->assertArrayHasKey('access-control-expose-headers', $response->headers->all());
$this->assertEquals('http_x_custom', $response->headers->get('access-control-expose-headers'));
}
public function testAllowMethods()
{
$response = $this->request(
['enabled' => true, 'allow_origin' => ['*'], 'allow_methods' => ['GET', 'POST', 'PUT']],
'OPTIONS'
);
$this->assertArrayHasKey('access-control-allow-methods', $response->headers->all());
$this->assertEquals(implode(', ', ['GET', 'POST', 'PUT']), $response->headers->get('access-control-allow-methods'));
}
public function testAllowHeaders()
{
$response = $this->request(
['enabled' => true, 'allow_origin' => ['*'], 'allow_headers' => ['HTTP_X_CUSTOM']],
'OPTIONS'
);
$this->assertArrayHasKey('access-control-allow-headers', $response->headers->all());
$this->assertEquals('http_x_custom', $response->headers->get('access-control-allow-headers'));
}
public function testCORSIsEnable()
{
$response = $this->request(['enabled' => true]);
$this->assertArrayHasKey('access-control-allow-origin', $response->headers->all());
}
public function testCORSIsDisable()
{
$response = $this->request(['enabled' => false]);
$this->assertArrayNotHasKey('access-control-allow-origin', $response->headers->all());
}
public function testAllowOrigin()
{
$response = $this->request(['enabled' => true, 'allow_origin' => ['*']]);
$this->assertArrayHasKey('access-control-allow-origin', $response->headers->all());
$this->assertEquals($this->origin, $response->headers->get('access-control-allow-origin'));
}
public function testCredentialIsEnabled()
{
$response = $this->request(['enabled' => true, 'allow_credentials' => true, 'allow_origin' => ['*']]);
$this->assertArrayHasKey('access-control-allow-credentials', $response->headers->all());
}
/**
* @param array $conf
* @param string $method
* @param array $extraHeaders
*
* @return \Symfony\Component\HttpFoundation\Response
*/
private function request(array $conf, $method = 'GET', array $extraHeaders = [])
{
$app = new Application(Application::ENV_TEST);
$app['phraseanet.configuration']['api_cors'] = $conf;
$app['dispatcher']->addSubscriber(new ApiCorsSubscriber($app));
$app->get('/api/v1/test-route', function () {
return '';
});
$client = new Client($app);
$client->request($method, '/api/v1/test-route',
[],
[],
array_merge(
$extraHeaders,
[
'HTTP_Origin' => $this->origin,
]
)
);
return $client->getResponse();
}
}