Cors::__invoke()   D
last analyzed

Complexity

Conditions 10
Paths 18

Size

Total Lines 37
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 4.8196
c 0
b 0
f 0
cc 10
eloc 22
nc 18
nop 3

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Psr7Middlewares\Middleware;
4
5
use Psr\Http\Message\ServerRequestInterface;
6
use Psr\Http\Message\ResponseInterface;
7
use Psr\Log\LoggerInterface;
8
use Neomerx\Cors\Analyzer;
9
use Neomerx\Cors\Contracts\AnalysisResultInterface;
10
use Neomerx\Cors\Contracts\Strategies\SettingsStrategyInterface;
11
use Neomerx\Cors\Strategies\Settings;
12
13
/**
14
 * Middleware to implement Cors.
15
 */
16
class Cors
17
{
18
    /**
19
     * @var SettingsStrategyInterface The settings used by the Analyzer
20
     */
21
    private $settings;
22
23
    /**
24
     * @var LoggerInterface|null The logger used by the Analyzer for debugging
25
     */
26
    private $logger;
27
28
    /**
29
     * Defines the settings used.
30
     *
31
     * @param SettingsStrategyInterface|null $settings
32
     */
33
    public function __construct(SettingsStrategyInterface $settings = null)
34
    {
35
        $this->settings = $settings ?: new Settings();
36
    }
37
38
    /**
39
     * Set the server origin.
40
     *
41
     * @see Neomerx\Cors\Contracts\Strategies::setServerOrigin
42
     *
43
     * @param string|array $origin
44
     *
45
     * @return self
46
     */
47
    public function origin($origin)
48
    {
49
        $this->settings->setServerOrigin($origin);
50
51
        return $this;
52
    }
53
54
    /**
55
     * Set allowed origins.
56
     *
57
     * @see Neomerx\Cors\Contracts\Strategies::setRequestAllowedOrigins
58
     *
59
     * @param array $origins
60
     *
61
     * @return self
62
     */
63
    public function allowedOrigins(array $origins)
64
    {
65
        $this->settings->setRequestAllowedOrigins($origins);
66
67
        return $this;
68
    }
69
70
    /**
71
     * Set allowed methods.
72
     *
73
     * @see Neomerx\Cors\Contracts\Strategies::setRequestAllowedMethods
74
     * @see Neomerx\Cors\Contracts\Strategies::setForceAddAllowedMethodsToPreFlightResponse
75
     *
76
     * @param array $methods
77
     * @param bool  $force   If allowed methods should be added to pre-flight response
78
     *
79
     * @return self
80
     */
81
    public function allowedMethods(array $methods, $force = false)
82
    {
83
        $this->settings->setRequestAllowedMethods($methods);
84
        $this->settings->setForceAddAllowedMethodsToPreFlightResponse($force);
85
86
        return $this;
87
    }
88
89
    /**
90
     * Set allowed headers.
91
     *
92
     * @see Neomerx\Cors\Contracts\Strategies::setRequestAllowedHeaders
93
     * @see Neomerx\Cors\Contracts\Strategies::setForceAddAllowedHeadersToPreFlightResponse
94
     *
95
     * @param array $headers
96
     * @param bool  $force   If allowed headers should be added to pre-flight response
97
     *
98
     * @return self
99
     */
100
    public function allowedHeaders(array $headers, $force = false)
101
    {
102
        $this->settings->setRequestAllowedHeaders($headers);
103
        $this->settings->setForceAddAllowedHeadersToPreFlightResponse($force);
104
105
        return $this;
106
    }
107
108
    /**
109
     * Set headers other than the simple ones that might be exposed to user agent.
110
     *
111
     * @see Neomerx\Cors\Contracts\Strategies::setResponseExposedHeaders
112
     *
113
     * @param array $headers
114
     *
115
     * @return self
116
     */
117
    public function exposedHeaders(array $headers)
118
    {
119
        $this->settings->setResponseExposedHeaders($headers);
120
121
        return $this;
122
    }
123
124
    /**
125
     * If access with credentials is supported by the resource.
126
     *
127
     * @see Neomerx\Cors\Contracts\Strategies::setRequestCredentialsSupported
128
     *
129
     * @param bool $allow
130
     *
131
     * @return self
132
     */
133
    public function allowCredentials($allow = true)
134
    {
135
        $this->settings->setRequestCredentialsSupported($allow);
136
137
        return $this;
138
    }
139
140
    /**
141
     * Set pre-flight cache max period in seconds.
142
     *
143
     * @see Neomerx\Cors\Contracts\Strategies::setPreFlightCacheMaxAge
144
     *
145
     * @param int $maxAge
146
     *
147
     * @return self
148
     */
149
    public function maxAge($maxAge)
150
    {
151
        $this->settings->setPreFlightCacheMaxAge($maxAge);
152
153
        return $this;
154
    }
155
156
    /**
157
     * If request 'Host' header should be checked against server's origin.
158
     *
159
     * @see Neomerx\Cors\Contracts\Strategies::setCheckHost
160
     *
161
     * @param bool $checkHost
162
     *
163
     * @return self
164
     */
165
    public function checkHost($checkHost = true)
166
    {
167
        $this->settings->setCheckHost($checkHost);
168
169
        return $this;
170
    }
171
172
    /**
173
     * Set the logger used by the Analyzer for debugging purposes.
174
     *
175
     * @param LoggerInterface
176
     *
177
     * @return self
178
     */
179
    public function logger(LoggerInterface $logger)
180
    {
181
        $this->logger = $logger;
182
183
        return $this;
184
    }
185
186
    /**
187
     * Execute the middleware.
188
     *
189
     * @param ServerRequestInterface $request
190
     * @param ResponseInterface      $response
191
     * @param callable               $next
192
     *
193
     * @return ResponseInterface
194
     */
195
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
196
    {
197
        $analyzer = Analyzer::instance($this->settings);
198
199
        if ($this->logger instanceof LoggerInterface) {
200
            $analyzer->setLogger($this->logger);
201
        }
202
203
        $cors = $analyzer->analyze($request);
204
205
        switch ($cors->getRequestType()) {
206
            case AnalysisResultInterface::ERR_NO_HOST_HEADER:
207
            case AnalysisResultInterface::ERR_ORIGIN_NOT_ALLOWED:
208
            case AnalysisResultInterface::ERR_METHOD_NOT_SUPPORTED:
209
            case AnalysisResultInterface::ERR_HEADERS_NOT_SUPPORTED:
210
                return $response->withStatus(403);
211
212
            case AnalysisResultInterface::TYPE_REQUEST_OUT_OF_CORS_SCOPE:
213
                return $next($request, $response);
214
215
            case AnalysisResultInterface::TYPE_PRE_FLIGHT_REQUEST:
216
                foreach ($cors->getResponseHeaders() as $name => $value) {
217
                    $response = $response->withHeader($name, $value);
218
                }
219
220
                return $response->withStatus(200);
221
222
            default:
223
                $response = $next($request, $response);
224
225
                foreach ($cors->getResponseHeaders() as $name => $value) {
226
                    $response = $response->withHeader($name, $value);
227
                }
228
229
                return $response;
230
        }
231
    }
232
}
233