91 lines
3.6 KiB
PHP
91 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace NoccyLabs\Mercureact\Http\Middleware;
|
|
|
|
use NoccyLabs\Mercureact\Configuration;
|
|
use NoccyLabs\Mercureact\Exception\SecurityException;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
use React\Http\Message\Response;
|
|
use React\Promise\Promise;
|
|
use React\Promise\PromiseInterface;
|
|
use Throwable;
|
|
|
|
class ResponseMiddleware
|
|
{
|
|
|
|
public function __construct(
|
|
private Configuration $config,
|
|
private LoggerInterface $logger,
|
|
)
|
|
{
|
|
|
|
}
|
|
|
|
/**
|
|
* Wraps rejections into error messages, and also does some sanity checks on the returned
|
|
* data, making sure it is a response.
|
|
*
|
|
* @param ServerRequestInterface $request
|
|
* @param callable $next
|
|
* @return PromiseInterface
|
|
*/
|
|
public function __invoke(ServerRequestInterface $request, callable $next): PromiseInterface
|
|
{
|
|
$promise = new Promise(
|
|
function (callable $resolve) use ($request, $next) {
|
|
$resolve($next($request));
|
|
}
|
|
);
|
|
return $promise->then(
|
|
function ($response) {
|
|
if ($response instanceof ResponseInterface) {
|
|
return $response;
|
|
}
|
|
if (is_array($response)) {
|
|
return Response::json($response);
|
|
}
|
|
if (is_string($response)) {
|
|
return Response::plaintext($response);
|
|
}
|
|
return Response::plaintext((string)$response);
|
|
},
|
|
function (Throwable $t) {
|
|
if ($t instanceof SecurityException) {
|
|
return Response::plaintext("Access Denied")->withStatus(Response::STATUS_UNAUTHORIZED);
|
|
}
|
|
$this->logger->warning(get_class($t).": ".$t->getMessage(), [ 'file'=>$t->getFile(), 'line'=>$t->getLine() ]);
|
|
return Response::plaintext("500: Internal Server Error (".$t->getMessage().")\n")->withStatus(500);
|
|
}
|
|
)->then(
|
|
function ($response) use ($request) {
|
|
assert("\$response instanceof ResponseInterface");
|
|
$host = ($request->getServerParams()['SERVER_ADDR']??"");
|
|
//. ":" . ($request->getServerParams()['SERVER_PORT']??"80");
|
|
$this->logger->debug(sprintf("%s %s %s → %3d (%d)",
|
|
$request->getServerParams()['REMOTE_ADDR'],
|
|
$request->getMethod(),
|
|
$request->getUri()->getPath(),
|
|
$response->getStatusCode(),
|
|
strlen($response->getBody())
|
|
), [
|
|
'remote' => $request->getServerParams()['REMOTE_ADDR'],
|
|
'status' => $response->getStatusCode(),
|
|
'method' => $request->getMethod(),
|
|
'path' => $request->getUri()->getPath(),
|
|
]);
|
|
|
|
return $response
|
|
// ->withAddedHeader('Link', '<https://'.$host.'/.well-known/mercure>; rel="mercure"')
|
|
// ->withAddedHeader('Link', '<wss://'.$host.'/.well-known/mercure>; rel="mercure+ws"')
|
|
->withHeader('Access-Control-Allow-Origin',
|
|
$this->config->get('server.cors.allow_origin', '*'))
|
|
->withHeader('Content-Security-Policy',
|
|
$this->config->get('server.cors.csp', "default-src * 'self' http: 'unsafe-eval' 'unsafe-inline'; connect-src * 'self'"))
|
|
->withHeader('Cache-Control', 'must-revalidate')
|
|
->withHeader('Server', 'Mercureact/0.1.0');
|
|
}
|
|
);
|
|
}
|
|
} |