1 | <?php |
||
2 | |||
3 | namespace ByJG\RestServer\Middleware; |
||
4 | |||
5 | use ByJG\RestServer\Exception\Error401Exception; |
||
6 | use ByJG\RestServer\HttpRequest; |
||
7 | use ByJG\RestServer\HttpResponse; |
||
8 | use ByJG\RestServer\ResponseBag; |
||
9 | |||
10 | class CorsMiddleware implements BeforeMiddlewareInterface |
||
11 | { |
||
12 | |||
13 | const CORS_OK = 'CORS_OK'; |
||
14 | const CORS_FAILED = 'CORS_FAILED'; |
||
15 | const CORS_OPTIONS = 'CORS_OPTIONS'; |
||
16 | |||
17 | protected $corsOrigins = ['.*']; |
||
18 | protected $corsMethods = [ 'GET', 'POST', 'PUT', 'DELETE', 'PATCH']; |
||
19 | protected $corsHeaders = [ |
||
20 | 'Authorization', |
||
21 | 'Content-Type', |
||
22 | 'Accept', |
||
23 | 'Origin', |
||
24 | 'User-Agent', |
||
25 | 'Cache-Control', |
||
26 | 'Keep-Alive', |
||
27 | 'X-Requested-With', |
||
28 | 'If-Modified-Since' |
||
29 | ]; |
||
30 | |||
31 | /** |
||
32 | * Undocumented function |
||
33 | * |
||
34 | * @param mixed $dispatcherStatus |
||
35 | * @param HttpResponse $response |
||
36 | * @param HttpRequest $request |
||
37 | * @return MiddlewareResult |
||
38 | */ |
||
39 | 4 | public function beforeProcess( |
|
40 | $dispatcherStatus, |
||
41 | HttpResponse $response, |
||
42 | HttpRequest $request |
||
43 | ) |
||
44 | { |
||
45 | 4 | $corsStatus = $this->preFlight($response, $request); |
|
46 | 4 | if ($corsStatus != self::CORS_OK) { |
|
47 | 2 | if ($corsStatus == self::CORS_OPTIONS) { |
|
48 | 1 | $response->emptyResponse(); |
|
49 | 1 | $response->getResponseBag()->setSerializationRule(ResponseBag::RAW); |
|
50 | 1 | return MiddlewareResult::stopProcessingOthers(); |
|
51 | 1 | } elseif ($corsStatus == self::CORS_FAILED) { |
|
52 | 1 | throw new Error401Exception("CORS verification failed. Request Blocked."); |
|
53 | } |
||
54 | } |
||
55 | |||
56 | 2 | return MiddlewareResult::continue(); |
|
57 | } |
||
58 | |||
59 | /** |
||
60 | * Undocumented function |
||
61 | * |
||
62 | * @param HttpResponse $response |
||
63 | * @param HttpRequest $request |
||
64 | * @return string |
||
65 | */ |
||
66 | 4 | protected function preFlight(HttpResponse $response, HttpRequest $request) |
|
67 | { |
||
68 | // TODO: Still missing some headers |
||
69 | // https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request |
||
70 | 4 | $corsStatus = self::CORS_OK; |
|
71 | |||
72 | 4 | if (!empty($request->server('HTTP_ORIGIN'))) { |
|
73 | 4 | $corsStatus = self::CORS_FAILED; |
|
74 | |||
75 | 4 | foreach ((array)$this->corsOrigins as $origin) { |
|
76 | 4 | if (preg_match("~^.*//$origin$~", $request->server('HTTP_ORIGIN'))) { |
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
77 | 3 | $response->addHeader("Access-Control-Allow-Origin", $request->server('HTTP_ORIGIN')); |
|
78 | 3 | $response->addHeader('Access-Control-Allow-Credentials', 'true'); |
|
79 | 3 | $response->addHeader('Access-Control-Max-Age', '86400'); // cache for 1 day |
|
80 | |||
81 | // Access-Control headers are received during OPTIONS requests |
||
82 | 3 | if ($request->server('REQUEST_METHOD') == 'OPTIONS') { |
|
83 | 1 | $response->setResponseCode(204, 'No Content'); |
|
84 | 1 | $response->addHeader("Access-Control-Allow-Methods", implode(",", array_merge(['OPTIONS'], $this->corsMethods))); |
|
85 | 1 | $response->addHeader("Access-Control-Allow-Headers", implode(",", $this->corsHeaders)); |
|
86 | 1 | return self::CORS_OPTIONS; |
|
87 | } |
||
88 | 2 | $corsStatus = self::CORS_OK; |
|
89 | 2 | break; |
|
90 | } |
||
91 | } |
||
92 | } |
||
93 | 3 | return $corsStatus; |
|
94 | } |
||
95 | |||
96 | 2 | public function withCorsOrigins($origins) |
|
97 | { |
||
98 | 2 | $this->corsOrigins = $origins; |
|
99 | 2 | return $this; |
|
100 | } |
||
101 | |||
102 | public function withAcceptCorsHeaders($headers) |
||
103 | { |
||
104 | $this->corsHeaders = $headers; |
||
105 | return $this; |
||
106 | } |
||
107 | |||
108 | public function withAcceptCorsMethods($methods) |
||
109 | { |
||
110 | $this->corsMethods = $methods; |
||
111 | return $this; |
||
112 | } |
||
113 | } |
||
114 |