mirror of https://github.com/nextcloud/server
Set the file's mtime from the headers in bulk upload
Signed-off-by: Louis Chemineau <louis@chmn.me>
This commit is contained in:
parent
b23934a45e
commit
69b8044b8f
|
@ -149,7 +149,7 @@ class ClassLoader
|
|||
|
||||
/**
|
||||
* @return string[] Array of classname => path
|
||||
* @psalm-var array<string, string>
|
||||
* @psalm-return array<string, string>
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
|
|
|
@ -163,6 +163,7 @@ return array(
|
|||
'OCA\\DAV\\Connector\\Sabre\\FilesReportPlugin' => $baseDir . '/../lib/Connector/Sabre/FilesReportPlugin.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\LockPlugin' => $baseDir . '/../lib/Connector/Sabre/LockPlugin.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\MaintenancePlugin' => $baseDir . '/../lib/Connector/Sabre/MaintenancePlugin.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\MtimeSanitizer' => $baseDir . '/../lib/Connector/Sabre/MtimeSanitizer.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\Node' => $baseDir . '/../lib/Connector/Sabre/Node.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\ObjectTree' => $baseDir . '/../lib/Connector/Sabre/ObjectTree.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\Principal' => $baseDir . '/../lib/Connector/Sabre/Principal.php',
|
||||
|
|
|
@ -178,6 +178,7 @@ class ComposerStaticInitDAV
|
|||
'OCA\\DAV\\Connector\\Sabre\\FilesReportPlugin' => __DIR__ . '/..' . '/../lib/Connector/Sabre/FilesReportPlugin.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\LockPlugin' => __DIR__ . '/..' . '/../lib/Connector/Sabre/LockPlugin.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\MaintenancePlugin' => __DIR__ . '/..' . '/../lib/Connector/Sabre/MaintenancePlugin.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\MtimeSanitizer' => __DIR__ . '/..' . '/../lib/Connector/Sabre/MtimeSanitizer.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\Node' => __DIR__ . '/..' . '/../lib/Connector/Sabre/Node.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\ObjectTree' => __DIR__ . '/..' . '/../lib/Connector/Sabre/ObjectTree.php',
|
||||
'OCA\\DAV\\Connector\\Sabre\\Principal' => __DIR__ . '/..' . '/../lib/Connector/Sabre/Principal.php',
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../',
|
||||
'aliases' => array(),
|
||||
'reference' => 'c6429e6cd19c57582364338362e543580821cf99',
|
||||
'reference' => 'e2c675724fc4ea50f1275bf0027b96f277c32578',
|
||||
'name' => '__root__',
|
||||
'dev' => false,
|
||||
),
|
||||
|
@ -16,7 +16,7 @@
|
|||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../',
|
||||
'aliases' => array(),
|
||||
'reference' => 'c6429e6cd19c57582364338362e543580821cf99',
|
||||
'reference' => 'e2c675724fc4ea50f1275bf0027b96f277c32578',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
),
|
||||
|
|
|
@ -29,6 +29,7 @@ use Sabre\HTTP\RequestInterface;
|
|||
use Sabre\HTTP\ResponseInterface;
|
||||
use OCP\Files\Folder;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCA\DAV\Connector\Sabre\MtimeSanitizer;
|
||||
|
||||
class BulkUploadPlugin extends ServerPlugin {
|
||||
|
||||
|
@ -78,7 +79,18 @@ class BulkUploadPlugin extends ServerPlugin {
|
|||
}
|
||||
|
||||
try {
|
||||
// TODO: Remove 'x-file-mtime' when the desktop client no longer use it.
|
||||
if (isset($headers['x-file-mtime'])) {
|
||||
$mtime = MtimeSanitizer::sanitizeMtime($headers['x-file-mtime']);
|
||||
} elseif (isset($headers['x-oc-mtime'])) {
|
||||
$mtime = MtimeSanitizer::sanitizeMtime($headers['x-oc-mtime']);
|
||||
} else {
|
||||
$mtime = null;
|
||||
}
|
||||
|
||||
$node = $this->userFolder->newFile($headers['x-file-path'], $content);
|
||||
$node->touch($mtime);
|
||||
|
||||
$writtenFiles[$headers['x-file-path']] = [
|
||||
"error" => false,
|
||||
"etag" => $node->getETag(),
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2021, Louis Chemineau <louis@chmn.me>
|
||||
*
|
||||
* @author Louis Chemineau <louis@chmn.me>
|
||||
*
|
||||
* @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 <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\Connector\Sabre;
|
||||
|
||||
class MtimeSanitizer {
|
||||
public static function sanitizeMtime(string $mtimeFromRequest): int {
|
||||
// In PHP 5.X "is_numeric" returns true for strings in hexadecimal
|
||||
// notation. This is no longer the case in PHP 7.X, so this check
|
||||
// ensures that strings with hexadecimal notations fail too in PHP 5.X.
|
||||
$isHexadecimal = preg_match('/^\s*0[xX]/', $mtimeFromRequest);
|
||||
if ($isHexadecimal || !is_numeric($mtimeFromRequest)) {
|
||||
throw new \InvalidArgumentException('X-OC-MTime header must be an integer (unix timestamp).');
|
||||
}
|
||||
|
||||
// Prevent writing invalid mtime (timezone-proof)
|
||||
if ((int)$mtimeFromRequest <= 24 * 60 * 60) {
|
||||
throw new \InvalidArgumentException('X-OC-MTime header must be a valid positive integer');
|
||||
}
|
||||
|
||||
return (int)$mtimeFromRequest;
|
||||
}
|
||||
}
|
|
@ -404,19 +404,6 @@ abstract class Node implements \Sabre\DAV\INode {
|
|||
}
|
||||
|
||||
protected function sanitizeMtime($mtimeFromRequest) {
|
||||
// In PHP 5.X "is_numeric" returns true for strings in hexadecimal
|
||||
// notation. This is no longer the case in PHP 7.X, so this check
|
||||
// ensures that strings with hexadecimal notations fail too in PHP 5.X.
|
||||
$isHexadecimal = is_string($mtimeFromRequest) && preg_match('/^\s*0[xX]/', $mtimeFromRequest);
|
||||
if ($isHexadecimal || !is_numeric($mtimeFromRequest)) {
|
||||
throw new \InvalidArgumentException('X-OC-MTime header must be an integer (unix timestamp).');
|
||||
}
|
||||
|
||||
// Prevent writing invalid mtime (timezone-proof)
|
||||
if ((int)$mtimeFromRequest <= 24 * 60 * 60) {
|
||||
throw new \InvalidArgumentException('X-OC-MTime header must be a valid positive integer');
|
||||
}
|
||||
|
||||
return (int)$mtimeFromRequest;
|
||||
return MtimeSanitizer::sanitizeMtime($mtimeFromRequest);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ do
|
|||
echo -en "--$BOUNDARY\r\n"
|
||||
# echo -en "Content-ID: $file_name\r\n"
|
||||
echo -en "X-File-Path: $file_remote_path\r\n"
|
||||
echo -en "X-File-Mtime: $file_mtime\r\n"
|
||||
echo -en "X-OC-Mtime: $file_mtime\r\n"
|
||||
# echo -en "X-File-Id: $file_id\r\n"
|
||||
echo -en "X-File-Md5: $file_hash\r\n"
|
||||
echo -en "Content-Length: $file_size\r\n"
|
||||
|
|
|
@ -207,6 +207,19 @@ trait WebDav {
|
|||
Assert::assertEquals($content, (string)$this->response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^File "([^"]*)" should have prop "([^"]*):([^"]*)" equal to "([^"]*)"$/
|
||||
* @param string $file
|
||||
* @param string $prefix
|
||||
* @param string $prop
|
||||
* @param string $value
|
||||
*/
|
||||
public function checkPropForFile($file, $prefix, $prop, $value) {
|
||||
$elementList = $this->propfindFile($this->currentUser, $file, "<$prefix:$prop/>");
|
||||
$property = $elementList['/'.$this->getDavFilesPath($this->currentUser).$file][200]["{DAV:}$prop"];
|
||||
Assert::assertEquals($property, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^Downloaded content when downloading file "([^"]*)" with range "([^"]*)" should be "([^"]*)"$/
|
||||
* @param string $fileSource
|
||||
|
@ -380,6 +393,30 @@ trait WebDav {
|
|||
return $response;
|
||||
}
|
||||
|
||||
/* Returns the elements of a report command
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
* @param string $properties properties which needs to be included in the report
|
||||
* @param string $filterRules filter-rules to choose what needs to appear in the report
|
||||
*/
|
||||
public function propfindFile($user, $path, $properties = '') {
|
||||
$client = $this->getSabreClient($user);
|
||||
|
||||
$body = '<?xml version="1.0" encoding="utf-8" ?>
|
||||
<d:propfind xmlns:d="DAV:"
|
||||
xmlns:oc="http://owncloud.org/ns"
|
||||
xmlns:nc="http://nextcloud.org/ns"
|
||||
xmlns:ocs="http://open-collaboration-services.org/ns">
|
||||
<d:prop>
|
||||
' . $properties . '
|
||||
</d:prop>
|
||||
</d:propfind>';
|
||||
|
||||
$response = $client->request('PROPFIND', $this->makeSabrePath($user, $path), $body);
|
||||
$parsedResponse = $client->parseMultistatus($response['body']);
|
||||
return $parsedResponse;
|
||||
}
|
||||
|
||||
/* Returns the elements of a report command
|
||||
* @param string $user
|
||||
* @param string $path
|
||||
|
@ -561,25 +598,28 @@ trait WebDav {
|
|||
* @param string $name3
|
||||
* @param string $content3
|
||||
*/
|
||||
public function userUploadsChunkedFiles($user, $name1, $content1, $name2, $content2, $name3, $content3) {
|
||||
public function userUploadsBulkedFiles($user, $name1, $content1, $name2, $content2, $name3, $content3) {
|
||||
$boundary = "boundary_azertyuiop";
|
||||
|
||||
$body = "";
|
||||
$body .= '--'.$boundary."\r\n";
|
||||
$body .= "X-File-Path: ".$name1."\r\n";
|
||||
$body .= "X-File-MD5: f6a6263167c92de8644ac998b3c4e4d1\r\n";
|
||||
$body .= "X-OC-Mtime: 1111111111\r\n";
|
||||
$body .= "Content-Length: ".strlen($content1)."\r\n";
|
||||
$body .= "\r\n";
|
||||
$body .= $content1."\r\n";
|
||||
$body .= '--'.$boundary."\r\n";
|
||||
$body .= "X-File-Path: ".$name2."\r\n";
|
||||
$body .= "X-File-MD5: 87c7d4068be07d390a1fffd21bf1e944\r\n";
|
||||
$body .= "X-OC-Mtime: 2222222222\r\n";
|
||||
$body .= "Content-Length: ".strlen($content2)."\r\n";
|
||||
$body .= "\r\n";
|
||||
$body .= $content2."\r\n";
|
||||
$body .= '--'.$boundary."\r\n";
|
||||
$body .= "X-File-Path: ".$name3."\r\n";
|
||||
$body .= "X-File-MD5: e86a1cf0678099986a901c79086f5617\r\n";
|
||||
$body .= "X-File-Mtime: 3333333333\r\n";
|
||||
$body .= "Content-Length: ".strlen($content3)."\r\n";
|
||||
$body .= "\r\n";
|
||||
$body .= $content3."\r\n";
|
||||
|
|
|
@ -615,10 +615,13 @@ Feature: webdav-related
|
|||
When As an "user0"
|
||||
Then Downloading file "/A.txt"
|
||||
And Downloaded content should be "AAAAA"
|
||||
And File "/A.txt" should have prop "d:getlastmodified" equal to "Fri, 18 Mar 2005 01:58:31 GMT"
|
||||
And Downloading file "/B.txt"
|
||||
And Downloaded content should be "BBBBB"
|
||||
And File "/B.txt" should have prop "d:getlastmodified" equal to "Sat, 02 Jun 2040 03:57:02 GMT"
|
||||
And Downloading file "/C.txt"
|
||||
And Downloaded content should be "CCCCC"
|
||||
And File "/C.txt" should have prop "d:getlastmodified" equal to "Sun, 18 Aug 2075 05:55:33 GMT"
|
||||
|
||||
Scenario: Creating a folder with invalid characters
|
||||
Given using new dav path
|
||||
|
|
Loading…
Reference in New Issue