From 09ca1a5c082cfbbb0805d5cbc23d46e507c39fb6 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sat, 19 Mar 2016 12:20:44 +0100 Subject: [PATCH] Support header locking Locking for http header. Throw exceptions. Socket shouldn't be affected by this since these classes are http specific. --- DataStorage/Cookie/CookieJar.php | 16 ++++++++ DataStorage/Session/HttpSession.php | 35 ++++++++++++++++ Message/Http/Response.php | 62 +++++++++++++++++++++++++---- 3 files changed, 106 insertions(+), 7 deletions(-) diff --git a/DataStorage/Cookie/CookieJar.php b/DataStorage/Cookie/CookieJar.php index 443d1cb0e..b310b8dad 100644 --- a/DataStorage/Cookie/CookieJar.php +++ b/DataStorage/Cookie/CookieJar.php @@ -28,6 +28,8 @@ class CookieJar { private $cookies = []; + private static $isLocked = false; + public function __construct() { $this->cookies = $_COOKIE; @@ -70,8 +72,22 @@ class CookieJar public function save() { + if(self::$isLocked) { + throw new \Exception('Already locked'); + } + foreach ($this->cookies as $key => $cookie) { setcookie($key, $cookie['value'], $cookie['expiry'], $cookie['path'], $cookie['domain'], $cookie['secure'], $cookie['httponly']); } } + + public static function lock() + { + self::$isLocked = true; + } + + public static function isLocked() : bool + { + return self::$isLocked; + } } diff --git a/DataStorage/Session/HttpSession.php b/DataStorage/Session/HttpSession.php index 007c06b5f..bfe43dc20 100644 --- a/DataStorage/Session/HttpSession.php +++ b/DataStorage/Session/HttpSession.php @@ -41,6 +41,14 @@ class HttpSession implements SessionInterface */ private $sid = null; + /** + * Is session locked/already set. + * + * @var bool + * @since 1.0.0 + */ + private static $isLocked = false; + /** * Constructor. * @@ -52,6 +60,10 @@ class HttpSession implements SessionInterface */ public function __construct(int $liftetime = 3600, $sid = false) { + if(self::$isLocked) { + throw new \Exception('Already locked'); + } + if (!is_bool($sid)) { session_id($sid); } @@ -62,6 +74,19 @@ class HttpSession implements SessionInterface $_SESSION = null; $this->sid = session_id(); + $this->setCsrfProtection(); + + self::$isLocked = true; + } + + /** + * Set Csrf protection for forms. + * + * @since 1.0.0 + * @author Dennis Eichhorn + */ + private function setCsrfProtection() + { $this->set('UID', 0, false); if(($CSRF = $this->get('CSRF')) === null) { @@ -138,4 +163,14 @@ class HttpSession implements SessionInterface session_write_close(); } + public static function lock() + { + self::$isLocked = true; + } + + public static function isLocked() + { + return self::$isLocked; + } + } diff --git a/Message/Http/Response.php b/Message/Http/Response.php index 82432081c..6259da2f4 100644 --- a/Message/Http/Response.php +++ b/Message/Http/Response.php @@ -51,6 +51,8 @@ class Response extends ResponseAbstract implements RenderableInterface */ private $head = null; + private static $isLocked = false; + /** * Constructor. * @@ -75,9 +77,15 @@ class Response extends ResponseAbstract implements RenderableInterface */ public function pushHeaderId($name) { + if(self::$isLocked) { + throw new \Exception('Already locked'); + } + foreach ($this->header[$name] as $key => $value) { header($name, $value); } + + $this->lock(); } /** @@ -92,6 +100,10 @@ class Response extends ResponseAbstract implements RenderableInterface */ public function removeHeader(int $key) : bool { + if(self::$isLocked) { + throw new \Exception('Already locked'); + } + if (isset($this->header[$key])) { unset($this->header[$key]); @@ -114,18 +126,33 @@ class Response extends ResponseAbstract implements RenderableInterface public function generateHeader(int $code) { if ($code === 403) { - $this->setHeader('HTTP', 'HTTP/1.0 403 Forbidden'); - $this->setHeader('Status', 'Status: HTTP/1.0 403 Forbidden'); + $this->generate403(); } elseif ($code === 406) { - $this->setHeader('HTTP', 'HTTP/1.0 406 Not acceptable'); - $this->setHeader('Status', 'Status:406 Not acceptable'); + $this->generate406(); } elseif ($code === 503) { - $this->setHeader('HTTP', 'HTTP/1.0 503 Service Temporarily Unavailable'); - $this->setHeader('Status', 'Status: 503 Service Temporarily Unavailable'); - $this->setHeader('Retry-After', 'Retry-After: 300'); + $this->generate503(); } } + private function generate403() + { + $this->setHeader('HTTP', 'HTTP/1.0 403 Forbidden'); + $this->setHeader('Status', 'Status: HTTP/1.0 403 Forbidden'); + } + + private function generate406() + { + $this->setHeader('HTTP', 'HTTP/1.0 406 Not acceptable'); + $this->setHeader('Status', 'Status: 406 Not acceptable'); + } + + private function generate503() + { + $this->setHeader('HTTP', 'HTTP/1.0 503 Service Temporarily Unavailable'); + $this->setHeader('Status', 'Status: 503 Service Temporarily Unavailable'); + $this->setHeader('Retry-After', 'Retry-After: 300'); + } + /** * Set response. * @@ -183,11 +210,17 @@ class Response extends ResponseAbstract implements RenderableInterface */ public function pushHeader() { + if(self::$isLocked) { + throw new \Exception('Already locked'); + } + foreach ($this->header as $name => $arr) { foreach ($arr as $ele => $value) { header($name . ': ' . $value); } } + + $this->lock(); } /** @@ -202,6 +235,10 @@ class Response extends ResponseAbstract implements RenderableInterface */ public function remove(int $id) : bool { + if(self::$isLocked) { + throw new \Exception('Already locked'); + } + if (isset($this->response[$id])) { unset($this->response[$id]); @@ -335,6 +372,10 @@ class Response extends ResponseAbstract implements RenderableInterface */ public function setHeader($key, string $header, bool $overwrite = false) : bool { + if(self::$isLocked) { + throw new \Exception('Already locked'); + } + if (!$overwrite && isset($this->header[$key])) { return false; } elseif ($overwrite) { @@ -349,4 +390,11 @@ class Response extends ResponseAbstract implements RenderableInterface return true; } + + private function lock() + { + CookieJar::lock(); + HttpSession::lock(); + self::$isLocked = true; + } }