From f522d1aaca28c73909daa0667450ca892bed6f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Mon, 31 Jul 2017 22:46:19 +0200 Subject: [PATCH 1/5] Handle OC-Total-Length in new chunking - fixes #26988 --- apps/dav/bin/chunkperf.php | 4 +- apps/dav/lib/Connector/Sabre/File.php | 16 +- apps/dav/lib/Connector/Sabre/FilesPlugin.php | 56 +----- apps/dav/lib/Connector/Sabre/Node.php | 14 ++ apps/dav/lib/Server.php | 2 + apps/dav/lib/Upload/ChunkingPlugin.php | 106 +++++++++++ .../tests/unit/Connector/Sabre/FileTest.php | 5 + .../unit/Connector/Sabre/FilesPluginTest.php | 57 ------ .../tests/unit/Upload/ChunkingPluginTest.php | 167 ++++++++++++++++++ 9 files changed, 302 insertions(+), 125 deletions(-) create mode 100644 apps/dav/lib/Upload/ChunkingPlugin.php create mode 100644 apps/dav/tests/unit/Upload/ChunkingPluginTest.php diff --git a/apps/dav/bin/chunkperf.php b/apps/dav/bin/chunkperf.php index 1a0cec416e2c..44b89394989f 100644 --- a/apps/dav/bin/chunkperf.php +++ b/apps/dav/bin/chunkperf.php @@ -72,5 +72,7 @@ function request($client, $method, $uploadUrl, $data = null, $headers = []) { $destination = pathinfo($file, PATHINFO_BASENAME); //echo "Moving $uploadUrl/.file to it's final destination $baseUri/files/$userName/$destination" . PHP_EOL; request($client, 'MOVE', "$uploadUrl/.file", null, [ - 'Destination' => "$baseUri/files/$userName/$destination" + 'Destination' => "$baseUri/files/$userName/$destination", + 'OC-Total-Length' => filesize($file), + 'X-OC-MTime' => filemtime($file) ]); diff --git a/apps/dav/lib/Connector/Sabre/File.php b/apps/dav/lib/Connector/Sabre/File.php index 2687defcdc55..c2407846207a 100644 --- a/apps/dav/lib/Connector/Sabre/File.php +++ b/apps/dav/lib/Connector/Sabre/File.php @@ -230,9 +230,7 @@ public function put($data) { // allow sync clients to send the mtime along in a header if (isset($this->request->server['HTTP_X_OC_MTIME'])) { - $mtime = $this->sanitizeMtime( - $this->request->server ['HTTP_X_OC_MTIME'] - ); + $mtime = $this->sanitizeMtime($this->request->server ['HTTP_X_OC_MTIME']); if ($this->fileView->touch($this->path, $mtime)) { header('X-OC-MTime: accepted'); } @@ -616,18 +614,6 @@ private function convertToSabreException(\Exception $e) { throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e); } - private function sanitizeMtime ($mtimeFromRequest) { - $mtime = (float) $mtimeFromRequest; - if ($mtime >= PHP_INT_MAX) { - $mtime = PHP_INT_MAX; - } elseif ($mtime <= (PHP_INT_MAX*-1)) { - $mtime = (PHP_INT_MAX*-1); - } else { - $mtime = (int) $mtimeFromRequest; - } - return $mtime; - } - /** * Set $algo to get a specific checksum, leave null to get all checksums * (space seperated) diff --git a/apps/dav/lib/Connector/Sabre/FilesPlugin.php b/apps/dav/lib/Connector/Sabre/FilesPlugin.php index 22aedd69e329..c814b582786b 100644 --- a/apps/dav/lib/Connector/Sabre/FilesPlugin.php +++ b/apps/dav/lib/Connector/Sabre/FilesPlugin.php @@ -30,7 +30,7 @@ namespace OCA\DAV\Connector\Sabre; -use OC\Files\View; +use OC\AppFramework\Http\Request; use OCP\Files\ForbiddenException; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; @@ -44,9 +44,6 @@ use OCP\Files\StorageNotAvailableException; use OCP\IConfig; use OCP\IRequest; -use Sabre\DAV\Exception\BadRequest; -use OCA\DAV\Connector\Sabre\Directory; -use OCA\DAV\Upload\FutureFile; class FilesPlugin extends ServerPlugin { @@ -85,11 +82,6 @@ class FilesPlugin extends ServerPlugin { */ private $isPublic; - /** - * @var View - */ - private $fileView; - /** * @var bool */ @@ -167,7 +159,6 @@ public function initialize(\Sabre\DAV\Server $server) { } }); $this->server->on('beforeMove', [$this, 'checkMove']); - $this->server->on('beforeMove', [$this, 'beforeMoveFutureFile']); } /** @@ -240,9 +231,9 @@ function httpGet(RequestInterface $request, ResponseInterface $response) { $filename = $node->getName(); if ($this->request->isUserAgent( [ - \OC\AppFramework\Http\Request::USER_AGENT_IE, - \OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME, - \OC\AppFramework\Http\Request::USER_AGENT_FREEBOX, + Request::USER_AGENT_IE, + Request::USER_AGENT_ANDROID_MOBILE_CHROME, + Request::USER_AGENT_FREEBOX, ])) { $response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"'); } else { @@ -418,43 +409,4 @@ public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) { } } } - - /** - * Move handler for future file. - * - * This overrides the default move behavior to prevent Sabre - * to delete the target file before moving. Because deleting would - * lose the file id and metadata. - * - * @param string $path source path - * @param string $destination destination path - * @return bool|void false to stop handling, void to skip this handler - */ - public function beforeMoveFutureFile($path, $destination) { - $sourceNode = $this->tree->getNodeForPath($path); - if (!$sourceNode instanceof FutureFile) { - // skip handling as the source is not a chunked FutureFile - return; - } - - if (!$this->tree->nodeExists($destination)) { - // skip and let the default handler do its work - return; - } - - // do a move manually, skipping Sabre's default "delete" for existing nodes - $this->tree->move($path, $destination); - - // trigger all default events (copied from CorePlugin::move) - $this->server->emit('afterMove', [$path, $destination]); - $this->server->emit('afterUnbind', [$path]); - $this->server->emit('afterBind', [$destination]); - - $response = $this->server->httpResponse; - $response->setHeader('Content-Length', '0'); - $response->setStatus(204); - - return false; - } - } diff --git a/apps/dav/lib/Connector/Sabre/Node.php b/apps/dav/lib/Connector/Sabre/Node.php index 52c76a61a9c3..494d4d635213 100644 --- a/apps/dav/lib/Connector/Sabre/Node.php +++ b/apps/dav/lib/Connector/Sabre/Node.php @@ -164,6 +164,7 @@ public function getLastModified() { * Even if the modification time is set to a custom value the access time is set to now. */ public function touch($mtime) { + $mtime = $this->sanitizeMtime($mtime); $this->fileView->touch($this->path, $mtime); $this->refreshInfo(); } @@ -369,4 +370,17 @@ public function changeLock($type) { public function getFileInfo() { return $this->info; } + + protected function sanitizeMtime ($mtimeFromRequest) { + $mtime = (float) $mtimeFromRequest; + if ($mtime >= PHP_INT_MAX) { + $mtime = PHP_INT_MAX; + } elseif ($mtime <= (PHP_INT_MAX*-1)) { + $mtime = (PHP_INT_MAX*-1); + } else { + $mtime = (int) $mtimeFromRequest; + } + return $mtime; + } + } diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php index e6807c8d73d4..6f5b140e1dc3 100644 --- a/apps/dav/lib/Server.php +++ b/apps/dav/lib/Server.php @@ -43,6 +43,7 @@ use OCA\DAV\Files\BrowserErrorPagePlugin; use OCA\DAV\Files\CustomPropertiesBackend; use OCA\DAV\SystemTag\SystemTagPlugin; +use OCA\DAV\Upload\ChunkingPlugin; use OCP\IRequest; use OCP\SabrePluginEvent; use Sabre\CardDAV\VCFExportPlugin; @@ -139,6 +140,7 @@ public function __construct(IRequest $request, $baseUri) { )); $this->server->addPlugin(new CopyEtagHeaderPlugin()); + $this->server->addPlugin(new ChunkingPlugin()); // Some WebDAV clients do require Class 2 WebDAV support (locking), since // we do not provide locking we emulate it using a fake locking plugin. diff --git a/apps/dav/lib/Upload/ChunkingPlugin.php b/apps/dav/lib/Upload/ChunkingPlugin.php new file mode 100644 index 000000000000..8d56bcc8d9ea --- /dev/null +++ b/apps/dav/lib/Upload/ChunkingPlugin.php @@ -0,0 +1,106 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 OCA\DAV\Upload; + + +use OCA\DAV\Connector\Sabre\File; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\Server; +use Sabre\DAV\ServerPlugin; + +class ChunkingPlugin extends ServerPlugin { + + /** @var Server */ + private $server; + /** @var FutureFile */ + private $sourceNode; + + /** + * @inheritdoc + */ + function initialize(Server $server) { + $server->on('beforeMove', [$this, 'beforeMove']); + $this->server = $server; + } + + /** + * @param string $sourcePath source path + * @param string $destination destination path + */ + function beforeMove($sourcePath, $destination) { + $this->sourceNode = $this->server->tree->getNodeForPath($sourcePath); + if (!$this->sourceNode instanceof FutureFile) { + // skip handling as the source is not a chunked FutureFile + return; + } + + $this->verifySize(); + return $this->performMove($sourcePath, $destination); + } + + /** + * Move handler for future file. + * + * This overrides the default move behavior to prevent Sabre + * to delete the target file before moving. Because deleting would + * lose the file id and metadata. + * + * @param string $path source path + * @param string $destination destination path + * @return bool|void false to stop handling, void to skip this handler + */ + public function performMove($path, $destination) { + if (!$this->server->tree->nodeExists($destination)) { + // skip and let the default handler do its work + return; + } + + // do a move manually, skipping Sabre's default "delete" for existing nodes + $this->server->tree->move($path, $destination); + + // trigger all default events (copied from CorePlugin::move) + $this->server->emit('afterMove', [$path, $destination]); + $this->server->emit('afterUnbind', [$path]); + $this->server->emit('afterBind', [$destination]); + + $response = $this->server->httpResponse; + $response->setHeader('Content-Length', '0'); + $response->setStatus(204); + + return false; + } + + /** + * @throws BadRequest + */ + private function verifySize() { + $expectedSize = $this->server->httpRequest->getHeader('OC-Total-Length'); + if ($expectedSize === null) { + return; + } + $actualSize = $this->sourceNode->getSize(); + if ((int)$expectedSize !== $actualSize) { + throw new BadRequest("Chunks on server do not sum up to $expectedSize but to $actualSize"); + } + } +} diff --git a/apps/dav/tests/unit/Connector/Sabre/FileTest.php b/apps/dav/tests/unit/Connector/Sabre/FileTest.php index 374ca20f3cc6..7e78ffd49905 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FileTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FileTest.php @@ -39,6 +39,7 @@ use OCP\Files\NotPermittedException; use OCP\Files\Storage; use OCP\Files\StorageNotAvailableException; +use OCP\IConfig; use OCP\Lock\LockedException; use OCP\Util; use Sabre\DAV\Exception; @@ -92,6 +93,9 @@ public function tearDown() { parent::tearDown(); } + /** + * @return \PHPUnit_Framework_MockObject_MockObject | Storage + */ private function getMockStorage() { $storage = $this->createMock(Storage::class); $storage->expects($this->any()) @@ -177,6 +181,7 @@ public function testSimplePutFails($thrownException, $expectedException, $checkP ->setConstructorArgs([['datadir' => \OC::$server->getTempManager()->getTemporaryFolder()]]) ->getMock(); Filesystem::mount($storage, [], $this->user . '/'); + /** @var View | \PHPUnit_Framework_MockObject_MockObject $view */ $view = $this->getMockBuilder(View::class) ->setMethods(['getRelativePath', 'resolvePath']) ->setConstructorArgs([]) diff --git a/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php index 182f3e01ebb1..b38512e0bf4b 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FilesPluginTest.php @@ -33,8 +33,6 @@ use Sabre\HTTP\ResponseInterface; use Test\TestCase; use OCP\Files\FileInfo; -use OCA\DAV\Upload\FutureFile; -use OCA\DAV\Connector\Sabre\Directory; /** * Copyright (c) 2015 Vincent Petry @@ -549,59 +547,4 @@ public function testDownloadHeaders($isClumsyAgent, $contentDispositionHeader) { $this->plugin->httpGet($request, $response); } - - public function testBeforeMoveFutureFileSkip() { - $node = $this->createMock(Directory::class); - - $this->tree->expects($this->any()) - ->method('getNodeForPath') - ->with('source') - ->will($this->returnValue($node)); - $this->server->httpResponse->expects($this->never()) - ->method('setStatus'); - - $this->assertNull($this->plugin->beforeMoveFutureFile('source', 'target')); - } - - public function testBeforeMoveFutureFileSkipNonExisting() { - $sourceNode = $this->createMock(FutureFile::class); - - $this->tree->expects($this->any()) - ->method('getNodeForPath') - ->with('source') - ->will($this->returnValue($sourceNode)); - $this->tree->expects($this->any()) - ->method('nodeExists') - ->with('target') - ->will($this->returnValue(false)); - $this->server->httpResponse->expects($this->never()) - ->method('setStatus'); - - $this->assertNull($this->plugin->beforeMoveFutureFile('source', 'target')); - } - - public function testBeforeMoveFutureFileMoveIt() { - $sourceNode = $this->createMock(FutureFile::class); - - $this->tree->expects($this->any()) - ->method('getNodeForPath') - ->with('source') - ->will($this->returnValue($sourceNode)); - $this->tree->expects($this->any()) - ->method('nodeExists') - ->with('target') - ->will($this->returnValue(true)); - $this->tree->expects($this->once()) - ->method('move') - ->with('source', 'target'); - - $this->server->httpResponse->expects($this->once()) - ->method('setHeader') - ->with('Content-Length', '0'); - $this->server->httpResponse->expects($this->once()) - ->method('setStatus') - ->with(204); - - $this->assertFalse($this->plugin->beforeMoveFutureFile('source', 'target')); - } } diff --git a/apps/dav/tests/unit/Upload/ChunkingPluginTest.php b/apps/dav/tests/unit/Upload/ChunkingPluginTest.php new file mode 100644 index 000000000000..a392d2b78f64 --- /dev/null +++ b/apps/dav/tests/unit/Upload/ChunkingPluginTest.php @@ -0,0 +1,167 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 OCA\DAV\Tests\unit\Upload; + + +use OCA\DAV\Upload\ChunkingPlugin; +use Sabre\HTTP\RequestInterface; +use Sabre\HTTP\ResponseInterface; +use Test\TestCase; +use OCA\DAV\Upload\FutureFile; +use OCA\DAV\Connector\Sabre\Directory; + +class ChunkingPluginTest extends TestCase { + + + /** + * @var \Sabre\DAV\Server | \PHPUnit_Framework_MockObject_MockObject + */ + private $server; + + /** + * @var \Sabre\DAV\Tree | \PHPUnit_Framework_MockObject_MockObject + */ + private $tree; + + /** + * @var ChunkingPlugin + */ + private $plugin; + /** @var RequestInterface | \PHPUnit_Framework_MockObject_MockObject */ + private $request; + /** @var ResponseInterface | \PHPUnit_Framework_MockObject_MockObject */ + private $response; + + public function setUp() { + parent::setUp(); + + $this->server = $this->getMockBuilder('\Sabre\DAV\Server') + ->disableOriginalConstructor() + ->getMock(); + $this->tree = $this->getMockBuilder('\Sabre\DAV\Tree') + ->disableOriginalConstructor() + ->getMock(); + + $this->server->tree = $this->tree; + $this->plugin = new ChunkingPlugin(); + + $this->request = $this->createMock(RequestInterface::class); + $this->response = $this->createMock(ResponseInterface::class); + $this->server->httpRequest = $this->request; + $this->server->httpResponse = $this->response; + + $this->plugin->initialize($this->server); + } + + public function testBeforeMoveFutureFileSkip() { + $node = $this->createMock(Directory::class); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('source') + ->will($this->returnValue($node)); + $this->response->expects($this->never()) + ->method('setStatus'); + + $this->assertNull($this->plugin->beforeMove('source', 'target')); + } + + public function testBeforeMoveFutureFileSkipNonExisting() { + $sourceNode = $this->createMock(FutureFile::class); + $sourceNode->expects($this->once()) + ->method('getSize') + ->willReturn(4); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('source') + ->will($this->returnValue($sourceNode)); + $this->tree->expects($this->any()) + ->method('nodeExists') + ->with('target') + ->will($this->returnValue(false)); + $this->response->expects($this->never()) + ->method('setStatus'); + $this->request->expects($this->once()) + ->method('getHeader') + ->with('OC-Total-Length') + ->willReturn(4); + + $this->assertNull($this->plugin->beforeMove('source', 'target')); + } + + public function testBeforeMoveFutureFileMoveIt() { + $sourceNode = $this->createMock(FutureFile::class); + $sourceNode->expects($this->once()) + ->method('getSize') + ->willReturn(4); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('source') + ->will($this->returnValue($sourceNode)); + $this->tree->expects($this->any()) + ->method('nodeExists') + ->with('target') + ->will($this->returnValue(true)); + $this->tree->expects($this->once()) + ->method('move') + ->with('source', 'target'); + + $this->response->expects($this->once()) + ->method('setHeader') + ->with('Content-Length', '0'); + $this->response->expects($this->once()) + ->method('setStatus') + ->with(204); + $this->request->expects($this->once()) + ->method('getHeader') + ->with('OC-Total-Length') + ->willReturn('4'); + + $this->assertFalse($this->plugin->beforeMove('source', 'target')); + } + + /** + * @expectedException \Sabre\DAV\Exception\BadRequest + * @expectedExceptionMessage Chunks on server do not sum up to 4 but to 3 + */ + public function testBeforeMoveSizeIsWrong() { + $sourceNode = $this->createMock(FutureFile::class); + $sourceNode->expects($this->once()) + ->method('getSize') + ->willReturn(3); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('source') + ->will($this->returnValue($sourceNode)); + $this->request->expects($this->once()) + ->method('getHeader') + ->with('OC-Total-Length') + ->willReturn('4'); + + $this->assertFalse($this->plugin->beforeMove('source', 'target')); + } + +} From f077743ed7aa81882788cbfb04e0d9132294495a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Thu, 10 Aug 2017 12:14:02 +0200 Subject: [PATCH 2/5] Add integration tests for length header on new chunking --- .../integration/features/bootstrap/WebDav.php | 17 ++++++++++++++ .../webdav-related-new-endpoint.feature | 22 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/tests/integration/features/bootstrap/WebDav.php b/tests/integration/features/bootstrap/WebDav.php index 1cb375232c96..f8277f8ff9a6 100644 --- a/tests/integration/features/bootstrap/WebDav.php +++ b/tests/integration/features/bootstrap/WebDav.php @@ -895,6 +895,23 @@ public function userMovesNewChunkFileWithIdToMychunkedfile($user, $id, $dest) } } + /** + * @Then user :user moves new chunk file with id :id to :dest with size :size + */ + public function userMovesNewChunkFileWithIdToMychunkedfileWithSize($user, $id, $dest, $size) + { + $source = '/uploads/' . $user . '/' . $id . '/.file'; + $destination = $this->baseUrlWithoutOCSAppendix() . $this->getDavFilesPath($user) . $dest; + + try { + $this->response = $this->makeDavRequest($user, 'MOVE', $source, [ + 'Destination' => $destination, + 'OC-Total-Length' => $size + ], null, "uploads"); + } catch(\GuzzleHttp\Exception\BadResponseException $ex) { + $this->response = $ex->getResponse(); + } + } /** * @Given /^Downloading file "([^"]*)" as "([^"]*)"$/ diff --git a/tests/integration/features/webdav-related-new-endpoint.feature b/tests/integration/features/webdav-related-new-endpoint.feature index 3c65b636b3f6..0bc682f4ca6f 100644 --- a/tests/integration/features/webdav-related-new-endpoint.feature +++ b/tests/integration/features/webdav-related-new-endpoint.feature @@ -579,4 +579,24 @@ Feature: webdav-related-new-endpoint Given using new dav path And user "user0" exists When user "user0" uploads chunk file "1" of "3" with "AAAAA" to "/myChunkedFile.txt" - Then the HTTP status code should be "503" \ No newline at end of file + Then the HTTP status code should be "503" + + Scenario: Upload file via new chunking endpoint with wrong size header + Given using new dav path + And user "user0" exists + And user "user0" creates a new chunking upload with id "chunking-42" + And user "user0" uploads new chunk file "1" with "AAAAA" to id "chunking-42" + And user "user0" uploads new chunk file "2" with "BBBBB" to id "chunking-42" + And user "user0" uploads new chunk file "3" with "CCCCC" to id "chunking-42" + When user "user0" moves new chunk file with id "chunking-42" to "/myChunkedFile.txt" with size 5 + Then the HTTP status code should be "400" + + Scenario: Upload file via new chunking endpoint with correct size header + Given using new dav path + And user "user0" exists + And user "user0" creates a new chunking upload with id "chunking-42" + And user "user0" uploads new chunk file "1" with "AAAAA" to id "chunking-42" + And user "user0" uploads new chunk file "2" with "BBBBB" to id "chunking-42" + And user "user0" uploads new chunk file "3" with "CCCCC" to id "chunking-42" + When user "user0" moves new chunk file with id "chunking-42" to "/myChunkedFile.txt" with size 15 + Then the HTTP status code should be "201" From 87b492902e65a955cb58b3d2d14469dcdaa2fb5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Thu, 10 Aug 2017 12:23:20 +0200 Subject: [PATCH 3/5] Transmit OC-Total-Length in browser as well --- apps/files/js/file-upload.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 4b1688a0da45..758e317d17d3 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -288,7 +288,10 @@ OC.FileUpload.prototype = { 'uploads/' + encodeURIComponent(uid) + '/' + encodeURIComponent(this.getId()) + '/.file', 'files/' + encodeURIComponent(uid) + '/' + OC.joinPaths(this.getFullPath(), this.getFileName()), true, - {'X-OC-Mtime': this.getFile().lastModified / 1000} + { + 'X-OC-Mtime': this.getFile().lastModified / 1000, + 'OC-Total-Length': this.getFile().size + } ); }, From a08ddd4240edf0e94f09a754d536496fedfd96a3 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 11 Aug 2017 12:01:04 +0200 Subject: [PATCH 4/5] Only set X-OC-Mtime when browser provided lastModified on upload --- apps/files/js/file-upload.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 758e317d17d3..4ab1a93de500 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -284,14 +284,22 @@ OC.FileUpload.prototype = { } var uid = OC.getCurrentUser().uid; + var mtime = this.getFile().lastModified; + var size = this.getFile().size; + var headers = {}; + if (mtime) { + headers['X-OC-Mtime'] = mtime / 1000; + } + if (size) { + headers['OC-Total-Length'] = size; + + } + return this.uploader.davClient.move( 'uploads/' + encodeURIComponent(uid) + '/' + encodeURIComponent(this.getId()) + '/.file', 'files/' + encodeURIComponent(uid) + '/' + OC.joinPaths(this.getFullPath(), this.getFileName()), true, - { - 'X-OC-Mtime': this.getFile().lastModified / 1000, - 'OC-Total-Length': this.getFile().size - } + headers ); }, From ee33eca8115b9885d8b40ea432623925bef90870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 11 Aug 2017 14:23:01 +0200 Subject: [PATCH 5/5] Add mb4 container id .... --- build/autotest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/autotest.sh b/build/autotest.sh index 853846bc063e..1766eda458f5 100755 --- a/build/autotest.sh +++ b/build/autotest.sh @@ -229,7 +229,7 @@ function execute_tests { DATABASEHOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "$DOCKER_CONTAINER_ID") - echo "Waiting for MySQL(utf8mb4) initialisation ..." + echo "Waiting for MySQL(utf8mb4) initialisation of container $DOCKER_CONTAINER_ID ..." if ! apps/files_external/tests/env/wait-for-connection $DATABASEHOST 3306 600; then echo "[ERROR] Waited 600 seconds, no response" >&2