mirror of
https://github.com/nextcloud/server.git
synced 2026-03-30 22:26:41 -04:00
fix: propfind query monitor breaking removeListener and removeAllListeners
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com>
This commit is contained in:
parent
d5417d63e0
commit
5d028cfaf8
2 changed files with 118 additions and 6 deletions
|
|
@ -34,6 +34,16 @@ class Server extends \Sabre\DAV\Server {
|
|||
|
||||
public bool $debugEnabled = false;
|
||||
|
||||
/**
|
||||
* @var array<string, array<int, callable>>
|
||||
*/
|
||||
private array $originalListeners = [];
|
||||
|
||||
/**
|
||||
* @var array<string, array<int, callable>>
|
||||
*/
|
||||
private array $wrappedListeners = [];
|
||||
|
||||
/**
|
||||
* @see \Sabre\DAV\Server
|
||||
*/
|
||||
|
|
@ -86,15 +96,49 @@ class Server extends \Sabre\DAV\Server {
|
|||
$parentFn($eventName, $callBack, $priority);
|
||||
return;
|
||||
}
|
||||
// The \Sabre\DAVACL\Plugin needs to excluded as it relies on removeListener()
|
||||
if ($pluginName === \Sabre\DAVACL\Plugin::class) {
|
||||
$parentFn($eventName, $callBack, $priority);
|
||||
return;
|
||||
|
||||
$wrappedCallback
|
||||
= $this->getMonitoredCallback($callBack, $pluginName, $eventName);
|
||||
$this->originalListeners[$eventName][] = $callBack;
|
||||
$this->wrappedListeners[$eventName][] = $wrappedCallback;
|
||||
|
||||
$parentFn($eventName, $wrappedCallback, $priority);
|
||||
}
|
||||
|
||||
public function removeListener(
|
||||
string $eventName,
|
||||
callable $listener,
|
||||
): bool {
|
||||
$listenerIndex = null;
|
||||
if (isset($this->wrappedListeners[$eventName], $this->originalListeners[$eventName])) {
|
||||
$key = array_search(
|
||||
$listener,
|
||||
$this->originalListeners[$eventName],
|
||||
true
|
||||
);
|
||||
if ($key !== false) {
|
||||
$listenerIndex = $key;
|
||||
$listener = $this->wrappedListeners[$eventName][$listenerIndex];
|
||||
}
|
||||
}
|
||||
$removed = parent::removeListener($eventName, $listener);
|
||||
|
||||
if ($removed && $listenerIndex !== null) {
|
||||
unset($this->originalListeners[$eventName][$listenerIndex], $this->wrappedListeners[$eventName][$listenerIndex]);
|
||||
}
|
||||
|
||||
$callback = $this->getMonitoredCallback($callBack, $pluginName, $eventName);
|
||||
return $removed;
|
||||
}
|
||||
|
||||
$parentFn($eventName, $callback, $priority);
|
||||
public function removeAllListeners(?string $eventName = null): void {
|
||||
parent::removeAllListeners($eventName);
|
||||
|
||||
if ($eventName === null) {
|
||||
$this->originalListeners = [];
|
||||
$this->wrappedListeners = [];
|
||||
} else {
|
||||
unset($this->wrappedListeners[$eventName], $this->originalListeners[$eventName]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
68
apps/dav/tests/unit/Connector/ServerTest.php
Normal file
68
apps/dav/tests/unit/Connector/ServerTest.php
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCA\DAV\Tests\unit\Connector\Sabre;
|
||||
|
||||
use OCA\DAV\Connector\Sabre\Server;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Sabre\DAV\INode;
|
||||
use Sabre\DAV\PropFind;
|
||||
use Test\TestCase;
|
||||
|
||||
class ServerTest extends TestCase {
|
||||
|
||||
private Server $server;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->server = new Server();
|
||||
$this->server->debugEnabled = true;
|
||||
}
|
||||
|
||||
public function testRemoveListener(): void {
|
||||
$listener = static function () {
|
||||
return false;
|
||||
};
|
||||
$this->server->on('propFind', $listener);
|
||||
$this->server->removeListener('propFind', $listener);
|
||||
|
||||
$propFind = $this->createMock(PropFind::class);
|
||||
$iNode = $this->createMock(INode::class);
|
||||
|
||||
$return = $this->server->emit('propFind', [$propFind, $iNode]);
|
||||
$this->assertTrue($return);
|
||||
}
|
||||
|
||||
public static function removeAllListenersData(): array {
|
||||
return [
|
||||
'all listeners' => [null], 'propFind listeners' => ['propFind'],
|
||||
];
|
||||
}
|
||||
|
||||
#[DataProvider('removeAllListenersData')]
|
||||
public function testRemoveAllListeners(?string $removeEventName): void {
|
||||
$listener = static function () {
|
||||
return false;
|
||||
};
|
||||
$this->server->on('propFind', $listener);
|
||||
$this->server->on('otherEvent', $listener);
|
||||
|
||||
$this->server->removeAllListeners($removeEventName);
|
||||
|
||||
$propFind = $this->createMock(PropFind::class);
|
||||
$iNode = $this->createMock(INode::class);
|
||||
|
||||
$propFindReturn = $this->server->emit('propFind', [$propFind, $iNode]);
|
||||
$this->assertTrue($propFindReturn);
|
||||
$otherEventReturn = $this->server->emit('otherEvent', [$propFind,
|
||||
$iNode]);
|
||||
// if listeners are not removed when they should, emit will return false
|
||||
$this->assertEquals($removeEventName === null, $otherEventReturn);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue