From 8c7017679d9a644a7103788e5b55780febe12aaf Mon Sep 17 00:00:00 2001 From: Benjamin Gaussorgues Date: Wed, 6 Sep 2023 09:16:55 +0200 Subject: [PATCH] Detect aborted connection in OC\Files\View and stop writing data to the output buffer Signed-off-by: Benjamin Gaussorgues --- lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + lib/private/Files/View.php | 14 +++++++-- lib/private/legacy/OC_Files.php | 4 +++ lib/public/Files/ConnectionLostException.php | 33 ++++++++++++++++++++ 5 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 lib/public/Files/ConnectionLostException.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 5b543ad55b9..229d7054fe4 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -291,6 +291,7 @@ return array( 'OCP\\Files\\Config\\IMountProviderCollection' => $baseDir . '/lib/public/Files/Config/IMountProviderCollection.php', 'OCP\\Files\\Config\\IRootMountProvider' => $baseDir . '/lib/public/Files/Config/IRootMountProvider.php', 'OCP\\Files\\Config\\IUserMountCache' => $baseDir . '/lib/public/Files/Config/IUserMountCache.php', + 'OCP\\Files\\ConnectionLostException' => $baseDir . '/lib/public/Files/ConnectionLostException.php', 'OCP\\Files\\DavUtil' => $baseDir . '/lib/public/Files/DavUtil.php', 'OCP\\Files\\EmptyFileNameException' => $baseDir . '/lib/public/Files/EmptyFileNameException.php', 'OCP\\Files\\EntityTooLargeException' => $baseDir . '/lib/public/Files/EntityTooLargeException.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 19e2f3393d6..e790fd19584 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -324,6 +324,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Files\\Config\\IMountProviderCollection' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IMountProviderCollection.php', 'OCP\\Files\\Config\\IRootMountProvider' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IRootMountProvider.php', 'OCP\\Files\\Config\\IUserMountCache' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IUserMountCache.php', + 'OCP\\Files\\ConnectionLostException' => __DIR__ . '/../../..' . '/lib/public/Files/ConnectionLostException.php', 'OCP\\Files\\DavUtil' => __DIR__ . '/../../..' . '/lib/public/Files/DavUtil.php', 'OCP\\Files\\EmptyFileNameException' => __DIR__ . '/../../..' . '/lib/public/Files/EmptyFileNameException.php', 'OCP\\Files\\EntityTooLargeException' => __DIR__ . '/../../..' . '/lib/public/Files/EntityTooLargeException.php', diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index 05b4b2e21b8..e5476c77b2a 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -56,6 +56,7 @@ use OC\User\Manager as UserManager; use OCA\Files_Sharing\SharedMount; use OCP\Constants; use OCP\Files\Cache\ICacheEntry; +use OCP\Files\ConnectionLostException; use OCP\Files\EmptyFileNameException; use OCP\Files\FileNameTooLongException; use OCP\Files\InvalidCharacterInPathException; @@ -397,10 +398,11 @@ class View { } $handle = $this->fopen($path, 'rb'); if ($handle) { - $chunkSize = 524288; // 512 kB chunks + $chunkSize = 524288; // 512 kiB chunks while (!feof($handle)) { echo fread($handle, $chunkSize); flush(); + $this->checkConnectionStatus(); } fclose($handle); return $this->filesize($path); @@ -423,7 +425,7 @@ class View { } $handle = $this->fopen($path, 'rb'); if ($handle) { - $chunkSize = 524288; // 512 kB chunks + $chunkSize = 524288; // 512 kiB chunks $startReading = true; if ($from !== 0 && $from !== '0' && fseek($handle, $from) !== 0) { @@ -453,6 +455,7 @@ class View { } echo fread($handle, $len); flush(); + $this->checkConnectionStatus(); } return ftell($handle) - $from; } @@ -462,6 +465,13 @@ class View { return false; } + private function checkConnectionStatus(): void { + $connectionStatus = \connection_status(); + if ($connectionStatus !== CONNECTION_NORMAL) { + throw new ConnectionLostException("Connection lost. Status: $connectionStatus"); + } + } + /** * @param string $path * @return mixed diff --git a/lib/private/legacy/OC_Files.php b/lib/private/legacy/OC_Files.php index 5655139b24a..d38f45545db 100644 --- a/lib/private/legacy/OC_Files.php +++ b/lib/private/legacy/OC_Files.php @@ -230,6 +230,10 @@ class OC_Files { OC::$server->getLogger()->logException($ex); $l = \OC::$server->getL10N('lib'); \OC_Template::printErrorPage($l->t('Cannot download file'), $ex->getMessage(), 200); + } catch (\OCP\Files\ConnectionLostException $ex) { + self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); + OC::$server->getLogger()->logException($ex, ['level' => \OCP\ILogger::DEBUG]); + \OC_Template::printErrorPage('Connection lost', $ex->getMessage(), 200); } catch (\Exception $ex) { self::unlockAllTheFiles($dir, $files, $getType, $view, $filename); OC::$server->getLogger()->logException($ex); diff --git a/lib/public/Files/ConnectionLostException.php b/lib/public/Files/ConnectionLostException.php new file mode 100644 index 00000000000..8e5deb99b46 --- /dev/null +++ b/lib/public/Files/ConnectionLostException.php @@ -0,0 +1,33 @@ + + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCP\Files; + +/** + * Exception for lost connection with the + * @since 25.0.11 + */ +class ConnectionLostException extends \RuntimeException { +} -- 2.39.5