CorsMiddleware::addExposeHeaders()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 7
ccs 3
cts 3
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chubbyphp\Cors;
6
7
use Chubbyphp\Cors\Negotiation\HeadersNegotiatorInterface;
8
use Chubbyphp\Cors\Negotiation\MethodNegotiatorInterface;
9
use Chubbyphp\Cors\Negotiation\Origin\OriginNegotiatorInterface;
10
use Psr\Http\Message\ResponseFactoryInterface;
11
use Psr\Http\Message\ResponseInterface;
12
use Psr\Http\Message\ServerRequestInterface;
13
use Psr\Http\Server\MiddlewareInterface;
14
use Psr\Http\Server\RequestHandlerInterface;
15
16
final class CorsMiddleware implements MiddlewareInterface
17
{
18
    /**
19
     * @var ResponseFactoryInterface
20
     */
21
    private $responseFactory;
22
23
    /**
24
     * @var OriginNegotiatorInterface
25
     */
26
    private $originNegotiator;
27
28
    /**
29
     * @var MethodNegotiatorInterface
30
     */
31
    private $methodNegotiator;
32
33
    /**
34
     * @var HeadersNegotiatorInterface
35
     */
36
    private $headersNegotiator;
37
38
    /**
39
     * @var array<string>
40
     */
41
    private $exposeHeaders;
42
43
    /**
44
     * @var bool
45
     */
46
    private $allowCredentials;
47
48
    /**
49
     * @var int
50
     */
51
    private $maxAge;
52
53
    /**
54
     * @param array<string> $exposeHeaders
55
     */
56
    public function __construct(
57
        ResponseFactoryInterface $responseFactory,
58
        OriginNegotiatorInterface $originNegotiator,
59
        MethodNegotiatorInterface $methodNegotiator,
60
        HeadersNegotiatorInterface $headersNegotiator,
61
        array $exposeHeaders = [],
62 8
        bool $allowCredentials = false,
63
        int $maxAge = 600
64
    ) {
65
        $this->responseFactory = $responseFactory;
66
        $this->originNegotiator = $originNegotiator;
67
        $this->methodNegotiator = $methodNegotiator;
68
        $this->headersNegotiator = $headersNegotiator;
69
        $this->exposeHeaders = $exposeHeaders;
70
        $this->allowCredentials = $allowCredentials;
71 8
        $this->maxAge = $maxAge;
72 8
    }
73 8
74 8
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
75 8
    {
76 8
        $allowOrigin = $this->originNegotiator->negotiate($request);
77 8
78 8
        if ($this->isPreflight($request)) {
79
            return $this->handlePreflight($request, $allowOrigin);
80 8
        }
81
82 8
        return $this->handle($request, $handler, $allowOrigin);
83
    }
84 8
85 5
    private function isPreflight(ServerRequestInterface $request): bool
86
    {
87
        return 'OPTIONS' === strtoupper($request->getMethod());
88 3
    }
89
90
    private function handlePreflight(ServerRequestInterface $request, ?string $allowOrigin): ResponseInterface
91 8
    {
92
        $response = $this->responseFactory->createResponse(204);
93 8
94
        if (null === $allowOrigin) {
95
            return $response;
96 5
        }
97
98 5
        $response = $this->addAllowOrigin($response, $allowOrigin);
99
        $response = $this->addAllowCredentials($response);
100 5
        $response = $this->addExposeHeaders($response);
101 1
102
        if (!$this->methodNegotiator->negotiate($request)) {
103
            return $response;
104 4
        }
105 4
106 4
        $response = $this->addAllowMethod($response);
107
108 4
        if (!$this->headersNegotiator->negotiate($request)) {
109 1
            return $response;
110
        }
111
112 3
        $response = $this->addAllowHeaders($response);
113
114 3
        return $this->addMaxAge($response);
115 1
    }
116
117
    private function handle(
118 2
        ServerRequestInterface $request,
119
        RequestHandlerInterface $handler,
120 2
        ?string $allowOrigin
121
    ): ResponseInterface {
122
        $response = $handler->handle($request);
123 3
124
        if (null === $allowOrigin) {
125
            return $response;
126
        }
127
128 3
        $response = $this->addAllowOrigin($response, $allowOrigin);
129
        $response = $this->addAllowCredentials($response);
130 3
131 1
        return $this->addExposeHeaders($response);
132
    }
133
134 2
    private function addAllowOrigin(ResponseInterface $response, string $allowOrigin): ResponseInterface
135 2
    {
136
        return $response->withHeader('Access-Control-Allow-Origin', $allowOrigin);
137 2
    }
138
139
    private function addAllowCredentials(ResponseInterface $response): ResponseInterface
140 6
    {
141
        return $response->withHeader('Access-Control-Allow-Credentials', $this->allowCredentials ? 'true' : 'false');
142 6
    }
143
144
    private function addExposeHeaders(ResponseInterface $response): ResponseInterface
145 6
    {
146
        if ([] === $this->exposeHeaders) {
147 6
            return $response;
148
        }
149
150 6
        return $response->withHeader('Access-Control-Expose-Headers', implode(', ', $this->exposeHeaders));
151
    }
152 6
153 4
    private function addAllowMethod(ResponseInterface $response): ResponseInterface
154
    {
155
        return $response->withHeader(
156 2
            'Access-Control-Allow-Methods',
157
            implode(', ', $this->methodNegotiator->getAllowedMethods())
158
        );
159 3
    }
160
161 3
    private function addAllowHeaders(ResponseInterface $response): ResponseInterface
162 3
    {
163 3
        return $response->withHeader(
164
            'Access-Control-Allow-Headers',
165
            implode(', ', $this->headersNegotiator->getAllowedHeaders())
166
        );
167 2
    }
168
169 2
    private function addMaxAge(ResponseInterface $response): ResponseInterface
170 2
    {
171 2
        return $response->withHeader('Access-Control-Max-Age', (string) $this->maxAge);
172
    }
173
}
174