diff --git a/Classes/Netlogix/Cors/Http/Component/CorsComponent.php b/Classes/Netlogix/Cors/Http/Component/CorsComponent.php index 1da9985..92750f4 100755 --- a/Classes/Netlogix/Cors/Http/Component/CorsComponent.php +++ b/Classes/Netlogix/Cors/Http/Component/CorsComponent.php @@ -15,87 +15,90 @@ /** * HTTP component sending CORS (Access-Control-Allow-*) headers. */ -class CorsComponent implements ComponentInterface { +class CorsComponent implements ComponentInterface +{ - /** - * @var array - */ - protected $options; + /** + * @var array + */ + protected $options; - /** - * @param array $options - */ - public function __construct(array $options = array()) { - $this->options = $options; - } + /** + * @param array $options + */ + public function __construct(array $options = array()) + { + $this->options = $options; + } - /** - * If this one is no CORS, this component let pass the request. - * In case of CORS requests, either the allow headers are sent or the - * AccessDeniedException is thrown. - * - * @param ComponentContext $componentContext - * @return void - */ - public function handle(ComponentContext $componentContext) { - static $possibleMethods = array('GET', 'POST', 'OPTIONS', 'DELETE', 'PUT'); + /** + * If this one is no CORS, this component let pass the request. + * In case of CORS requests, either the allow headers are sent or the + * AccessDeniedException is thrown. + * + * @param ComponentContext $componentContext + * @return void + */ + public function handle(ComponentContext $componentContext) + { + static $possibleMethods = array('GET', 'POST', 'OPTIONS', 'DELETE', 'PUT'); - $corsService = new CorsService(); + $corsService = new CorsService(); - /** - * allowedMethods - */ - if (isset($this->options['allowedMethods']) && is_array($this->options['allowedMethods'])) { - $configuredMethods = $this->options['allowedMethods']; - $configuredMethods = array_map('strtoupper', $configuredMethods); - $configuredMethods = array_filter($configuredMethods, function($method) use ($possibleMethods) { - return in_array($method, $possibleMethods); - }); - $corsService->setAllowedMethods($configuredMethods); - } + /** + * allowedMethods + */ + if (isset($this->options['allowedMethods']) && is_array($this->options['allowedMethods'])) { + $configuredMethods = $this->options['allowedMethods']; + $configuredMethods = array_map('strtoupper', $configuredMethods); + $configuredMethods = array_filter($configuredMethods, function ($method) use ($possibleMethods) { + return in_array($method, $possibleMethods); + }); + $corsService->setAllowedMethods($configuredMethods); + } - /** - * allowedOrigins - */ - $configuredOrigins = array(); - if (isset($this->options['allowedOrigins']) && is_array($this->options['allowedOrigins'])) { - $configuredOrigins = array_values($this->options['allowedOrigins']); - } elseif (isset($this->options['allowedOrigins']) && is_string($this->options['allowedOrigins'])) { - $configuredOrigins = Arrays::trimExplode(',', $this->options['allowedOrigins']); - } - $corsService->setAllowedOrigins($configuredOrigins); + /** + * allowedOrigins + */ + $configuredOrigins = array(); + if (isset($this->options['allowedOrigins']) && is_array($this->options['allowedOrigins'])) { + $configuredOrigins = array_values($this->options['allowedOrigins']); + } elseif (isset($this->options['allowedOrigins']) && is_string($this->options['allowedOrigins'])) { + $configuredOrigins = Arrays::trimExplode(',', $this->options['allowedOrigins']); + } + $corsService->setAllowedOrigins($configuredOrigins); - /** - * allowedHeaders - */ - $configuredHeaders = array(); - if (isset($this->options['allowedHeaders']) && is_array($this->options['allowedHeaders'])) { - $configuredHeaders = array_values($this->options['allowedHeaders']); - } elseif (isset($this->options['allowedHeaders']) && is_string($this->options['allowedHeaders'])) { - $configuredHeaders = Arrays::trimExplode(',', $this->options['allowedHeaders']); - } - $corsService->setAllowedHeaders($configuredHeaders); + /** + * allowedHeaders + */ + $configuredHeaders = array(); + if (isset($this->options['allowedHeaders']) && is_array($this->options['allowedHeaders'])) { + $configuredHeaders = array_values($this->options['allowedHeaders']); + } elseif (isset($this->options['allowedHeaders']) && is_string($this->options['allowedHeaders'])) { + $configuredHeaders = Arrays::trimExplode(',', $this->options['allowedHeaders']); + } + $corsService->setAllowedHeaders($configuredHeaders); - /** - * allowCredentials - */ - if (isset($this->options['allowCredentials']) && $this->options['allowCredentials']) { - $corsService->setAllowCredentials(TRUE); - } else { - $corsService->setAllowCredentials(FALSE); - } + /** + * allowCredentials + */ + if (isset($this->options['allowCredentials']) && $this->options['allowCredentials']) { + $corsService->setAllowCredentials(true); + } else { + $corsService->setAllowCredentials(false); + } - /** - * maxAge - */ - if (isset($this->options['maxAge']) && $this->options['maxAge']) { - $corsService->setMaxAge(intval($this->options['maxAge'])); - } else { - $corsService->setMaxAge(600); - } + /** + * maxAge + */ + if (isset($this->options['maxAge']) && $this->options['maxAge']) { + $corsService->setMaxAge(intval($this->options['maxAge'])); + } else { + $corsService->setMaxAge(600); + } - $corsService->sendHeaders(); + $corsService->sendHeaders(); - } + } } \ No newline at end of file diff --git a/Classes/Netlogix/Cors/Service/CorsService.php b/Classes/Netlogix/Cors/Service/CorsService.php index 421b911..9cd34f2 100755 --- a/Classes/Netlogix/Cors/Service/CorsService.php +++ b/Classes/Netlogix/Cors/Service/CorsService.php @@ -13,183 +13,200 @@ /** * Cross Origin Resource Sharing (CORS) service */ -class CorsService { - - /** - * @var int - */ - protected $maxAge = 0; - - /** - * Allowed origin domains - * - * @var array - */ - protected $allowedOrigins = array(); - - /** - * Allowed request methods (GET, POST, OPTIONS, ...) - * - * @var array - */ - protected $allowedMethods = array('GET'); - - /** - * Allowed custom HTTP headers - * - * @var array - */ - protected $allowedHeaders = array(); - - /** - * Whether sending credentials is allowed (cookies, basic auth, ...) - * - * @var bool - */ - protected $allowCredentials = FALSE; - - /** - * @return int - */ - public function getMaxAge() - { - return $this->maxAge; - } - - /** - * @param int $maxAge - */ - public function setMaxAge($maxAge) - { - $this->maxAge = $maxAge; - } - - /** - * @param boolean $allowCredentials - */ - public function setAllowCredentials($allowCredentials) { - $this->allowCredentials = $allowCredentials; - } - - /** - * @return boolean - */ - public function getAllowCredentials() { - return $this->allowCredentials; - } - - /** - * @param array $allowedHeaders - */ - public function setAllowedHeaders($allowedHeaders) { - $this->allowedHeaders = $allowedHeaders; - } - - /** - * @return array - */ - public function getAllowedHeaders() { - return $this->allowedHeaders; - } - - /** - * @param array $allowedMethods - */ - public function setAllowedMethods($allowedMethods) { - $this->allowedMethods = $allowedMethods; - } - - /** - * @return array - */ - public function getAllowedMethods() { - return $this->allowedMethods; - } - - /** - * @param array $allowedOrigins - */ - public function setAllowedOrigins($allowedOrigins) { - $this->allowedOrigins = $allowedOrigins; - } - - /** - * @return array - */ - public function getAllowedOrigins() { - return $this->allowedOrigins; - } - - /** - * Send HTTP headers for current request - */ - public function sendHeaders() { - if (!$this->isCorsRequest()) { - return; - } - - if ($this->isCurrentRequestAllowed()) { - header('Access-Control-Max-Age: ' . $this->maxAge); - header('Access-Control-Allow-Methods: ' . implode(', ', $this->allowedMethods)); - header('Access-Control-Allow-Credentials: ' . ($this->allowCredentials ? 'true' : 'false')); - if (in_array('*', $this->allowedOrigins)) { - header('Access-Control-Allow-Origin: *'); - } else { - header('Access-Control-Allow-Origin: ' . Bootstrap::getEnvironmentConfigurationSetting('HTTP_ORIGIN')); - } - if (!empty($this->allowedHeaders)) { - header('Access-Control-Allow-Headers: ' . implode(', ', $this->allowedHeaders)); - } - } else { - $this->denyRequest(); - } - - if (Bootstrap::getEnvironmentConfigurationSetting('REQUEST_METHOD') === 'OPTIONS' && (Bootstrap::getEnvironmentConfigurationSetting('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') || Bootstrap::getEnvironmentConfigurationSetting('HTTP_ACCESS_CONTROL_REQUEST_METHOD'))) { - exit; - } - } - - /** - * @return bool - */ - protected function isCorsRequest() { - $origin = Bootstrap::getEnvironmentConfigurationSetting('HTTP_ORIGIN'); - if (!$origin) { - return FALSE; - } - if (rtrim($origin, '/') == rtrim(Request::createFromEnvironment()->getBaseUri(), '/')) { - // Unfortunately Chrome always adds the "HTTP_ORIGIN" header to POST, POT and DELETE request. - return FALSE; - } - return TRUE; - } - - /** - * Check whether the current request is allowed according to configuration - * - * @return bool - */ - protected function isCurrentRequestAllowed() { - $currentRequestIsAllowed = TRUE; - - $requestMethod = Bootstrap::getEnvironmentConfigurationSetting('REQUEST_METHOD'); - $requestOrigin = Bootstrap::getEnvironmentConfigurationSetting('HTTP_ORIGIN'); - - if (!in_array($requestMethod, $this->allowedMethods)) { - $currentRequestIsAllowed = FALSE; - } - if ($currentRequestIsAllowed && !in_array($requestOrigin, $this->allowedOrigins) && !in_array('*', $this->allowedOrigins)) { - $currentRequestIsAllowed = FALSE; - } - return $currentRequestIsAllowed; - } - - /** - * Deny request and send forbidden header - * - * @throws \TYPO3\Flow\Http\Exception - */ - protected function denyRequest() { - throw new AccessDeniedException('CORS request not allowed', 1337172748); - } +class CorsService +{ + + /** + * @var int + */ + protected $maxAge = 0; + + /** + * Allowed origin domains + * + * @var array + */ + protected $allowedOrigins = array(); + + /** + * Allowed request methods (GET, POST, OPTIONS, ...) + * + * @var array + */ + protected $allowedMethods = array('GET'); + + /** + * Allowed custom HTTP headers + * + * @var array + */ + protected $allowedHeaders = array(); + + /** + * Whether sending credentials is allowed (cookies, basic auth, ...) + * + * @var bool + */ + protected $allowCredentials = false; + + /** + * @return int + */ + public function getMaxAge() + { + return $this->maxAge; + } + + /** + * @param int $maxAge + */ + public function setMaxAge($maxAge) + { + $this->maxAge = $maxAge; + } + + /** + * @param boolean $allowCredentials + */ + public function setAllowCredentials($allowCredentials) + { + $this->allowCredentials = $allowCredentials; + } + + /** + * @return boolean + */ + public function getAllowCredentials() + { + return $this->allowCredentials; + } + + /** + * @param array $allowedHeaders + */ + public function setAllowedHeaders($allowedHeaders) + { + $this->allowedHeaders = $allowedHeaders; + } + + /** + * @return array + */ + public function getAllowedHeaders() + { + return $this->allowedHeaders; + } + + /** + * @param array $allowedMethods + */ + public function setAllowedMethods($allowedMethods) + { + $this->allowedMethods = $allowedMethods; + } + + /** + * @return array + */ + public function getAllowedMethods() + { + return $this->allowedMethods; + } + + /** + * @param array $allowedOrigins + */ + public function setAllowedOrigins($allowedOrigins) + { + $this->allowedOrigins = $allowedOrigins; + } + + /** + * @return array + */ + public function getAllowedOrigins() + { + return $this->allowedOrigins; + } + + /** + * Send HTTP headers for current request + */ + public function sendHeaders() + { + if (!$this->isCorsRequest()) { + return; + } + + if ($this->isCurrentRequestAllowed()) { + header('Access-Control-Max-Age: ' . $this->maxAge); + header('Access-Control-Allow-Methods: ' . implode(', ', $this->allowedMethods)); + header('Access-Control-Allow-Credentials: ' . ($this->allowCredentials ? 'true' : 'false')); + if (in_array('*', $this->allowedOrigins)) { + header('Access-Control-Allow-Origin: *'); + } else { + header('Access-Control-Allow-Origin: ' . Bootstrap::getEnvironmentConfigurationSetting('HTTP_ORIGIN')); + } + if (!empty($this->allowedHeaders)) { + header('Access-Control-Allow-Headers: ' . implode(', ', $this->allowedHeaders)); + } + } else { + $this->denyRequest(); + } + + if (Bootstrap::getEnvironmentConfigurationSetting('REQUEST_METHOD') === 'OPTIONS' && (Bootstrap::getEnvironmentConfigurationSetting('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') || Bootstrap::getEnvironmentConfigurationSetting('HTTP_ACCESS_CONTROL_REQUEST_METHOD'))) { + exit; + } + } + + /** + * @return bool + */ + protected function isCorsRequest() + { + $origin = Bootstrap::getEnvironmentConfigurationSetting('HTTP_ORIGIN'); + if (!$origin) { + return false; + } + if (rtrim($origin, '/') == rtrim(Request::createFromEnvironment()->getBaseUri(), '/')) { + // Unfortunately Chrome always adds the "HTTP_ORIGIN" header to POST, POT and DELETE request. + return false; + } + + return true; + } + + /** + * Check whether the current request is allowed according to configuration + * + * @return bool + */ + protected function isCurrentRequestAllowed() + { + $currentRequestIsAllowed = true; + + $requestMethod = Bootstrap::getEnvironmentConfigurationSetting('REQUEST_METHOD'); + $requestOrigin = Bootstrap::getEnvironmentConfigurationSetting('HTTP_ORIGIN'); + + if (!in_array($requestMethod, $this->allowedMethods)) { + $currentRequestIsAllowed = false; + } + if ($currentRequestIsAllowed && !in_array($requestOrigin, $this->allowedOrigins) && !in_array('*', + $this->allowedOrigins) + ) { + $currentRequestIsAllowed = false; + } + + return $currentRequestIsAllowed; + } + + /** + * Deny request and send forbidden header + * + * @throws \TYPO3\Flow\Http\Exception + */ + protected function denyRequest() + { + throw new AccessDeniedException('CORS request not allowed', 1337172748); + } } diff --git a/composer.json b/composer.json index 99e86fc..839ee75 100755 --- a/composer.json +++ b/composer.json @@ -1,13 +1,13 @@ { - "name": "netlogix/cors", - "type": "typo3-flow-package", - "description": "Handle CORS requests, basically ported from EXT:nxcors", - "require": { - "typo3/flow": "*" - }, - "autoload": { - "psr-0": { - "Netlogix\\Cors": "Classes" - } + "name": "netlogix/cors", + "type": "typo3-flow-package", + "description": "Handle CORS requests, basically ported from EXT:nxcors", + "require": { + "typo3/flow": "*" + }, + "autoload": { + "psr-0": { + "Netlogix\\Cors": "Classes" } + } } \ No newline at end of file