DAV now returns file name with Content-Disposition header
Fixes issue where Chrome would append ".txt" to XML files when downloaded in the web UI
This commit is contained in:
parent
4c26abe228
commit
1399e87d57
|
@ -42,6 +42,7 @@ use \Sabre\HTTP\RequestInterface;
|
||||||
use \Sabre\HTTP\ResponseInterface;
|
use \Sabre\HTTP\ResponseInterface;
|
||||||
use OCP\Files\StorageNotAvailableException;
|
use OCP\Files\StorageNotAvailableException;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
|
use OCP\IRequest;
|
||||||
|
|
||||||
class FilesPlugin extends ServerPlugin {
|
class FilesPlugin extends ServerPlugin {
|
||||||
|
|
||||||
|
@ -95,20 +96,29 @@ class FilesPlugin extends ServerPlugin {
|
||||||
*/
|
*/
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var IRequest
|
||||||
|
*/
|
||||||
|
private $request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Tree $tree
|
* @param Tree $tree
|
||||||
* @param View $view
|
* @param View $view
|
||||||
|
* @param IConfig $config
|
||||||
|
* @param IRequest $request
|
||||||
* @param bool $isPublic
|
* @param bool $isPublic
|
||||||
* @param bool $downloadAttachment
|
* @param bool $downloadAttachment
|
||||||
*/
|
*/
|
||||||
public function __construct(Tree $tree,
|
public function __construct(Tree $tree,
|
||||||
View $view,
|
View $view,
|
||||||
IConfig $config,
|
IConfig $config,
|
||||||
|
IRequest $request,
|
||||||
$isPublic = false,
|
$isPublic = false,
|
||||||
$downloadAttachment = true) {
|
$downloadAttachment = true) {
|
||||||
$this->tree = $tree;
|
$this->tree = $tree;
|
||||||
$this->fileView = $view;
|
$this->fileView = $view;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
|
$this->request = $request;
|
||||||
$this->isPublic = $isPublic;
|
$this->isPublic = $isPublic;
|
||||||
$this->downloadAttachment = $downloadAttachment;
|
$this->downloadAttachment = $downloadAttachment;
|
||||||
}
|
}
|
||||||
|
@ -225,7 +235,18 @@ class FilesPlugin extends ServerPlugin {
|
||||||
|
|
||||||
// adds a 'Content-Disposition: attachment' header
|
// adds a 'Content-Disposition: attachment' header
|
||||||
if ($this->downloadAttachment) {
|
if ($this->downloadAttachment) {
|
||||||
$response->addHeader('Content-Disposition', 'attachment');
|
$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,
|
||||||
|
])) {
|
||||||
|
$response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"');
|
||||||
|
} else {
|
||||||
|
$response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename)
|
||||||
|
. '; filename="' . rawurlencode($filename) . '"');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
|
if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
|
||||||
|
|
|
@ -144,6 +144,7 @@ class ServerFactory {
|
||||||
$objectTree,
|
$objectTree,
|
||||||
$view,
|
$view,
|
||||||
$this->config,
|
$this->config,
|
||||||
|
$this->request,
|
||||||
false,
|
false,
|
||||||
!$this->config->getSystemValue('debug', false)
|
!$this->config->getSystemValue('debug', false)
|
||||||
)
|
)
|
||||||
|
|
|
@ -141,6 +141,7 @@ class Server {
|
||||||
$this->server->tree,
|
$this->server->tree,
|
||||||
$view,
|
$view,
|
||||||
\OC::$server->getConfig(),
|
\OC::$server->getConfig(),
|
||||||
|
$this->request,
|
||||||
false,
|
false,
|
||||||
!\OC::$server->getConfig()->getSystemValue('debug', false)
|
!\OC::$server->getConfig()->getSystemValue('debug', false)
|
||||||
)
|
)
|
||||||
|
|
|
@ -73,6 +73,11 @@ class FilesPluginTest extends TestCase {
|
||||||
*/
|
*/
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \OCP\IRequest | \PHPUnit_Framework_MockObject_MockObject
|
||||||
|
*/
|
||||||
|
private $request;
|
||||||
|
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
$this->server = $this->getMockBuilder('\Sabre\DAV\Server')
|
$this->server = $this->getMockBuilder('\Sabre\DAV\Server')
|
||||||
|
@ -88,11 +93,13 @@ class FilesPluginTest extends TestCase {
|
||||||
$this->config->expects($this->any())->method('getSystemValue')
|
$this->config->expects($this->any())->method('getSystemValue')
|
||||||
->with($this->equalTo('data-fingerprint'), $this->equalTo(''))
|
->with($this->equalTo('data-fingerprint'), $this->equalTo(''))
|
||||||
->willReturn('my_fingerprint');
|
->willReturn('my_fingerprint');
|
||||||
|
$this->request = $this->getMock('\OCP\IRequest');
|
||||||
|
|
||||||
$this->plugin = new FilesPlugin(
|
$this->plugin = new FilesPlugin(
|
||||||
$this->tree,
|
$this->tree,
|
||||||
$this->view,
|
$this->view,
|
||||||
$this->config
|
$this->config,
|
||||||
|
$this->request
|
||||||
);
|
);
|
||||||
$this->plugin->initialize($this->server);
|
$this->plugin->initialize($this->server);
|
||||||
}
|
}
|
||||||
|
@ -268,6 +275,7 @@ class FilesPluginTest extends TestCase {
|
||||||
$this->tree,
|
$this->tree,
|
||||||
$this->view,
|
$this->view,
|
||||||
$this->config,
|
$this->config,
|
||||||
|
$this->getMock('\OCP\IRequest'),
|
||||||
true);
|
true);
|
||||||
$this->plugin->initialize($this->server);
|
$this->plugin->initialize($this->server);
|
||||||
|
|
||||||
|
@ -484,4 +492,60 @@ class FilesPluginTest extends TestCase {
|
||||||
|
|
||||||
$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
|
$this->plugin->checkMove('FolderA/test.txt', 'test.txt');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function downloadHeadersProvider() {
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
false,
|
||||||
|
'attachment; filename*=UTF-8\'\'somefile.xml; filename="somefile.xml"'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
true,
|
||||||
|
'attachment; filename="somefile.xml"'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider downloadHeadersProvider
|
||||||
|
*/
|
||||||
|
public function testDownloadHeaders($isClumsyAgent, $contentDispositionHeader) {
|
||||||
|
$request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$request
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getPath')
|
||||||
|
->will($this->returnValue('test/somefile.xml'));
|
||||||
|
|
||||||
|
$node = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\File')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
$node
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getName')
|
||||||
|
->will($this->returnValue('somefile.xml'));
|
||||||
|
|
||||||
|
$this->tree
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getNodeForPath')
|
||||||
|
->with('test/somefile.xml')
|
||||||
|
->will($this->returnValue($node));
|
||||||
|
|
||||||
|
$this->request
|
||||||
|
->expects($this->once())
|
||||||
|
->method('isUserAgent')
|
||||||
|
->will($this->returnValue($isClumsyAgent));
|
||||||
|
|
||||||
|
$response
|
||||||
|
->expects($this->once())
|
||||||
|
->method('addHeader')
|
||||||
|
->with('Content-Disposition', $contentDispositionHeader);
|
||||||
|
|
||||||
|
$this->plugin->httpGet($request, $response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -343,7 +343,8 @@ class FilesReportPluginTest extends \Test\TestCase {
|
||||||
new \OCA\DAV\Connector\Sabre\FilesPlugin(
|
new \OCA\DAV\Connector\Sabre\FilesPlugin(
|
||||||
$this->tree,
|
$this->tree,
|
||||||
$this->view,
|
$this->view,
|
||||||
$config
|
$config,
|
||||||
|
$this->getMock('\OCP\IRequest')
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$this->plugin->initialize($this->server);
|
$this->plugin->initialize($this->server);
|
||||||
|
|
|
@ -82,7 +82,7 @@ Feature: webdav-related
|
||||||
And As an "admin"
|
And As an "admin"
|
||||||
When Downloading file "/welcome.txt"
|
When Downloading file "/welcome.txt"
|
||||||
Then The following headers should be set
|
Then The following headers should be set
|
||||||
|Content-Disposition|attachment|
|
|Content-Disposition|attachment; filename*=UTF-8''welcome.txt; filename="welcome.txt"|
|
||||||
|Content-Security-Policy|default-src 'none';|
|
|Content-Security-Policy|default-src 'none';|
|
||||||
|X-Content-Type-Options |nosniff|
|
|X-Content-Type-Options |nosniff|
|
||||||
|X-Download-Options|noopen|
|
|X-Download-Options|noopen|
|
||||||
|
@ -97,7 +97,7 @@ Feature: webdav-related
|
||||||
And As an "admin"
|
And As an "admin"
|
||||||
When Downloading file "/welcome.txt"
|
When Downloading file "/welcome.txt"
|
||||||
Then The following headers should be set
|
Then The following headers should be set
|
||||||
|Content-Disposition|attachment|
|
|Content-Disposition|attachment; filename*=UTF-8''welcome.txt; filename="welcome.txt"|
|
||||||
|Content-Security-Policy|default-src 'none';|
|
|Content-Security-Policy|default-src 'none';|
|
||||||
|X-Content-Type-Options |nosniff|
|
|X-Content-Type-Options |nosniff|
|
||||||
|X-Download-Options|noopen|
|
|X-Download-Options|noopen|
|
||||||
|
|
Loading…
Reference in New Issue