Not needed any more in IE >= 11 Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>pull/1283/head
parent
25d9dce067
commit
c68e273664
@ -1,188 +0,0 @@ |
||||
<?php |
||||
/** |
||||
* @author Vincent Petry <pvince81@owncloud.com> |
||||
* |
||||
* @copyright Copyright (c) 2015, ownCloud, Inc. |
||||
* @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; |
||||
|
||||
use Sabre\DAV\IFile; |
||||
use Sabre\HTTP\RequestInterface; |
||||
use Sabre\HTTP\ResponseInterface; |
||||
use Sabre\DAV\Exception\BadRequest; |
||||
|
||||
/** |
||||
* Plugin to receive Webdav PUT through POST, |
||||
* mostly used as a workaround for browsers that |
||||
* do not support PUT upload. |
||||
*/ |
||||
class IFrameTransportPlugin extends \Sabre\DAV\ServerPlugin { |
||||
|
||||
/** |
||||
* @var \Sabre\DAV\Server $server |
||||
*/ |
||||
private $server; |
||||
|
||||
/** |
||||
* This initializes the plugin. |
||||
* |
||||
* @param \Sabre\DAV\Server $server |
||||
* @return void |
||||
*/ |
||||
public function initialize(\Sabre\DAV\Server $server) { |
||||
$this->server = $server; |
||||
$this->server->on('method:POST', [$this, 'handlePost']); |
||||
} |
||||
|
||||
/** |
||||
* POST operation |
||||
* |
||||
* @param RequestInterface $request request object |
||||
* @param ResponseInterface $response response object |
||||
* @return null|false |
||||
*/ |
||||
public function handlePost(RequestInterface $request, ResponseInterface $response) { |
||||
try { |
||||
return $this->processUpload($request, $response); |
||||
} catch (\Sabre\DAV\Exception $e) { |
||||
$response->setStatus($e->getHTTPCode()); |
||||
$response->setBody(['message' => $e->getMessage()]); |
||||
$this->convertResponse($response); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Wrap and send response in JSON format |
||||
* |
||||
* @param ResponseInterface $response response object |
||||
*/ |
||||
private function convertResponse(ResponseInterface $response) { |
||||
if (is_resource($response->getBody())) { |
||||
throw new BadRequest('Cannot request binary data with iframe transport'); |
||||
} |
||||
|
||||
$responseData = json_encode([ |
||||
'status' => $response->getStatus(), |
||||
'headers' => $response->getHeaders(), |
||||
'data' => $response->getBody(), |
||||
]); |
||||
|
||||
// IE needs this content type |
||||
$response->setHeader('Content-Type', 'text/plain'); |
||||
$response->setHeader('Content-Length', strlen($responseData)); |
||||
$response->setStatus(200); |
||||
$response->setBody($responseData); |
||||
} |
||||
|
||||
/** |
||||
* Process upload |
||||
* |
||||
* @param RequestInterface $request request object |
||||
* @param ResponseInterface $response response object |
||||
* @return null|false |
||||
*/ |
||||
private function processUpload(RequestInterface $request, ResponseInterface $response) { |
||||
$queryParams = $request->getQueryParameters(); |
||||
|
||||
if (!isset($queryParams['_method'])) { |
||||
return null; |
||||
} |
||||
|
||||
$method = $queryParams['_method']; |
||||
if ($method !== 'PUT' && $method !== 'POST') { |
||||
return null; |
||||
} |
||||
|
||||
$contentType = $request->getHeader('Content-Type'); |
||||
list($contentType) = explode(';', $contentType); |
||||
if ($contentType !== 'application/x-www-form-urlencoded' |
||||
&& $contentType !== 'multipart/form-data' |
||||
) { |
||||
return null; |
||||
} |
||||
|
||||
if (!isset($_FILES['files'])) { |
||||
return null; |
||||
} |
||||
|
||||
// TODO: move this to another plugin ? |
||||
if (!\OC::$CLI && !\OC::$server->getRequest()->passesCSRFCheck()) { |
||||
throw new BadRequest('Invalid CSRF token'); |
||||
} |
||||
|
||||
if ($_FILES) { |
||||
$file = current($_FILES); |
||||
} else { |
||||
return null; |
||||
} |
||||
|
||||
if ($file['error'][0] !== 0) { |
||||
throw new BadRequest('Error during upload, code ' . $file['error'][0]); |
||||
} |
||||
|
||||
if (!\OC::$CLI && !is_uploaded_file($file['tmp_name'][0])) { |
||||
return null; |
||||
} |
||||
|
||||
if (count($file['tmp_name']) > 1) { |
||||
throw new BadRequest('Only a single file can be uploaded'); |
||||
} |
||||
|
||||
$postData = $request->getPostData(); |
||||
if (isset($postData['headers'])) { |
||||
$headers = json_decode($postData['headers'], true); |
||||
|
||||
// copy safe headers into the request |
||||
$allowedHeaders = [ |
||||
'If', |
||||
'If-Match', |
||||
'If-None-Match', |
||||
'If-Modified-Since', |
||||
'If-Unmodified-Since', |
||||
'Authorization', |
||||
]; |
||||
|
||||
foreach ($allowedHeaders as $allowedHeader) { |
||||
if (isset($headers[$allowedHeader])) { |
||||
$request->setHeader($allowedHeader, $headers[$allowedHeader]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// MEGAHACK, because the Sabre File impl reads this property directly |
||||
$_SERVER['CONTENT_LENGTH'] = $file['size'][0]; |
||||
$request->setHeader('Content-Length', $file['size'][0]); |
||||
|
||||
$tmpFile = $file['tmp_name'][0]; |
||||
$resource = fopen($tmpFile, 'r'); |
||||
|
||||
$request->setBody($resource); |
||||
$request->setMethod($method); |
||||
|
||||
$this->server->invokeMethod($request, $response, false); |
||||
|
||||
fclose($resource); |
||||
unlink($tmpFile); |
||||
|
||||
$this->convertResponse($response); |
||||
|
||||
return false; |
||||
} |
||||
|
||||
} |
||||
@ -1,164 +0,0 @@ |
||||
<?php |
||||
|
||||
namespace OCA\DAV\Tests\Unit\Connector\Sabre; |
||||
|
||||
/** |
||||
* Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> |
||||
* This file is licensed under the Affero General Public License version 3 or |
||||
* later. |
||||
* See the COPYING-README file. |
||||
*/ |
||||
class IFrameTransportPluginTest extends \Test\TestCase { |
||||
|
||||
/** |
||||
* @var \Sabre\DAV\Server |
||||
*/ |
||||
private $server; |
||||
|
||||
/** |
||||
* @var \OCA\DAV\Connector\Sabre\IFrameTransportPlugin |
||||
*/ |
||||
private $plugin; |
||||
|
||||
public function setUp() { |
||||
parent::setUp(); |
||||
$this->server = $this->getMockBuilder('\Sabre\DAV\Server') |
||||
->disableOriginalConstructor() |
||||
->getMock(); |
||||
|
||||
$this->plugin = new \OCA\DAV\Connector\Sabre\IFrameTransportPlugin(); |
||||
$this->plugin->initialize($this->server); |
||||
} |
||||
|
||||
public function tearDown() { |
||||
$_FILES = null; |
||||
unset($_SERVER['CONTENT_LENGTH']); |
||||
} |
||||
|
||||
public function testPutConversion() { |
||||
$request = $this->getMock('Sabre\HTTP\RequestInterface'); |
||||
$response = $this->getMock('Sabre\HTTP\ResponseInterface'); |
||||
|
||||
$request->expects($this->once()) |
||||
->method('getQueryParameters') |
||||
->will($this->returnValue(['_method' => 'PUT'])); |
||||
|
||||
$postData = [ |
||||
'headers' => json_encode([ |
||||
'If-None-Match' => '*', |
||||
'Disallowed-Header' => 'test', |
||||
]), |
||||
]; |
||||
|
||||
$request->expects($this->once()) |
||||
->method('getPostData') |
||||
->will($this->returnValue($postData)); |
||||
|
||||
$request->expects($this->once()) |
||||
->method('getHeader') |
||||
->with('Content-Type') |
||||
->will($this->returnValue('multipart/form-data')); |
||||
|
||||
$tmpFileName = tempnam(sys_get_temp_dir(), 'tmpfile'); |
||||
$fh = fopen($tmpFileName, 'w'); |
||||
fwrite($fh, 'hello'); |
||||
fclose($fh); |
||||
|
||||
$_FILES = ['files' => [ |
||||
'error' => [0], |
||||
'tmp_name' => [$tmpFileName], |
||||
'size' => [5], |
||||
]]; |
||||
|
||||
$request->expects($this->any()) |
||||
->method('setHeader') |
||||
->withConsecutive( |
||||
['If-None-Match', '*'], |
||||
['Content-Length', 5] |
||||
); |
||||
|
||||
$request->expects($this->once()) |
||||
->method('setMethod') |
||||
->with('PUT'); |
||||
|
||||
$this->server->expects($this->once()) |
||||
->method('invokeMethod') |
||||
->with($request, $response); |
||||
|
||||
// response data before conversion |
||||
$response->expects($this->once()) |
||||
->method('getHeaders') |
||||
->will($this->returnValue(['Test-Response-Header' => [123]])); |
||||
|
||||
$response->expects($this->any()) |
||||
->method('getBody') |
||||
->will($this->returnValue('test')); |
||||
|
||||
$response->expects($this->once()) |
||||
->method('getStatus') |
||||
->will($this->returnValue(201)); |
||||
|
||||
$responseBody = json_encode([ |
||||
'status' => 201, |
||||
'headers' => ['Test-Response-Header' => [123]], |
||||
'data' => 'test', |
||||
]); |
||||
|
||||
// response data after conversion |
||||
$response->expects($this->once()) |
||||
->method('setBody') |
||||
->with($responseBody); |
||||
|
||||
$response->expects($this->once()) |
||||
->method('setStatus') |
||||
->with(200); |
||||
|
||||
$response->expects($this->any()) |
||||
->method('setHeader') |
||||
->withConsecutive( |
||||
['Content-Type', 'text/plain'], |
||||
['Content-Length', strlen($responseBody)] |
||||
); |
||||
|
||||
$this->assertFalse($this->plugin->handlePost($request, $response)); |
||||
|
||||
$this->assertEquals(5, $_SERVER['CONTENT_LENGTH']); |
||||
|
||||
$this->assertFalse(file_exists($tmpFileName)); |
||||
} |
||||
|
||||
public function testIgnoreNonPut() { |
||||
$request = $this->getMock('Sabre\HTTP\RequestInterface'); |
||||
$response = $this->getMock('Sabre\HTTP\ResponseInterface'); |
||||
|
||||
$request->expects($this->once()) |
||||
->method('getQueryParameters') |
||||
->will($this->returnValue(['_method' => 'PROPFIND'])); |
||||
|
||||
$this->server->expects($this->never()) |
||||
->method('invokeMethod') |
||||
->with($request, $response); |
||||
|
||||
$this->assertNull($this->plugin->handlePost($request, $response)); |
||||
} |
||||
|
||||
public function testIgnoreMismatchedContentType() { |
||||
$request = $this->getMock('Sabre\HTTP\RequestInterface'); |
||||
$response = $this->getMock('Sabre\HTTP\ResponseInterface'); |
||||
|
||||
$request->expects($this->once()) |
||||
->method('getQueryParameters') |
||||
->will($this->returnValue(['_method' => 'PUT'])); |
||||
|
||||
$request->expects($this->once()) |
||||
->method('getHeader') |
||||
->with('Content-Type') |
||||
->will($this->returnValue('text/plain')); |
||||
|
||||
$this->server->expects($this->never()) |
||||
->method('invokeMethod') |
||||
->with($request, $response); |
||||
|
||||
$this->assertNull($this->plugin->handlePost($request, $response)); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue