Merge pull request #4048 from Icinga/fix/server-side-window-handling

Fix server side window handling
This commit is contained in:
Johannes Meyer 2020-01-16 08:57:11 +01:00 committed by GitHub
commit 69d15824fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 27 deletions

View File

@ -122,7 +122,6 @@ class ActionController extends Zend_Controller_Action
->_setInvokeArgs($invokeArgs); ->_setInvokeArgs($invokeArgs);
$this->_helper = new Zend_Controller_Action_HelperBroker($this); $this->_helper = new Zend_Controller_Action_HelperBroker($this);
$this->handlerBrowserWindows();
$moduleName = $this->getModuleName(); $moduleName = $this->getModuleName();
$this->view->defaultTitle = static::DEFAULT_TITLE; $this->view->defaultTitle = static::DEFAULT_TITLE;
$this->view->translationDomain = $moduleName !== 'default' ? $moduleName : 'icinga'; $this->view->translationDomain = $moduleName !== 'default' ? $moduleName : 'icinga';
@ -229,25 +228,12 @@ class ActionController extends Zend_Controller_Action
public function Window() public function Window()
{ {
if ($this->window === null) { if ($this->window === null) {
$this->window = new Window( $this->window = Window::getInstance();
$this->_request->getHeader('X-Icinga-WindowId', Window::UNDEFINED)
);
} }
return $this->window; 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() protected function reloadCss()
{ {
$this->reloadCss = true; $this->reloadCss = true;

View File

@ -114,12 +114,7 @@ class Request extends Zend_Controller_Request_Http
*/ */
public function protectId($id) public function protectId($id)
{ {
if (! isset($this->uniqueId)) { return $id . '-' . Window::getInstance()->getContainerId();
$windowId = $this->getHeader('X-Icinga-WindowId');
$this->uniqueId = empty($windowId) ? Window::generateId() : $windowId;
}
return $id . '-' . $this->uniqueId;
} }
public function getPost($key = null, $default = null) public function getPost($key = null, $default = null)

View File

@ -61,6 +61,13 @@ class Response extends Zend_Controller_Response_Http
*/ */
protected $rerenderLayout = false; protected $rerenderLayout = false;
/**
* Whether to send the current window ID to the client
*
* @var bool
*/
protected $overrideWindowId = false;
/** /**
* Get the auto-refresh interval * Get the auto-refresh interval
* *
@ -237,6 +244,29 @@ class Response extends Zend_Controller_Response_Http
return $this; 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 * 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); $this->setHeader('X-Icinga-Rerender-Layout', 'yes', true);
} }
} }
if ($this->getOverrideWindowId()) {
$this->setHeader('X-Icinga-WindowId', Window::getInstance()->getId(), true);
}
if ($this->getRerenderLayout()) { if ($this->getRerenderLayout()) {
$this->setHeader('X-Icinga-Container', 'layout', true); $this->setHeader('X-Icinga-Container', 'layout', true);
} }

View File

@ -3,29 +3,63 @@
namespace Icinga\Web; namespace Icinga\Web;
use Icinga\Web\Session; use Icinga\Application\Icinga;
use Icinga\Web\Session\SessionNamespace;
class Window class Window
{ {
const UNDEFINED = 'undefined'; const UNDEFINED = 'undefined';
/** @var Window */
protected static $window;
/** @var string */
protected $id; protected $id;
/** @var string */
protected $containerId;
public function __construct($id) 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() public function isUndefined()
{ {
return $this->id === self::UNDEFINED; return $this->id === self::UNDEFINED;
} }
/**
* Get the window's ID
*
* @return string
*/
public function getId() public function getId()
{ {
return $this->id; 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 * Return a window-aware session by using the given prefix
* *
@ -38,29 +72,54 @@ class Window
{ {
$session = Session::getSession(); $session = Session::getSession();
$identifier = $prefix . '_' . $this->id; $identifier = $prefix . '_' . $this->getId();
if ($reset && $session->hasNamespace($identifier)) { if ($reset && $session->hasNamespace($identifier)) {
$session->removeNamespace($identifier); $session->removeNamespace($identifier);
} }
$namespace = $session->getNamespace($identifier); $namespace = $session->getNamespace($identifier);
$nsUndef = $prefix . '_' . self::UNDEFINED; $nsUndef = $prefix . '_' . self::UNDEFINED;
if (!$reset && $this->id !== self::UNDEFINED && $session->hasNamespace($nsUndef)) { if (! $reset && ! $this->isUndefined() && $session->hasNamespace($nsUndef)) {
// We do not have any window-id on the very first request. Now we add // 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, // all values from the namespace, that has been created in this case,
// to the new one and remove it afterwards. // to the new one and remove it afterwards.
foreach ($session->getNamespace($nsUndef) as $name => $value) { foreach ($session->getNamespace($nsUndef) as $name => $value) {
$namespace->set($name, $value); $namespace->set($name, $value);
} }
$session->removeNamespace($nsUndef); $session->removeNamespace($nsUndef);
} }
return $namespace; return $namespace;
} }
/**
* Generate a random string
*
* @return string
*/
public static function generateId() public static function generateId()
{ {
$letters = 'abcefghijklmnopqrstuvwxyz'; $letters = 'abcefghijklmnopqrstuvwxyz';
return substr(str_shuffle($letters), 0, 12); 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) {
Icinga::app()->getResponse()->setOverrideWindowId();
$id = static::generateId();
}
static::$window = new Window($id);
}
return static::$window;
}
} }