Goodbye Iframe transport !

Not needed any more in IE >= 11

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
This commit is contained in:
Vincent Petry 2016-07-15 13:19:16 +02:00 committed by Roeland Jago Douma
parent 25d9dce067
commit c68e273664
No known key found for this signature in database
GPG Key ID: 1E152838F164D13B
3 changed files with 0 additions and 353 deletions

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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));
}
}