Giter Site home page Giter Site logo

neomerx-cors-psr7's Introduction

Build Status Scrutinizer Code Quality Code Coverage License

Description

This package has framework agnostic Cross-Origin Resource Sharing (CORS) implementation. It is complaint with PSR-7 HTTP message interfaces.

Why this package?

Sample usage

The package is designed to be used as a middleware. Typical usage

use Neomerx\Cors\Analyzer;
use Psr\Http\Message\RequestInterface;
use Neomerx\Cors\Contracts\AnalysisResultInterface;

class CorsMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param RequestInterface $request
     * @param Closure          $next
     *
     * @return mixed
     */
    public function handle(RequestInterface $request, Closure $next)
    {
        $cors = Analyzer::instance($this->getCorsSettings())->analyze($request);
        
        switch ($cors->getRequestType()) {
            case AnalysisResultInterface::ERR_NO_HOST_HEADER:
            case AnalysisResultInterface::ERR_ORIGIN_NOT_ALLOWED:
            case AnalysisResultInterface::ERR_METHOD_NOT_SUPPORTED:
            case AnalysisResultInterface::ERR_HEADERS_NOT_SUPPORTED:
                // return 4XX HTTP error
                return ...;

            case AnalysisResultInterface::TYPE_PRE_FLIGHT_REQUEST:
                $corsHeaders = $cors->getResponseHeaders();
                // return 200 HTTP with $corsHeaders
                return ...;

            case AnalysisResultInterface::TYPE_REQUEST_OUT_OF_CORS_SCOPE:
                // call next middleware handler
                return $next($request);
            
            default:
                // actual CORS request
                $response    = $next($request);
                $corsHeaders = $cors->getResponseHeaders();
                
                // add CORS headers to Response $response
                ...
                return $response;
        }
    }
}

Settings

Analyzer accepts settings in Analyzer::instance($settings) which must implement AnalysisStrategyInterface. You can use default implementation \Neomerx\Cors\Strategies\Settings to set the analyzer up.

For example,

use Neomerx\Cors\Strategies\Settings;

$settings = (new Settings())
    ->setServerOrigin('https', 'api.example.com', 443)
    ->setPreFlightCacheMaxAge(0)
    ->setCredentialsSupported()
    ->setAllowedOrigins(['https://www.example.com', ...]) // or enableAllOriginsAllowed()
    ->setAllowedMethods(['GET', 'POST', 'DELETE', ...])   // or enableAllMethodsAllowed()
    ->setAllowedHeaders(['X-Custom-Header', ...])         // or enableAllHeadersAllowed()
    ->setExposedHeaders(['X-Custom-Header', ...])
    ->disableAddAllowedMethodsToPreFlightResponse()
    ->disableAddAllowedHeadersToPreFlightResponse()
    ->enableCheckHost();

$cors = Analyzer::instance($settings)->analyze($request);

Settings could be cached which improves performance. If you already have settings configured as in the example above you can get internal settings state as

/** @var array $dataToCache */
$dataToCache = $settings->getData();

Cached state should be used as

$settings = (new Settings())->setData($dataFromCache);
$cors     = Analyzer::instance($settings)->analyze($request);

Install

composer require sankaest/neomerx-cors-psr7

Debug Mode

Debug logging will provide a detailed step-by-step description of how requests are handled. In order to activate it a PSR-3 compatible Logger should be set to Analyzer.

/** @var \Psr\Log\LoggerInterface $logger */
$logger   = ...;

$analyzer = Analyzer::instance($settings);
$analyzer->setLogger($logger)
$cors     = $analyzer->analyze($request);

Advanced Usage

There are many possible strategies for handling cross and same origin requests which might and might not depend on data from requests.

This built-in strategy Settings implements simple settings identical for all requests (same list of allowed origins, same allowed methods for all requests and etc).

However you can customize such behaviour. For example you can send different sets of allowed methods depending on request. This might be helpful when you have some kind of Access Control System and wish to differentiate response based on request (for example on its origin). You can either implement AnalysisStrategyInterface from scratch or override methods in Settings class if only a minor changes are needed to Settings. The new strategy could be sent to Analyzer constructor or Analyzer::instance method could be used for injection.

Example

class CustomMethodsSettings extends Settings
{
    public function getRequestAllowedMethods(RequestInterface $request): string
    {
        // An external Access Control System could be used to determine
        // which methods are allowed for this request.
        
        return ...;
    }
}

$cors = Analyzer::instance(new CustomMethodsSettings())->analyze($request);

Testing

composer test

Questions?

Do not hesitate to check issues or post a new one.

Contributing

If you have spotted any compliance issues with the CORS Recommendation please post an issue. Pull requests for documentation and code improvements (PSR-2, tests) are welcome.

Versioning

This package is using Semantic Versioning.

License

Apache License (Version 2.0). Please see License File for more information.

neomerx-cors-psr7's People

Contributors

sankaest avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.