Skip to content

Commit 92488ea

Browse files
fixup! fix: calendar subscription memory exhaustion
Signed-off-by: SebastianKrupinski <[email protected]>
1 parent f723827 commit 92488ea

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

apps/dav/lib/CalDAV/WebcalCaching/RefreshWebcalService.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace OCA\DAV\CalDAV\WebcalCaching;
1010

1111
use OCA\DAV\CalDAV\CalDavBackend;
12+
use OCP\AppFramework\Utility\ITimeFactory;
1213
use OCA\DAV\CalDAV\Import\ImportService;
1314
use Psr\Log\LoggerInterface;
1415
use Sabre\DAV\PropPatch;
@@ -30,6 +31,7 @@ public function __construct(
3031
private CalDavBackend $calDavBackend,
3132
private LoggerInterface $logger,
3233
private Connection $connection,
34+
private ITimeFactory $time,
3335
private ImportService $importService,
3436
) {
3537
}
@@ -40,6 +42,17 @@ public function refreshSubscription(string $principalUri, string $uri) {
4042
return;
4143
}
4244

45+
// Check the refresh rate if there is any
46+
if (!empty($subscription[self::REFRESH_RATE])) {
47+
// add the refresh interval to the last modified timestamp
48+
$refreshInterval = new \DateInterval($subscription[self::REFRESH_RATE]);
49+
$updateTime = $this->time->getDateTime();
50+
$updateTime->setTimestamp($subscription['lastmodified'])->add($refreshInterval);
51+
if ($updateTime->getTimestamp() > $this->time->getTime()) {
52+
return;
53+
}
54+
}
55+
4356
$result = $this->connection->queryWebcalFeed($subscription);
4457
if (!$result) {
4558
return;
@@ -71,6 +84,10 @@ public function refreshSubscription(string $principalUri, string $uri) {
7184

7285
// Some calendar providers (e.g. Google, MS) use very long UIDs
7386
if (strlen($vBase->UID->getValue()) > 512) {
87+
$this->logger->warning('Skipping calendar object with overly long UID from subscription "{subscriptionId}"', [
88+
'subscriptionId' => $subscription['id'],
89+
'uid' => $vBase->UID->getValue(),
90+
]);
7491
continue;
7592
}
7693

apps/dav/tests/unit/CalDAV/WebcalCaching/RefreshWebcalServiceTest.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use OCA\DAV\CalDAV\Import\ImportService;
1212
use OCA\DAV\CalDAV\WebcalCaching\Connection;
1313
use OCA\DAV\CalDAV\WebcalCaching\RefreshWebcalService;
14+
use OCP\AppFramework\Utility\ITimeFactory;
1415
use PHPUnit\Framework\MockObject\MockObject;
1516
use Psr\Log\LoggerInterface;
1617
use Sabre\DAV\Exception\BadRequest;
@@ -24,6 +25,7 @@ class RefreshWebcalServiceTest extends TestCase {
2425
private Connection&MockObject $connection;
2526
private LoggerInterface&MockObject $logger;
2627
private ImportService&MockObject $importService;
28+
private ITimeFactory&MockObject $timeFactory;
2729

2830
protected function setUp(): void {
2931
parent::setUp();
@@ -32,6 +34,10 @@ protected function setUp(): void {
3234
$this->connection = $this->createMock(Connection::class);
3335
$this->logger = $this->createMock(LoggerInterface::class);
3436
$this->importService = $this->createMock(ImportService::class);
37+
$this->timeFactory = $this->createMock(ITimeFactory::class);
38+
// Default time factory behavior: current time is far in the future so refresh always happens
39+
$this->timeFactory->method('getTime')->willReturn(PHP_INT_MAX);
40+
$this->timeFactory->method('getDateTime')->willReturn(new \DateTime());
3541
}
3642

3743
/**
@@ -50,6 +56,7 @@ public function testRun(string $body, string $format, string $result): void {
5056
$this->caldavBackend,
5157
$this->logger,
5258
$this->connection,
59+
$this->timeFactory,
5360
$this->importService
5461
);
5562

@@ -118,6 +125,7 @@ public function testRunIdentical(string $uid, array $calendarObject, string $bod
118125
$this->caldavBackend,
119126
$this->logger,
120127
$this->connection,
128+
$this->timeFactory,
121129
$this->importService
122130
);
123131

@@ -179,6 +187,7 @@ public function testSubscriptionNotFound(): void {
179187
$this->caldavBackend,
180188
$this->logger,
181189
$this->connection,
190+
$this->timeFactory,
182191
$this->importService
183192
);
184193

@@ -198,6 +207,7 @@ public function testConnectionReturnsNull(): void {
198207
$this->caldavBackend,
199208
$this->logger,
200209
$this->connection,
210+
$this->timeFactory,
201211
$this->importService
202212
);
203213

@@ -234,6 +244,7 @@ public function testDeletedObjectsArePurged(): void {
234244
$this->caldavBackend,
235245
$this->logger,
236246
$this->connection,
247+
$this->timeFactory,
237248
$this->importService
238249
);
239250

@@ -295,6 +306,7 @@ public function testLongUidIsSkipped(): void {
295306
$this->caldavBackend,
296307
$this->logger,
297308
$this->connection,
309+
$this->timeFactory,
298310
$this->importService
299311
);
300312

@@ -313,8 +325,8 @@ public function testLongUidIsSkipped(): void {
313325
],
314326
]);
315327

316-
// Create a UID that is longer than 255 characters
317-
$longUid = str_repeat('a', 256);
328+
// Create a UID that is longer than 512 characters
329+
$longUid = str_repeat('a', 513);
318330
$body = "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Test//Test//EN\r\nBEGIN:VEVENT\r\nUID:$longUid\r\nDTSTAMP:20160218T133704Z\r\nDTSTART:20160218T133704Z\r\nSUMMARY:Event with long UID\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n";
319331
$stream = $this->createStreamFromString($body);
320332

@@ -346,7 +358,7 @@ public function testLongUidIsSkipped(): void {
346358
public function testRunCreateCalendarNoException(string $body, string $format, string $result): void {
347359
$refreshWebcalService = $this->getMockBuilder(RefreshWebcalService::class)
348360
->onlyMethods(['getSubscription'])
349-
->setConstructorArgs([$this->caldavBackend, $this->logger, $this->connection, $this->importService])
361+
->setConstructorArgs([$this->caldavBackend, $this->logger, $this->connection, $this->timeFactory, $this->importService])
350362
->getMock();
351363

352364
$refreshWebcalService
@@ -399,7 +411,7 @@ public function testRunCreateCalendarNoException(string $body, string $format, s
399411
public function testRunCreateCalendarBadRequest(string $body, string $format, string $result): void {
400412
$refreshWebcalService = $this->getMockBuilder(RefreshWebcalService::class)
401413
->onlyMethods(['getSubscription'])
402-
->setConstructorArgs([$this->caldavBackend, $this->logger, $this->connection, $this->importService])
414+
->setConstructorArgs([$this->caldavBackend, $this->logger, $this->connection, $this->timeFactory, $this->importService])
403415
->getMock();
404416

405417
$refreshWebcalService

0 commit comments

Comments
 (0)