diff options
author | Vincent Petry <pvince81@owncloud.com> | 2014-07-02 18:15:58 +0200 |
---|---|---|
committer | Vincent Petry <pvince81@owncloud.com> | 2014-07-02 18:15:58 +0200 |
commit | f4eb90e22965752616051cad0899dc55b4b69506 (patch) | |
tree | 3f7f2b53dad157185d9ad110604ea7056601881f | |
parent | ea756a12b0dfdffe7b1bf9a69fb658ebf69db89a (diff) | |
parent | edb67f9f4dc8d3c028ba6f2d157d2174fb40aba8 (diff) | |
download | nextcloud-server-f4eb90e22965752616051cad0899dc55b4b69506.tar.gz nextcloud-server-f4eb90e22965752616051cad0899dc55b4b69506.zip |
Merge pull request #9311 from owncloud/storage-not-available
Handle storages not being available in webui and webdav
-rw-r--r-- | apps/files/ajax/list.php | 69 | ||||
-rw-r--r-- | apps/files/js/filelist.js | 23 | ||||
-rw-r--r-- | apps/files_sharing/js/external.js | 2 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/manager.php | 2 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/scanner.php | 18 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/storage.php | 85 | ||||
-rw-r--r-- | apps/files_sharing/tests/externalstorage.php | 1 | ||||
-rw-r--r-- | lib/private/connector/sabre/objecttree.php | 10 | ||||
-rw-r--r-- | lib/private/files/mount/manager.php | 4 | ||||
-rw-r--r-- | lib/private/files/storage/dav.php | 44 | ||||
-rw-r--r-- | lib/public/files/storageinvalidexception.php | 22 | ||||
-rw-r--r-- | lib/public/files/storagenotavailableexception.php | 22 |
12 files changed, 232 insertions, 70 deletions
diff --git a/apps/files/ajax/list.php b/apps/files/ajax/list.php index bae3628402f..b4641343ed4 100644 --- a/apps/files/ajax/list.php +++ b/apps/files/ajax/list.php @@ -2,29 +2,54 @@ OCP\JSON::checkLoggedIn(); \OC::$session->close(); +$l = OC_L10N::get('files'); // Load the files -$dir = isset( $_GET['dir'] ) ? $_GET['dir'] : ''; +$dir = isset($_GET['dir']) ? $_GET['dir'] : ''; $dir = \OC\Files\Filesystem::normalizePath($dir); -$dirInfo = \OC\Files\Filesystem::getFileInfo($dir); -if (!$dirInfo || !$dirInfo->getType() === 'dir') { - header("HTTP/1.0 404 Not Found"); - exit(); -} - -$data = array(); -$baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir='; - -$permissions = $dirInfo->getPermissions(); - -$sortAttribute = isset( $_GET['sort'] ) ? $_GET['sort'] : 'name'; -$sortDirection = isset( $_GET['sortdirection'] ) ? ($_GET['sortdirection'] === 'desc') : false; -// make filelist -$files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection); - -$data['directory'] = $dir; -$data['files'] = \OCA\Files\Helper::formatFileInfos($files); -$data['permissions'] = $permissions; - -OCP\JSON::success(array('data' => $data)); +try { + $dirInfo = \OC\Files\Filesystem::getFileInfo($dir); + if (!$dirInfo || !$dirInfo->getType() === 'dir') { + header("HTTP/1.0 404 Not Found"); + exit(); + } + + $data = array(); + $baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir='; + + $permissions = $dirInfo->getPermissions(); + + $sortAttribute = isset($_GET['sort']) ? $_GET['sort'] : 'name'; + $sortDirection = isset($_GET['sortdirection']) ? ($_GET['sortdirection'] === 'desc') : false; + + // make filelist + + $files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection); + $data['directory'] = $dir; + $data['files'] = \OCA\Files\Helper::formatFileInfos($files); + $data['permissions'] = $permissions; + + OCP\JSON::success(array('data' => $data)); +} catch (\OCP\Files\StorageNotAvailableException $e) { + OCP\JSON::error(array( + 'data' => array( + 'exception' => '\OCP\Files\StorageNotAvailableException', + 'message' => $l->t('Storage not available') + ) + )); +} catch (\OCP\Files\StorageInvalidException $e) { + OCP\JSON::error(array( + 'data' => array( + 'exception' => '\OCP\Files\StorageInvalidException', + 'message' => $l->t('Storage invalid') + ) + )); +} catch (\Exception $e) { + OCP\JSON::error(array( + 'data' => array( + 'exception' => '\Exception', + 'message' => $l->t('Unknown error') + ) + )); +} diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index c7fccc5dd66..94f161943a1 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -846,13 +846,18 @@ * @param {boolean} force set to true to force changing directory */ changeDirectory: function(targetDir, changeUrl, force) { + var self = this; var currentDir = this.getCurrentDirectory(); targetDir = targetDir || '/'; if (!force && currentDir === targetDir) { return; } this._setCurrentDir(targetDir, changeUrl); - this.reload(); + this.reload().then(function(success){ + if (!success) { + self.changeDirectory(currentDir, true); + } + }); }, linkTo: function(dir) { return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); @@ -912,7 +917,6 @@ * @brief Reloads the file list using ajax call */ reload: function() { - var self = this; this._selectedFiles = {}; this._selectionSummary.clear(); this.$el.find('.select-all').prop('checked', false); @@ -926,14 +930,10 @@ dir : this.getCurrentDirectory(), sort: this._sort, sortdirection: this._sortDirection - }, - error: function(result) { - self.reloadCallback(result); - }, - success: function(result) { - self.reloadCallback(result); } }); + var callBack = this.reloadCallback.bind(this); + return this._reloadCall.then(callBack, callBack); }, reloadCallback: function(result) { delete this._reloadCall; @@ -941,17 +941,17 @@ if (!result || result.status === 'error') { OC.Notification.show(result.data.message); - return; + return false; } if (result.status === 404) { // go back home this.changeDirectory('/'); - return; + return false; } // aborted ? if (result.status === 0){ - return; + return true; } // TODO: should rather return upload file size through @@ -963,6 +963,7 @@ } this.setFiles(result.data.files); + return true }, updateStorageStatistics: function(force) { diff --git a/apps/files_sharing/js/external.js b/apps/files_sharing/js/external.js index 1eb447da896..969a2b184d4 100644 --- a/apps/files_sharing/js/external.js +++ b/apps/files_sharing/js/external.js @@ -58,7 +58,7 @@ $(document).ready(function () { if (params.remote && params.token && params.owner && params.name) { // clear hash, it is unlikely that it contain any extra parameters location.hash = ''; - params.passwordProtected = parseInt(params.passwordProtected, 10) === 1; + params.passwordProtected = parseInt(params.protected, 10) === 1; OCA.Sharing.showAddExternalDialog( params.remote, params.token, diff --git a/apps/files_sharing/lib/external/manager.php b/apps/files_sharing/lib/external/manager.php index af317cc2027..dda283f4952 100644 --- a/apps/files_sharing/lib/external/manager.php +++ b/apps/files_sharing/lib/external/manager.php @@ -113,7 +113,9 @@ class Manager { * @return Mount */ protected function mountShare($data) { + $data['manager'] = $this; $mountPoint = '/' . $this->userSession->getUser()->getUID() . '/files' . $data['mountpoint']; + $data['mountpoint'] = $mountPoint; $mount = new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader); $this->mountManager->addMount($mount); return $mount; diff --git a/apps/files_sharing/lib/external/scanner.php b/apps/files_sharing/lib/external/scanner.php index 8921dd1a4c0..4dc5d4be9d8 100644 --- a/apps/files_sharing/lib/external/scanner.php +++ b/apps/files_sharing/lib/external/scanner.php @@ -19,23 +19,7 @@ class Scanner extends \OC\Files\Cache\Scanner { } public function scanAll() { - $remote = $this->storage->getRemote(); - $token = $this->storage->getToken(); - $password = $this->storage->getPassword(); - $url = $remote . '/index.php/apps/files_sharing/shareinfo?t=' . $token; - - $ch = curl_init(); - - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, - http_build_query(array('password' => $password))); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - $result = curl_exec($ch); - curl_close($ch); - - $data = json_decode($result, true); + $data = $this->storage->getShareInfo(); if ($data['status'] === 'success') { $this->addResult($data['data'], ''); } else { diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php index 454196f15ae..3a0de51192e 100644 --- a/apps/files_sharing/lib/external/storage.php +++ b/apps/files_sharing/lib/external/storage.php @@ -10,7 +10,11 @@ namespace OCA\Files_Sharing\External; use OC\Files\Filesystem; use OC\Files\Storage\DAV; +use OC\ForbiddenException; use OCA\Files_Sharing\ISharedStorage; +use OCP\Files\NotFoundException; +use OCP\Files\StorageInvalidException; +use OCP\Files\StorageNotAvailableException; class Storage extends DAV implements ISharedStorage { /** @@ -35,7 +39,13 @@ class Storage extends DAV implements ISharedStorage { private $updateChecked = false; + /** + * @var \OCA\Files_Sharing\External\Manager + */ + private $manager; + public function __construct($options) { + $this->manager = $options['manager']; $this->remote = $options['remote']; $this->remoteUser = $options['owner']; list($protocol, $remote) = explode('://', $this->remote); @@ -108,6 +118,8 @@ class Storage extends DAV implements ISharedStorage { * * @param string $path * @param int $time + * @throws \OCP\Files\StorageNotAvailableException + * @throws \OCP\Files\StorageInvalidException * @return bool */ public function hasUpdated($path, $time) { @@ -117,6 +129,77 @@ class Storage extends DAV implements ISharedStorage { return false; } $this->updateChecked = true; - return parent::hasUpdated('', $time); + try { + return parent::hasUpdated('', $time); + } catch (StorageNotAvailableException $e) { + // see if we can find out why the share is unavailable\ + try { + $this->getShareInfo(); + } catch (NotFoundException $shareException) { + // a 404 can either mean that the share no longer exists or there is no ownCloud on the remote + if ($this->testRemote()) { + // valid ownCloud instance means that the public share no longer exists + // since this is permanent (re-sharing the file will create a new token) + // we remove the invalid storage + $this->manager->removeShare($this->mountPoint); + $this->manager->getMountManager()->removeMount($this->mountPoint); + throw new StorageInvalidException(); + } else { + // ownCloud instance is gone, likely to be a temporary server configuration error + throw $e; + } + } catch(\Exception $shareException) { + // todo, maybe handle 403 better and ask the user for a new password + throw $e; + } + throw $e; + } + } + + /** + * check if the configured remote is a valid ownCloud instance + * + * @return bool + */ + protected function testRemote() { + try { + $result = file_get_contents($this->remote . '/status.php'); + $data = json_decode($result); + return is_object($data) and !empty($data->version); + } catch (\Exception $e) { + return false; + } + } + + public function getShareInfo() { + $remote = $this->getRemote(); + $token = $this->getToken(); + $password = $this->getPassword(); + $url = $remote . '/index.php/apps/files_sharing/shareinfo?t=' . $token; + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, + http_build_query(array('password' => $password))); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $result = curl_exec($ch); + + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + switch ($status) { + case 401: + case 403: + throw new ForbiddenException(); + case 404: + throw new NotFoundException(); + case 500: + throw new \Exception(); + } + + return json_decode($result, true); } } diff --git a/apps/files_sharing/tests/externalstorage.php b/apps/files_sharing/tests/externalstorage.php index 60c5787f295..1258148af53 100644 --- a/apps/files_sharing/tests/externalstorage.php +++ b/apps/files_sharing/tests/externalstorage.php @@ -72,6 +72,7 @@ class Test_Files_Sharing_External_Storage extends \PHPUnit_Framework_TestCase { 'mountpoint' => 'remoteshare', 'token' => 'abcdef', 'password' => '', + 'manager' => null ) ); $this->assertEquals($baseUri, $storage->getBaseUri()); diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php index 54596db3c47..d7a96cfc88e 100644 --- a/lib/private/connector/sabre/objecttree.php +++ b/lib/private/connector/sabre/objecttree.php @@ -11,6 +11,8 @@ namespace OC\Connector\Sabre; use OC\Files\FileInfo; use OC\Files\Filesystem; use OC\Files\Mount\MoveableMount; +use OCP\Files\StorageInvalidException; +use OCP\Files\StorageNotAvailableException; class ObjectTree extends \Sabre\DAV\ObjectTree { @@ -83,7 +85,13 @@ class ObjectTree extends \Sabre\DAV\ObjectTree { } } else { // read from cache - $info = $this->fileView->getFileInfo($path); + try { + $info = $this->fileView->getFileInfo($path); + } catch (StorageNotAvailableException $e) { + throw new \Sabre\DAV\Exception\ServiceUnavailable('Storage not available'); + } catch (StorageInvalidException $e){ + throw new \Sabre\DAV\Exception\NotFound('Storage ' . $path . ' is invalid'); + } } if (!$info) { diff --git a/lib/private/files/mount/manager.php b/lib/private/files/mount/manager.php index 45a9f339fba..e5180cfe173 100644 --- a/lib/private/files/mount/manager.php +++ b/lib/private/files/mount/manager.php @@ -27,6 +27,10 @@ class Manager { * @param string $mountPoint */ public function removeMount($mountPoint) { + $mountPoint = Filesystem::normalizePath($mountPoint); + if (strlen($mountPoint) > 1) { + $mountPoint .= '/'; + } unset($this->mounts[$mountPoint]); } diff --git a/lib/private/files/storage/dav.php b/lib/private/files/storage/dav.php index 8b97f750204..726688fe444 100644 --- a/lib/private/files/storage/dav.php +++ b/lib/private/files/storage/dav.php @@ -8,6 +8,9 @@ namespace OC\Files\Storage; +use OCP\Files\StorageNotAvailableException; +use Sabre\DAV\Exception; + class DAV extends \OC\Files\Storage\Common { protected $password; protected $user; @@ -463,29 +466,36 @@ class DAV extends \OC\Files\Storage\Common { * * @param string $path * @param int $time + * @throws \OCP\Files\StorageNotAvailableException * @return bool */ public function hasUpdated($path, $time) { $this->init(); - $response = $this->client->propfind($this->encodePath($path), array( - '{DAV:}getlastmodified', - '{DAV:}getetag', - '{http://owncloud.org/ns}permissions' - )); - if (isset($response['{DAV:}getetag'])) { - $cachedData = $this->getCache()->get($path); - $etag = trim($response['{DAV:}getetag'], '"'); - if ($cachedData['etag'] !== $etag) { - return true; - } else if (isset($response['{http://owncloud.org/ns}permissions'])) { - $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']); - return $permissions !== $cachedData['permissions']; + try { + $response = $this->client->propfind($this->encodePath($path), array( + '{DAV:}getlastmodified', + '{DAV:}getetag', + '{http://owncloud.org/ns}permissions' + )); + if (isset($response['{DAV:}getetag'])) { + $cachedData = $this->getCache()->get($path); + $etag = trim($response['{DAV:}getetag'], '"'); + if ($cachedData['etag'] !== $etag) { + return true; + } else if (isset($response['{http://owncloud.org/ns}permissions'])) { + $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']); + return $permissions !== $cachedData['permissions']; + } else { + return false; + } } else { - return false; + $remoteMtime = strtotime($response['{DAV:}getlastmodified']); + return $remoteMtime > $time; } - } else { - $remoteMtime = strtotime($response['{DAV:}getlastmodified']); - return $remoteMtime > $time; + } catch (Exception\NotFound $e) { + return false; + } catch (Exception $e) { + throw new StorageNotAvailableException(); } } } diff --git a/lib/public/files/storageinvalidexception.php b/lib/public/files/storageinvalidexception.php new file mode 100644 index 00000000000..7419ccc1d11 --- /dev/null +++ b/lib/public/files/storageinvalidexception.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Public interface of ownCloud for apps to use. + * Files/AlreadyExistsException class + */ + +// use OCP namespace for all classes that are considered public. +// This means that they should be used by apps instead of the internal ownCloud classes +namespace OCP\Files; + +/** + * Storage has invalid configuration + */ +class StorageInvalidException extends \Exception { +} diff --git a/lib/public/files/storagenotavailableexception.php b/lib/public/files/storagenotavailableexception.php new file mode 100644 index 00000000000..b526cb4ea0f --- /dev/null +++ b/lib/public/files/storagenotavailableexception.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Public interface of ownCloud for apps to use. + * Files/AlreadyExistsException class + */ + +// use OCP namespace for all classes that are considered public. +// This means that they should be used by apps instead of the internal ownCloud classes +namespace OCP\Files; + +/** + * Storage is temporarily not available + */ +class StorageNotAvailableException extends \Exception { +} |