Skip to content

Commit

Permalink
CORS support (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
domino91 authored Nov 5, 2024
1 parent 9ef7ad5 commit b3e0d3f
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/DependencyInjection/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Freddie\Hub\Hub;
use Freddie\Hub\HubControllerInterface;
use Freddie\Hub\HubInterface;
use Freddie\Hub\Middleware\CorsMiddleware;
use Freddie\Hub\Middleware\HttpExceptionConverterMiddleware;
use Freddie\Hub\Middleware\TokenExtractorMiddleware;
use Freddie\Hub\Transport\TransportFactory;
Expand Down Expand Up @@ -111,6 +112,7 @@
$services
->set(App::class)
->args([
service(CorsMiddleware::class),
service(HttpExceptionConverterMiddleware::class),
service(TokenExtractorMiddleware::class),
]);
Expand All @@ -124,6 +126,12 @@
$services
->set(Factory::class);

$services
->set(CorsMiddleware::class)
->args([
param('env(string:default::CORS_ORIGINS)')
]);

$services
->set(Configuration::class)
->factory(service(ConfigurationFactory::class))
Expand Down
35 changes: 35 additions & 0 deletions src/Hub/Middleware/CorsMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Freddie\Hub\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use React\Http\Message\Response;

final class CorsMiddleware
{
public function __construct(
private readonly ?string $corsOrigin = '*',
) {
}

public function __invoke(
ServerRequestInterface $request,
callable $next
): ResponseInterface {
$response = $next($request);

$corsOrigin = $this->corsOrigin ?? $this->getOrigin($request);

return $response->withAddedHeader('Access-Control-Allow-Origin', $corsOrigin)
->withAddedHeader('Access-Control-Allow-Headers', '*')
->withAddedHeader('Access-Control-Allow-Methods', '*')
->withAddedHeader('Access-Control-Allow-Credentials', 'true')
->withStatus(Response::STATUS_OK);
}

private function getOrigin(ServerRequestInterface $request): string
{
return $request->getHeaderLine('Origin') ?: 'null';
}
}
48 changes: 48 additions & 0 deletions tests/Unit/Hub/Middleware/CorsMiddlewareTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Freddie\Tests\Unit\Hub\Middleware;

use FrameworkX\App;
use Freddie\Hub\Middleware\CorsMiddleware;
use React\Http\Message\Response;
use React\Http\Message\ServerRequest;

use function expect;
use function Freddie\Tests\handle;
use function it;

it('decorates response with CORS mechanism', function () {
// Given
$corsOrigins = 'http://testdomain.local';
$expectedResponse = new Response(200);
$app = new App(new CorsMiddleware($corsOrigins), fn () => $expectedResponse);
$request = new ServerRequest('POST', './well-known/mercure');

// When
$response = handle($app, $request);

// Then
expect($response->getHeaderLine('Access-Control-Allow-Origin'))->toBe($corsOrigins)
->and($response->getHeaderLine('Access-Control-Allow-Methods'))->toBe('*')
->and($response->getHeaderLine('Access-Control-Allow-Headers'))->toBe('*')
->and($response->getHeaderLine('Access-Control-Allow-Credentials'))->toBe('true');
});

it('decorates response with CORS mechanism with default corsOrigin setup', function () {
// Given
$corsOrigins = null;
$expectedResponse = new Response(400);
$app = new App(new CorsMiddleware($corsOrigins), fn () => $expectedResponse);
$request = new ServerRequest('POST', './well-known/mercure');

// When
$response = handle($app, $request);

// Then
expect($response->getHeaderLine('Access-Control-Allow-Origin'))->toBe('null')
->and($response->getHeaderLine('Access-Control-Allow-Methods'))->toBe('*')
->and($response->getHeaderLine('Access-Control-Allow-Headers'))->toBe('*')
->and($response->getHeaderLine('Access-Control-Allow-Credentials'))->toBe('true');
});

0 comments on commit b3e0d3f

Please sign in to comment.