From d459e58acabf78e9f078c5cf288adfa81c15e288 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Tue, 14 Jan 2020 10:13:02 +0100 Subject: [PATCH 1/4] Response: Add methods to override the client's window id --- library/Icinga/Web/Response.php | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/library/Icinga/Web/Response.php b/library/Icinga/Web/Response.php index 88d9e2302..d869f8f09 100644 --- a/library/Icinga/Web/Response.php +++ b/library/Icinga/Web/Response.php @@ -61,6 +61,13 @@ class Response extends Zend_Controller_Response_Http */ protected $rerenderLayout = false; + /** + * Whether to send the current window ID to the client + * + * @var bool + */ + protected $overrideWindowId = false; + /** * Get the auto-refresh interval * @@ -237,6 +244,29 @@ class Response extends Zend_Controller_Response_Http return $this; } + /** + * Get whether to send the current window ID to the client + * + * @return bool + */ + public function getOverrideWindowId() + { + return $this->overrideWindowId; + } + + /** + * Set whether to send the current window ID to the client + * + * @param bool $overrideWindowId + * + * @return $this + */ + public function setOverrideWindowId($overrideWindowId = true) + { + $this->overrideWindowId = $overrideWindowId; + return $this; + } + /** * Entry point for HTTP responses in JSON format * @@ -262,6 +292,9 @@ class Response extends Zend_Controller_Response_Http $this->setHeader('X-Icinga-Rerender-Layout', 'yes', true); } } + if ($this->getOverrideWindowId()) { + $this->setHeader('X-Icinga-WindowId', Window::getInstance()->getId(), true); + } if ($this->getRerenderLayout()) { $this->setHeader('X-Icinga-Container', 'layout', true); } From 2d3fc218db53258ec63e11500f403ff3c51cfd20 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Tue, 14 Jan 2020 09:42:33 +0100 Subject: [PATCH 2/4] Window: Differentiate between window and container id --- library/Icinga/Web/Window.php | 69 ++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 5 deletions(-) diff --git a/library/Icinga/Web/Window.php b/library/Icinga/Web/Window.php index e6f1a05e1..7b43d0536 100644 --- a/library/Icinga/Web/Window.php +++ b/library/Icinga/Web/Window.php @@ -3,29 +3,63 @@ namespace Icinga\Web; -use Icinga\Web\Session; +use Icinga\Application\Icinga; +use Icinga\Web\Session\SessionNamespace; class Window { const UNDEFINED = 'undefined'; + /** @var Window */ + protected static $window; + + /** @var string */ protected $id; + /** @var string */ + protected $containerId; + public function __construct($id) { - $this->id = $id; + $parts = explode('_', $id, 2); + if (isset($parts[1])) { + $this->id = $parts[0]; + $this->containerId = $id; + } else { + $this->id = $id; + } } + /** + * Get whether the window's ID is undefined + * + * @return bool + */ public function isUndefined() { return $this->id === self::UNDEFINED; } + /** + * Get the window's ID + * + * @return string + */ public function getId() { return $this->id; } + /** + * Get the container's ID + * + * @return string + */ + public function getContainerId() + { + return $this->containerId ?: $this->id; + } + /** * Return a window-aware session by using the given prefix * @@ -38,29 +72,54 @@ class Window { $session = Session::getSession(); - $identifier = $prefix . '_' . $this->id; + $identifier = $prefix . '_' . $this->getId(); if ($reset && $session->hasNamespace($identifier)) { $session->removeNamespace($identifier); } + $namespace = $session->getNamespace($identifier); $nsUndef = $prefix . '_' . self::UNDEFINED; - if (!$reset && $this->id !== self::UNDEFINED && $session->hasNamespace($nsUndef)) { - // We do not have any window-id on the very first request. Now we add + if (! $reset && ! $this->isUndefined() && $session->hasNamespace($nsUndef)) { + // We may not have any window-id on the very first request. Now we add // all values from the namespace, that has been created in this case, // to the new one and remove it afterwards. foreach ($session->getNamespace($nsUndef) as $name => $value) { $namespace->set($name, $value); } + $session->removeNamespace($nsUndef); } return $namespace; } + /** + * Generate a random string + * + * @return string + */ public static function generateId() { $letters = 'abcefghijklmnopqrstuvwxyz'; return substr(str_shuffle($letters), 0, 12); } + + /** + * @return Window + */ + public static function getInstance() + { + if (! isset(static::$window)) { + $id = Icinga::app()->getRequest()->getHeader('X-Icinga-WindowId'); + if (empty($id) || $id === static::UNDEFINED) { + $id = static::generateId(); + Icinga::app()->getResponse()->setHeader('X-Icinga-WindowId', $id); + } + + static::$window = new Window($id); + } + + return static::$window; + } } From 855bb8ae72c4437b0945326e16163a3b4eaee966 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Tue, 14 Jan 2020 09:46:26 +0100 Subject: [PATCH 3/4] Properly handle window id's and container id's --- library/Icinga/Web/Controller/ActionController.php | 5 ++--- library/Icinga/Web/Request.php | 7 +------ library/Icinga/Web/Window.php | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/library/Icinga/Web/Controller/ActionController.php b/library/Icinga/Web/Controller/ActionController.php index 7a8aa0e7e..ecb2dfa3f 100644 --- a/library/Icinga/Web/Controller/ActionController.php +++ b/library/Icinga/Web/Controller/ActionController.php @@ -229,10 +229,9 @@ class ActionController extends Zend_Controller_Action public function Window() { if ($this->window === null) { - $this->window = new Window( - $this->_request->getHeader('X-Icinga-WindowId', Window::UNDEFINED) - ); + $this->window = Window::getInstance(); } + return $this->window; } diff --git a/library/Icinga/Web/Request.php b/library/Icinga/Web/Request.php index 4a3246d5f..064ce6335 100644 --- a/library/Icinga/Web/Request.php +++ b/library/Icinga/Web/Request.php @@ -114,12 +114,7 @@ class Request extends Zend_Controller_Request_Http */ public function protectId($id) { - if (! isset($this->uniqueId)) { - $windowId = $this->getHeader('X-Icinga-WindowId'); - $this->uniqueId = empty($windowId) ? Window::generateId() : $windowId; - } - - return $id . '-' . $this->uniqueId; + return $id . '-' . Window::getInstance()->getContainerId(); } public function getPost($key = null, $default = null) diff --git a/library/Icinga/Web/Window.php b/library/Icinga/Web/Window.php index 7b43d0536..158483a06 100644 --- a/library/Icinga/Web/Window.php +++ b/library/Icinga/Web/Window.php @@ -113,8 +113,8 @@ class Window if (! isset(static::$window)) { $id = Icinga::app()->getRequest()->getHeader('X-Icinga-WindowId'); if (empty($id) || $id === static::UNDEFINED) { + Icinga::app()->getResponse()->setOverrideWindowId(); $id = static::generateId(); - Icinga::app()->getResponse()->setHeader('X-Icinga-WindowId', $id); } static::$window = new Window($id); From 9fe43dda5f0ea1ccca8665d0e5dbf582ab7b4b68 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Tue, 14 Jan 2020 09:46:50 +0100 Subject: [PATCH 4/4] ActionController: Drop method `handlerBrowserWindows()` --- library/Icinga/Web/Controller/ActionController.php | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/library/Icinga/Web/Controller/ActionController.php b/library/Icinga/Web/Controller/ActionController.php index ecb2dfa3f..e1324c3d9 100644 --- a/library/Icinga/Web/Controller/ActionController.php +++ b/library/Icinga/Web/Controller/ActionController.php @@ -122,7 +122,6 @@ class ActionController extends Zend_Controller_Action ->_setInvokeArgs($invokeArgs); $this->_helper = new Zend_Controller_Action_HelperBroker($this); - $this->handlerBrowserWindows(); $moduleName = $this->getModuleName(); $this->view->defaultTitle = static::DEFAULT_TITLE; $this->view->translationDomain = $moduleName !== 'default' ? $moduleName : 'icinga'; @@ -235,18 +234,6 @@ class ActionController extends Zend_Controller_Action return $this->window; } - protected function handlerBrowserWindows() - { - if ($this->isXhr()) { - $id = $this->_request->getHeader('X-Icinga-WindowId', null); - - if ($id === Window::UNDEFINED) { - $this->window = new Window($id); - $this->_response->setHeader('X-Icinga-WindowId', Window::generateId()); - } - } - } - protected function reloadCss() { $this->reloadCss = true;