Skip to content

Commit

Permalink
Merge a9f9140 into 0b54400
Browse files Browse the repository at this point in the history
  • Loading branch information
Orkin committed Aug 25, 2013
2 parents 0b54400 + a9f9140 commit 2f50877
Show file tree
Hide file tree
Showing 9 changed files with 606 additions and 2 deletions.
4 changes: 3 additions & 1 deletion config/module.config.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
'ZfrRest\View\Model\ModelPluginManager' => 'ZfrRest\Factory\ModelPluginManagerFactory',
'ZfrRest\Mvc\View\Http\CreateResourcePayloadListener'
=> 'ZfrRest\Factory\CreateResourcePayloadListenerFactory',
'ZfrRest\Mvc\CorsListener' => 'ZfrRest\Factory\CorsListenerFactory',
)
),

Expand Down Expand Up @@ -91,7 +92,8 @@
'register_http_exception' => true,
'register_create_resource_payload' => true,
'register_select_model' => true,
'register_http_method_override' => false
'register_http_method_override' => false,
'register_cors_support' => false
),

/**
Expand Down
43 changes: 42 additions & 1 deletion config/zfr_rest.local.php.dist
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ return array(
* or manually use the AcceptableViewModelSelector to return the right model according to Content-Type
*/
// 'register_select_model' => true,

/**
* If this listener is registered (it is not by default), it will check before routing any request
* if the request is a preflight OPTIONS request to accept or not a CORS request
*/
// 'register_cors_support' => false
),

/**
Expand Down Expand Up @@ -110,6 +116,41 @@ return array(
* This configuration allow to add classes to the ModelPluginManager. This works like any other
* plugin manager
*/
'models' => array()
'models' => array(),

/**
* This configuration allow to add headers to preflith OPTIONS
*/
'cors' => array(
/**
* Set the list of allowed origins domain.
*/
// 'origins' => array('http://exemple.com'),

/**
* Set the list of rest method verbs.
*/
// 'allowed_methods' => array('GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'),

/**
* Set the list of headers.
*/
// 'allowed_headers' => array('content-type', 'accept'),

/**
* Set the max age of the authorize request in seconds.
*/
// 'max_age' => 10,

/**
* Set the list of exposed headers.
*/
// 'exposed_headers' => array(),

/**
* Allow cors request with credential.
*/
// 'allowed_credentials' => false,
),
)
);
44 changes: 44 additions & 0 deletions src/ZfrRest/Factory/CorsListenerFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/

namespace ZfrRest\Factory;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use ZfrRest\Mvc\CorsListener;
use ZfrRest\Options\ModuleOptions;

/**
* CorsListenerFactory
*
* @license MIT
* @author Florent Blaison <florent.blaison@gmail.com>
*/
class CorsListenerFactory implements FactoryInterface
{
/**
* {@inheritDoc}
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
/* @var $moduleOptions ModuleOptions */
$moduleOptions = $serviceLocator->get('ZfrRest\Options\ModuleOptions');

return new CorsListener($moduleOptions);
}
}
4 changes: 4 additions & 0 deletions src/ZfrRest/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ public function onBootstrap(EventInterface $event)
if ($listenersOptions->getRegisterSelectModel()) {
$eventManager->attach($serviceManager->get('ZfrRest\Mvc\View\Http\SelectModelListener'));
}

if ($listenersOptions->getRegisterCorsSupport()) {
$eventManager->attach($serviceManager->get('ZfrRest\Mvc\CorsListener'));
}
}

/**
Expand Down
105 changes: 105 additions & 0 deletions src/ZfrRest/Mvc/CorsListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/

namespace ZfrRest\Mvc;

use Zend\EventManager\AbstractListenerAggregate;
use Zend\EventManager\EventManagerInterface;
use Zend\Http\Response as HttpResponse;
use Zend\Http\Request as HttpRequest;
use Zend\Mvc\MvcEvent;
use ZfrRest\Options\ModuleOptions;

/**
* CorsListener
*
* @license MIT
* @author Florent Blaison <florent.blaison@gmail.com>
*/
class CorsListener extends AbstractListenerAggregate
{
/**
* @var ModuleOptions
*/
protected $moduleOptions;

/**
* @param ModuleOptions $moduleOptions
*/
public function __construct(ModuleOptions $moduleOptions)
{
$this->moduleOptions = $moduleOptions;
}

/**
* {@inheritDoc}
*/
public function attach(EventManagerInterface $events)
{
$this->listeners[] = $events->attach(MvcEvent::EVENT_ROUTE, array($this, 'onCors'), 1000);
}

/**
* Get the preflight options request authorization
*
* @param MvcEvent $event
* @return mixed
*/
public function onCors(MvcEvent $event)
{
/** @var $request HttpRequest */
$request = $event->getRequest();
$origin = $request->getHeader('Origin', null);
if ($origin === null) {
return;
}

/** @var $response HttpResponse */
$response = $event->getResponse();
$headers = $response->getHeaders();
$corsOptions = $this->moduleOptions->getCors();

if (!in_array($origin->getFieldValue(), $corsOptions->getOrigins())) {
return;
}

$headers->addHeaderLine('Access-Control-Allow-Origin', $origin->getFieldValue());

$method = strtolower($request->getMethod());
if ($method !== 'options') {
return;
}

$requestMethod = $request->getHeader('Access-Control-Request-Method', null);
if ($requestMethod !== null) {
$response->setStatusCode(204);
$headers->addHeaderLine('Access-Control-Allow-Methods', implode(',', $corsOptions->getAllowedMethods()));
$headers->addHeaderLine('Access-Control-Allow-Headers', implode(',', $corsOptions->getAllowedHeaders()));
$headers->addHeaderLine('Access-Control-Max-Age', $corsOptions->getMaxAge());
$headers->addHeaderLine('Content-Length', 0);
if ($corsOptions->getAllowedCredentials()) {
$headers->addHeaderLine('Access-Control-Allow-Credentials', $corsOptions->getAllowedCredentials());
}
} else {
$response->setStatusCode(403);
}

$event->setResult($response);
return $response;
}
}
Loading

0 comments on commit 2f50877

Please sign in to comment.