From 0fb719dffe5c2240c97da6ecb37b4437b7ba0391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 16 Sep 2013 10:43:53 +0200 Subject: [PATCH 1/4] adding size() to the file cache --- lib/cache/file.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/cache/file.php b/lib/cache/file.php index 361138e4736..eed2637c981 100644 --- a/lib/cache/file.php +++ b/lib/cache/file.php @@ -40,6 +40,24 @@ class OC_Cache_File{ return $result; } + /** + * Returns the size of the stored/cached data + * + * @param $key + * @return int + */ + public function size($key) { + $result = 0; + $proxyStatus = \OC_FileProxy::$enabled; + \OC_FileProxy::$enabled = false; + if ($this->hasKey($key)) { + $storage = $this->getStorage(); + $result = $storage->filesize($key); + } + \OC_FileProxy::$enabled = $proxyStatus; + return $result; + } + public function set($key, $value, $ttl=0) { $storage = $this->getStorage(); $result = false; From 16ef5a8b357e623b1f1621c3e52957167e93e46b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 16 Sep 2013 10:47:29 +0200 Subject: [PATCH 2/4] returning the number of stored bytes in store() and adding cleanup() method --- lib/filechunking.php | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/filechunking.php b/lib/filechunking.php index e6d69273a44..c0e3acbf1aa 100644 --- a/lib/filechunking.php +++ b/lib/filechunking.php @@ -34,10 +34,19 @@ class OC_FileChunking { return $this->cache; } + /** + * Stores the given $data under the given $key - the number of stored bytes is returned + * + * @param $index + * @param $data + * @return int + */ public function store($index, $data) { $cache = $this->getCache(); $name = $this->getPrefix().$index; $cache->set($name, $data); + + return $cache->size($name); } public function isComplete() { @@ -58,12 +67,24 @@ class OC_FileChunking { $count = 0; for($i=0; $i < $this->info['chunkcount']; $i++) { $chunk = $cache->get($prefix.$i); - $cache->remove($prefix.$i); $count += fwrite($f, $chunk); } + + $this->cleanup(); return $count; } + /** + * Removes all chunks which belong to this transmission + */ + public function cleanup() { + $cache = $this->getCache(); + $prefix = $this->getPrefix(); + for($i=0; $i < $this->info['chunkcount']; $i++) { + $cache->remove($prefix.$i); + } + } + public function signature_split($orgfile, $input) { $info = unpack('n', fread($input, 2)); $blocksize = $info[1]; From 39599019e5c3e47c5d03a1b63b438cacdab5b37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 16 Sep 2013 10:48:21 +0200 Subject: [PATCH 3/4] adding detection of aborted uploads --- lib/connector/sabre/directory.php | 99 ++++++++++++++++++------------- 1 file changed, 58 insertions(+), 41 deletions(-) diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php index 3181a4b310f..8a092c2455a 100644 --- a/lib/connector/sabre/directory.php +++ b/lib/connector/sabre/directory.php @@ -55,53 +55,40 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa } if (isset($_SERVER['HTTP_OC_CHUNKED'])) { - $info = OC_FileChunking::decodeName($name); - if (empty($info)) { - throw new Sabre_DAV_Exception_NotImplemented(); - } - $chunk_handler = new OC_FileChunking($info); - $chunk_handler->store($info['index'], $data); - if ($chunk_handler->isComplete()) { - $newPath = $this->path . '/' . $info['name']; - $chunk_handler->file_assemble($newPath); - return OC_Connector_Sabre_Node::getETagPropertyForPath($newPath); - } - } else { - $newPath = $this->path . '/' . $name; + return $this->createFileChunked($name, $data); + } + $newPath = $this->path . '/' . $name; - // mark file as partial while uploading (ignored by the scanner) - $partpath = $newPath . '.part'; + // mark file as partial while uploading (ignored by the scanner) + $partpath = $newPath . '.part'; - \OC\Files\Filesystem::file_put_contents($partpath, $data); + \OC\Files\Filesystem::file_put_contents($partpath, $data); - //detect aborted upload - if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT' ) { - if (isset($_SERVER['CONTENT_LENGTH'])) { - $expected = $_SERVER['CONTENT_LENGTH']; - $actual = \OC\Files\Filesystem::filesize($partpath); - if ($actual != $expected) { - \OC\Files\Filesystem::unlink($partpath); - throw new Sabre_DAV_Exception_BadRequest( - 'expected filesize ' . $expected . ' got ' . $actual); - } + //detect aborted upload + if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT' ) { + if (isset($_SERVER['CONTENT_LENGTH'])) { + $expected = $_SERVER['CONTENT_LENGTH']; + $actual = \OC\Files\Filesystem::filesize($partpath); + if ($actual != $expected) { + \OC\Files\Filesystem::unlink($partpath); + throw new Sabre_DAV_Exception_BadRequest( + 'expected filesize ' . $expected . ' got ' . $actual); } } - - // rename to correct path - \OC\Files\Filesystem::rename($partpath, $newPath); - - // allow sync clients to send the mtime along in a header - $mtime = OC_Request::hasModificationTime(); - if ($mtime !== false) { - if(\OC\Files\Filesystem::touch($newPath, $mtime)) { - header('X-OC-MTime: accepted'); - } - } - - return OC_Connector_Sabre_Node::getETagPropertyForPath($newPath); } - return null; + // rename to correct path + \OC\Files\Filesystem::rename($partpath, $newPath); + + // allow sync clients to send the mtime along in a header + $mtime = OC_Request::hasModificationTime(); + if ($mtime !== false) { + if(\OC\Files\Filesystem::touch($newPath, $mtime)) { + header('X-OC-MTime: accepted'); + } + } + + return OC_Connector_Sabre_Node::getETagPropertyForPath($newPath); } /** @@ -250,7 +237,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa * If the array is empty, all properties should be returned * * @param array $properties - * @return void + * @return array */ public function getProperties($properties) { $props = parent::getProperties($properties); @@ -260,4 +247,34 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa } return $props; } + + private function createFileChunked($name, $data) + { + $info = OC_FileChunking::decodeName($name); + if (empty($info)) { + throw new Sabre_DAV_Exception_NotImplemented(); + } + $chunk_handler = new OC_FileChunking($info); + $bytesWritten = $chunk_handler->store($info['index'], $data); + + //detect aborted upload + if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT' ) { + if (isset($_SERVER['CONTENT_LENGTH'])) { + $expected = $_SERVER['CONTENT_LENGTH']; + if ($bytesWritten != $expected) { + $chunk_handler->cleanup(); + throw new Sabre_DAV_Exception_BadRequest( + 'expected filesize ' . $expected . ' got ' . $bytesWritten); + } + } + } + + if ($chunk_handler->isComplete()) { + $newPath = $this->path . '/' . $info['name']; + $chunk_handler->file_assemble($newPath); + return OC_Connector_Sabre_Node::getETagPropertyForPath($newPath); + } + + return null; + } } From 61a534fb60eb275344e6cf7890fdfe88657e53a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 7 Oct 2013 17:49:21 +0200 Subject: [PATCH 4/4] moving createFileChunked() to OC_Connector_Sabre_File --- lib/private/connector/sabre/file.php | 49 +++++++++++++++++++--------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php index 8ffec371e3f..f2191732c0d 100644 --- a/lib/private/connector/sabre/file.php +++ b/lib/private/connector/sabre/file.php @@ -58,21 +58,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D // chunked handling if (isset($_SERVER['HTTP_OC_CHUNKED'])) { - list(, $name) = \Sabre_DAV_URLUtil::splitPath($this->path); - - $info = OC_FileChunking::decodeName($name); - if (empty($info)) { - throw new Sabre_DAV_Exception_NotImplemented(); - } - $chunk_handler = new OC_FileChunking($info); - $chunk_handler->store($info['index'], $data); - if ($chunk_handler->isComplete()) { - $newPath = $this->path . '/' . $info['name']; - $chunk_handler->file_assemble($newPath); - return $this->getETagPropertyForPath($newPath); - } - - return null; + return $this->createFileChunked($data); } // mark file as partial while uploading (ignored by the scanner) @@ -189,4 +175,37 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D return \OC\Files\Filesystem::getMimeType($this->path); } + + private function createFileChunked($data) + { + list($path, $name) = \Sabre_DAV_URLUtil::splitPath($this->path); + + $info = OC_FileChunking::decodeName($name); + if (empty($info)) { + throw new Sabre_DAV_Exception_NotImplemented(); + } + $chunk_handler = new OC_FileChunking($info); + $bytesWritten = $chunk_handler->store($info['index'], $data); + + //detect aborted upload + if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT' ) { + if (isset($_SERVER['CONTENT_LENGTH'])) { + $expected = $_SERVER['CONTENT_LENGTH']; + if ($bytesWritten != $expected) { + $chunk_handler->cleanup(); + throw new Sabre_DAV_Exception_BadRequest( + 'expected filesize ' . $expected . ' got ' . $bytesWritten); + } + } + } + + if ($chunk_handler->isComplete()) { + $newPath = $path . '/' . $info['name']; + $chunk_handler->file_assemble($newPath); + return OC_Connector_Sabre_Node::getETagPropertyForPath($newPath); + } + + return null; + } + }