Goodbye Iframe transport !
Not needed any more in IE >= 11 Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
This commit is contained in:
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -114,7 +114,6 @@ class ServerFactory {
|
|||
// FIXME: The following line is a workaround for legacy components relying on being able to send a GET to /
|
||||
$server->addPlugin(new \OCA\DAV\Connector\Sabre\DummyGetResponsePlugin());
|
||||
$server->addPlugin(new \OCA\DAV\Connector\Sabre\ExceptionLoggerPlugin('webdav', $this->logger));
|
||||
$server->addPlugin(new \OCA\DAV\Connector\Sabre\IFrameTransportPlugin());
|
||||
$server->addPlugin(new \OCA\DAV\Connector\Sabre\LockPlugin());
|
||||
// Some WebDAV clients do require Class 2 WebDAV support (locking), since
|
||||
// we do not provide locking we emulate it using a fake locking plugin.
|
||||
|
|
|
@ -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