Check the quota on the actual file's storage in dav quota plugin
Fix quota plugin to use the correct file name when chunking When chunking, the file name is the compound name, so need to convert it to the correct final file name before doing the free space check. This ensures that in the case of shared files, the correct storage is used for the quota check.
This commit is contained in:
parent
7b0f83b616
commit
53eff9792f
|
@ -95,12 +95,14 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
||||||
$req = $this->server->httpRequest;
|
$req = $this->server->httpRequest;
|
||||||
if ($req->getHeader('OC-Chunked')) {
|
if ($req->getHeader('OC-Chunked')) {
|
||||||
$info = \OC_FileChunking::decodeName($newName);
|
$info = \OC_FileChunking::decodeName($newName);
|
||||||
$chunkHandler = new \OC_FileChunking($info);
|
$chunkHandler = $this->getFileChunking($info);
|
||||||
// subtract the already uploaded size to see whether
|
// subtract the already uploaded size to see whether
|
||||||
// there is still enough space for the remaining chunks
|
// there is still enough space for the remaining chunks
|
||||||
$length -= $chunkHandler->getCurrentSize();
|
$length -= $chunkHandler->getCurrentSize();
|
||||||
|
// use target file name for free space check in case of shared files
|
||||||
|
$uri = rtrim($parentUri, '/') . '/' . $info['name'];
|
||||||
}
|
}
|
||||||
$freeSpace = $this->getFreeSpace($parentUri);
|
$freeSpace = $this->getFreeSpace($uri);
|
||||||
if ($freeSpace !== \OCP\Files\FileInfo::SPACE_UNKNOWN && $length > $freeSpace) {
|
if ($freeSpace !== \OCP\Files\FileInfo::SPACE_UNKNOWN && $length > $freeSpace) {
|
||||||
if (isset($chunkHandler)) {
|
if (isset($chunkHandler)) {
|
||||||
$chunkHandler->cleanup();
|
$chunkHandler->cleanup();
|
||||||
|
@ -111,6 +113,11 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFileChunking($info) {
|
||||||
|
// FIXME: need a factory for better mocking support
|
||||||
|
return new \OC_FileChunking($info);
|
||||||
|
}
|
||||||
|
|
||||||
public function getLength() {
|
public function getLength() {
|
||||||
$req = $this->server->httpRequest;
|
$req = $this->server->httpRequest;
|
||||||
$length = $req->getHeader('X-Expected-Entity-Length');
|
$length = $req->getHeader('X-Expected-Entity-Length');
|
||||||
|
@ -127,12 +134,12 @@ class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $parentUri
|
* @param string $uri
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getFreeSpace($parentUri) {
|
public function getFreeSpace($uri) {
|
||||||
try {
|
try {
|
||||||
$freeSpace = $this->view->free_space($parentUri);
|
$freeSpace = $this->view->free_space(ltrim($uri, '/'));
|
||||||
return $freeSpace;
|
return $freeSpace;
|
||||||
} catch (\OCP\Files\StorageNotAvailableException $e) {
|
} catch (\OCP\Files\StorageNotAvailableException $e) {
|
||||||
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
|
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
|
||||||
|
|
|
@ -39,10 +39,13 @@ class QuotaPlugin extends \Test\TestCase {
|
||||||
*/
|
*/
|
||||||
private $plugin;
|
private $plugin;
|
||||||
|
|
||||||
private function init($quota) {
|
private function init($quota, $checkedPath = '') {
|
||||||
$view = $this->buildFileViewMock($quota);
|
$view = $this->buildFileViewMock($quota, $checkedPath);
|
||||||
$this->server = new \Sabre\DAV\Server();
|
$this->server = new \Sabre\DAV\Server();
|
||||||
$this->plugin = new \OCA\DAV\Connector\Sabre\QuotaPlugin($view);
|
$this->plugin = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\QuotaPlugin')
|
||||||
|
->setConstructorArgs([$view])
|
||||||
|
->setMethods(['getFileChunking'])
|
||||||
|
->getMock();
|
||||||
$this->plugin->initialize($this->server);
|
$this->plugin->initialize($this->server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +54,8 @@ class QuotaPlugin extends \Test\TestCase {
|
||||||
*/
|
*/
|
||||||
public function testLength($expected, $headers) {
|
public function testLength($expected, $headers) {
|
||||||
$this->init(0);
|
$this->init(0);
|
||||||
|
$this->plugin->expects($this->never())
|
||||||
|
->method('getFileChunking');
|
||||||
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
||||||
$length = $this->plugin->getLength();
|
$length = $this->plugin->getLength();
|
||||||
$this->assertEquals($expected, $length);
|
$this->assertEquals($expected, $length);
|
||||||
|
@ -61,6 +66,8 @@ class QuotaPlugin extends \Test\TestCase {
|
||||||
*/
|
*/
|
||||||
public function testCheckQuota($quota, $headers) {
|
public function testCheckQuota($quota, $headers) {
|
||||||
$this->init($quota);
|
$this->init($quota);
|
||||||
|
$this->plugin->expects($this->never())
|
||||||
|
->method('getFileChunking');
|
||||||
|
|
||||||
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
||||||
$result = $this->plugin->checkQuota('');
|
$result = $this->plugin->checkQuota('');
|
||||||
|
@ -73,11 +80,26 @@ class QuotaPlugin extends \Test\TestCase {
|
||||||
*/
|
*/
|
||||||
public function testCheckExceededQuota($quota, $headers) {
|
public function testCheckExceededQuota($quota, $headers) {
|
||||||
$this->init($quota);
|
$this->init($quota);
|
||||||
|
$this->plugin->expects($this->never())
|
||||||
|
->method('getFileChunking');
|
||||||
|
|
||||||
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
||||||
$this->plugin->checkQuota('');
|
$this->plugin->checkQuota('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider quotaOkayProvider
|
||||||
|
*/
|
||||||
|
public function testCheckQuotaOnPath($quota, $headers) {
|
||||||
|
$this->init($quota, 'sub/test.txt');
|
||||||
|
$this->plugin->expects($this->never())
|
||||||
|
->method('getFileChunking');
|
||||||
|
|
||||||
|
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
||||||
|
$result = $this->plugin->checkQuota('/sub/test.txt');
|
||||||
|
$this->assertTrue($result);
|
||||||
|
}
|
||||||
|
|
||||||
public function quotaOkayProvider() {
|
public function quotaOkayProvider() {
|
||||||
return array(
|
return array(
|
||||||
array(1024, array()),
|
array(1024, array()),
|
||||||
|
@ -110,12 +132,89 @@ class QuotaPlugin extends \Test\TestCase {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildFileViewMock($quota) {
|
public function quotaChunkedOkProvider() {
|
||||||
|
return array(
|
||||||
|
array(1024, 0, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
|
||||||
|
array(1024, 0, array('CONTENT-LENGTH' => '512')),
|
||||||
|
array(1024, 0, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
|
||||||
|
// with existing chunks (allowed size = total length - chunk total size)
|
||||||
|
array(400, 128, array('X-EXPECTED-ENTITY-LENGTH' => '512')),
|
||||||
|
array(400, 128, array('CONTENT-LENGTH' => '512')),
|
||||||
|
array(400, 128, array('OC-TOTAL-LENGTH' => '512', 'CONTENT-LENGTH' => '500')),
|
||||||
|
// \OCP\Files\FileInfo::SPACE-UNKNOWN = -2
|
||||||
|
array(-2, 0, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
|
||||||
|
array(-2, 0, array('CONTENT-LENGTH' => '512')),
|
||||||
|
array(-2, 0, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
|
||||||
|
array(-2, 128, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
|
||||||
|
array(-2, 128, array('CONTENT-LENGTH' => '512')),
|
||||||
|
array(-2, 128, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider quotaChunkedOkProvider
|
||||||
|
*/
|
||||||
|
public function testCheckQuotaChunkedOk($quota, $chunkTotalSize, $headers) {
|
||||||
|
$this->init($quota, 'sub/test.txt');
|
||||||
|
|
||||||
|
$mockChunking = $this->getMockBuilder('\OC_FileChunking')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$mockChunking->expects($this->once())
|
||||||
|
->method('getCurrentSize')
|
||||||
|
->will($this->returnValue($chunkTotalSize));
|
||||||
|
|
||||||
|
$this->plugin->expects($this->once())
|
||||||
|
->method('getFileChunking')
|
||||||
|
->will($this->returnValue($mockChunking));
|
||||||
|
|
||||||
|
$headers['OC-CHUNKED'] = 1;
|
||||||
|
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
||||||
|
$result = $this->plugin->checkQuota('/sub/test.txt-chunking-12345-3-1');
|
||||||
|
$this->assertTrue($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function quotaChunkedFailProvider() {
|
||||||
|
return array(
|
||||||
|
array(400, 0, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
|
||||||
|
array(400, 0, array('CONTENT-LENGTH' => '512')),
|
||||||
|
array(400, 0, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
|
||||||
|
// with existing chunks (allowed size = total length - chunk total size)
|
||||||
|
array(380, 128, array('X-EXPECTED-ENTITY-LENGTH' => '512')),
|
||||||
|
array(380, 128, array('CONTENT-LENGTH' => '512')),
|
||||||
|
array(380, 128, array('OC-TOTAL-LENGTH' => '512', 'CONTENT-LENGTH' => '500')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider quotaChunkedFailProvider
|
||||||
|
* @expectedException \Sabre\DAV\Exception\InsufficientStorage
|
||||||
|
*/
|
||||||
|
public function testCheckQuotaChunkedFail($quota, $chunkTotalSize, $headers) {
|
||||||
|
$this->init($quota, 'sub/test.txt');
|
||||||
|
|
||||||
|
$mockChunking = $this->getMockBuilder('\OC_FileChunking')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$mockChunking->expects($this->once())
|
||||||
|
->method('getCurrentSize')
|
||||||
|
->will($this->returnValue($chunkTotalSize));
|
||||||
|
|
||||||
|
$this->plugin->expects($this->once())
|
||||||
|
->method('getFileChunking')
|
||||||
|
->will($this->returnValue($mockChunking));
|
||||||
|
|
||||||
|
$headers['OC-CHUNKED'] = 1;
|
||||||
|
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
||||||
|
$this->plugin->checkQuota('/sub/test.txt-chunking-12345-3-1');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildFileViewMock($quota, $checkedPath) {
|
||||||
// mock filesysten
|
// mock filesysten
|
||||||
$view = $this->getMock('\OC\Files\View', array('free_space'), array(), '', false);
|
$view = $this->getMock('\OC\Files\View', array('free_space'), array(), '', false);
|
||||||
$view->expects($this->any())
|
$view->expects($this->any())
|
||||||
->method('free_space')
|
->method('free_space')
|
||||||
->with($this->identicalTo(''))
|
->with($this->identicalTo($checkedPath))
|
||||||
->will($this->returnValue($quota));
|
->will($this->returnValue($quota));
|
||||||
|
|
||||||
return $view;
|
return $view;
|
||||||
|
|
Loading…
Reference in New Issue