mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-23 18:03:17 +00:00
Enhance XSendFileMapping to handle apache
Update xsendfile
This commit is contained in:
@@ -28,8 +28,7 @@ use Alchemy\Phrasea\CLI;
|
||||
use Alchemy\Phrasea\Command\Plugin\AddPlugin;
|
||||
use Alchemy\Phrasea\Command\Plugin\RemovePlugin;
|
||||
use Alchemy\Phrasea\Command\CheckConfig;
|
||||
use Alchemy\Phrasea\Command\Setup\XSendFileMappingNginxDumper;
|
||||
use Alchemy\Phrasea\Command\Setup\XSendFileMappingApacheDumper;
|
||||
use Alchemy\Phrasea\Command\Setup\XSendFileMappingDumper;
|
||||
|
||||
require_once __DIR__ . '/../lib/autoload.php';
|
||||
|
||||
@@ -98,8 +97,7 @@ try {
|
||||
$app->command(new AddPlugin());
|
||||
$app->command(new RemovePlugin());
|
||||
$app->command(new Configuration());
|
||||
$app->command(new XSendFileMappingNginxDumper());
|
||||
$app->command(new XSendFileMappingApacheDumper());
|
||||
$app->command(new XSendFileMappingDumper());
|
||||
|
||||
$result_code = is_int($app->run()) ? : 1;
|
||||
} catch (\Exception $e) {
|
||||
|
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Command\Setup;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* This command dumps XsendFile Apache condifuration
|
||||
*/
|
||||
class XSendFileMappingApacheDumper extends AbstractXSendFileMappingDumper
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('xsendfile:dump-apache');
|
||||
|
||||
$this->setDescription('Dump XSendFile mapping for Apache web server');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doDump(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$mapper = $this->container['phraseanet.xsendfile-mapping'];
|
||||
|
||||
$output->writeln('<info>Apache XSendfile configuration</info>');
|
||||
$output->writeln('');
|
||||
$output->writeln('<IfModule mod_xsendfile.c>');
|
||||
$output->writeln(' <Files *>');
|
||||
$output->writeln(' XSendFile on');
|
||||
foreach ($this->container['phraseanet.xsendfile-mapping']->getMapping() as $entry) {
|
||||
$output->writeln(' XSendFilePath ' . $mapper->sanitizePath($entry['directory']));
|
||||
}
|
||||
$output->writeln(' </Files>');
|
||||
$output->writeln('</IfModule>');
|
||||
$output->writeln('');
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -12,35 +12,45 @@
|
||||
namespace Alchemy\Phrasea\Command\Setup;
|
||||
|
||||
use Alchemy\Phrasea\Command\Command;
|
||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
abstract class AbstractXSendFileMappingDumper extends Command
|
||||
class XSendFileMappingDumper extends Command
|
||||
{
|
||||
public function __construct($name = null) {
|
||||
parent::__construct('xsendfile:configuration-dumper');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doExecute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$configuration = 0;
|
||||
|
||||
$output->writeln('');
|
||||
if ($this->container['phraseanet.file-serve']->isXSendFileEnable()) {
|
||||
$output->writeln('XSendFile support is <info>enabled</info>');
|
||||
} else {
|
||||
|
||||
if (!$this->container['phraseanet.xsendfile-factory']->isXSendFileModeEnabled()) {
|
||||
$output->writeln('XSendFile support is <error>disabled</error>');
|
||||
$configuration++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (2 < count($this->container['phraseanet.xsendfile-mapping']->getMapping())) {
|
||||
|
||||
$output->writeln('XSendFile support is <info>enabled</info>');
|
||||
|
||||
try {
|
||||
$configuration = $this->container['phraseanet.xsendfile-factory']->getMode(true)->getVirtualHostConfiguration();
|
||||
$output->writeln('XSendFile configuration seems <info>OK</info>');
|
||||
} else {
|
||||
$output->writeln($configuration);
|
||||
|
||||
return 0;
|
||||
} catch (RuntimeException $e) {
|
||||
$output->writeln('XSendFile configuration seems <error>invalid</error>');
|
||||
$configuration++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
|
||||
return $configuration + $this->doDump($input, $output);
|
||||
return 0;
|
||||
}
|
||||
|
||||
abstract protected function doDump(InputInterface $input, OutputInterface $output);
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Command\Setup;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* This command dumps XSendFile Nginx configuration
|
||||
*/
|
||||
class XSendFileMappingNginxDumper extends AbstractXSendFileMappingDumper
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('xsendfile:dump-nginx');
|
||||
|
||||
$this->setDescription('Dump xsendfile mapping for Nginx web server');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doDump(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$mapper = $this->container['phraseanet.xsendfile-mapping'];
|
||||
$output->writeln('<info>Nginx XSendfile configuration</info>');
|
||||
$output->writeln('');
|
||||
foreach ($this->container['phraseanet.xsendfile-mapping']->getMapping() as $entry) {
|
||||
$output->writeln(' location ' . $mapper->sanitizeMountPoint($entry['mount-point']) . ' {');
|
||||
$output->writeln(' internal;');
|
||||
$output->writeln(' add_header Etag $upstream_http_etag;');
|
||||
$output->writeln(' add_header Link $upstream_http_link;');
|
||||
$output->writeln(' alias ' . $mapper->sanitizePath($entry['directory']) . ';');
|
||||
$output->writeln(' }');
|
||||
$output->writeln('');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -15,6 +15,7 @@ use Silex\Application;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
class XSendFileSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
@@ -34,10 +35,9 @@ class XSendFileSubscriber implements EventSubscriberInterface
|
||||
|
||||
public function applyHeaders(GetResponseEvent $event)
|
||||
{
|
||||
if ($this->app['phraseanet.configuration']['xsendfile']['enabled']) {
|
||||
$request = $event->getRequest();
|
||||
$request->headers->set('X-Sendfile-Type', 'X-Accel-Redirect');
|
||||
$request->headers->set('X-Accel-Mapping', (string) $this->app['phraseanet.xsendfile-mapping']);
|
||||
if ($this->app['phraseanet.xsendfile-factory']->isXSendFileModeEnabled()) {
|
||||
BinaryFileResponse::trustXSendfileTypeHeader();
|
||||
$this->app['phraseanet.xsendfile-factory']->getMode()->setHeaders($event->getRequest());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -11,11 +11,11 @@
|
||||
|
||||
namespace Alchemy\Phrasea\Core\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Core\Event\Subscriber\XSendFileSubscriber;
|
||||
use Alchemy\Phrasea\Http\ServeFileResponseFactory;
|
||||
use Alchemy\Phrasea\Http\XSendFile\XSendFileFactory;
|
||||
use Silex\Application;
|
||||
use Silex\ServiceProviderInterface;
|
||||
use Alchemy\Phrasea\Http\ServeFileResponseFactory;
|
||||
use Alchemy\Phrasea\Http\XsendfileMapping;
|
||||
use Alchemy\Phrasea\Core\Event\Subscriber\XSendFileSubscriber;
|
||||
|
||||
class FileServeServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
@@ -24,27 +24,8 @@ class FileServeServiceProvider implements ServiceProviderInterface
|
||||
*/
|
||||
public function register(Application $app)
|
||||
{
|
||||
$app['xsendfile.mapping'] = $app->share(function(Application $app) {
|
||||
$mapping = array();
|
||||
|
||||
if (isset($app['phraseanet.configuration']['xsendfile']['mapping'])) {
|
||||
$mapping = $app['phraseanet.configuration']['xsendfile']['mapping'];
|
||||
}
|
||||
|
||||
$mapping[] = array(
|
||||
'directory' => $app['root.path'] . '/tmp/download/',
|
||||
'mount-point' => '/download/',
|
||||
);
|
||||
$mapping[] = array(
|
||||
'directory' => $app['root.path'] . '/tmp/lazaret/',
|
||||
'mount-point' => '/lazaret/',
|
||||
);
|
||||
|
||||
return $mapping;
|
||||
});
|
||||
|
||||
$app['phraseanet.xsendfile-mapping'] = $app->share(function($app) {
|
||||
return new XsendfileMapping($app['xsendfile.mapping']);
|
||||
$app['phraseanet.xsendfile-factory'] = $app->share(function($app) {
|
||||
return XSendFileFactory::create($app);
|
||||
});
|
||||
|
||||
$app['phraseanet.file-serve'] = $app->share(function (Application $app) {
|
||||
|
@@ -24,7 +24,7 @@ interface DeliverDataInterface
|
||||
* @param string $file
|
||||
* @param string $filename
|
||||
* @param string $disposition
|
||||
* @param string|null $mimetype
|
||||
* @param string|null $mimeType
|
||||
* @param integer $cacheDuration
|
||||
*/
|
||||
public function deliverFile($file, $filename = null, $disposition = self::DISPOSITION_INLINE, $mimeType = null, $cacheDuration = 3600);
|
||||
|
@@ -18,17 +18,11 @@ use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
class ServeFileResponseFactory implements DeliverDataInterface
|
||||
{
|
||||
private $xSendFileEnable = false;
|
||||
private $unicode;
|
||||
|
||||
public function __construct($enableXSendFile, \unicode $unicode)
|
||||
public function __construct(\unicode $unicode)
|
||||
{
|
||||
$this->xSendFileEnable = (Boolean) $enableXSendFile;
|
||||
$this->unicode = $unicode;
|
||||
|
||||
if ($this->xSendFileEnable) {
|
||||
BinaryFileResponse::trustXSendfileTypeHeader();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,7 +32,6 @@ class ServeFileResponseFactory implements DeliverDataInterface
|
||||
public static function create(Application $app)
|
||||
{
|
||||
return new self(
|
||||
$app['phraseanet.configuration']['xsendfile']['enabled'],
|
||||
$app['unicode']
|
||||
);
|
||||
}
|
||||
@@ -77,11 +70,6 @@ class ServeFileResponseFactory implements DeliverDataInterface
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function isXSendFileEnable()
|
||||
{
|
||||
return $this->xSendFileEnable;
|
||||
}
|
||||
|
||||
private function sanitizeFilename($filename)
|
||||
{
|
||||
return str_replace(array('/', '\\'), '', $filename);
|
||||
|
68
lib/Alchemy/Phrasea/Http/XSendFile/AbstractXSendFileMode.php
Normal file
68
lib/Alchemy/Phrasea/Http/XSendFile/AbstractXSendFileMode.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Http\XSendFile;
|
||||
|
||||
use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
||||
|
||||
abstract class AbstractXSendFileMode
|
||||
{
|
||||
protected $mapping = array();
|
||||
|
||||
/**
|
||||
* @params array $mapping
|
||||
*
|
||||
* @throws InvalidArgumentException if mapping is invalid;
|
||||
*/
|
||||
public function __construct(array $mapping)
|
||||
{
|
||||
$this->setMapping($mapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getMapping()
|
||||
{
|
||||
return $this->mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @params array $mapping
|
||||
*
|
||||
* @throws InvalidArgumentException if mapping is invalid;
|
||||
*/
|
||||
abstract public function setMapping(array $mapping);
|
||||
|
||||
/**
|
||||
* Sanitizes path directory.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function sanitizePath($path)
|
||||
{
|
||||
return sprintf('/%s', trim($path, '/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes a mount point.
|
||||
*
|
||||
* @param string $mountPoint
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function sanitizeMountPoint($mountPoint)
|
||||
{
|
||||
return sprintf('/%s', trim($mountPoint, '/'));
|
||||
}
|
||||
}
|
74
lib/Alchemy/Phrasea/Http/XSendFile/ApacheMode.php
Normal file
74
lib/Alchemy/Phrasea/Http/XSendFile/ApacheMode.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Http\XSendFile;
|
||||
|
||||
use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class ApacheMode extends AbstractXSendFileMode implements ModeInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setHeaders(Request $request)
|
||||
{
|
||||
$request->headers->add(array(
|
||||
'X-Sendfile-Type' => 'X-SendFile',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMapping(array $mapping)
|
||||
{
|
||||
$final = array();
|
||||
|
||||
foreach ($mapping as $entry) {
|
||||
if (!is_array($entry)) {
|
||||
throw new InvalidArgumentException('XSendFile mapping entry must be an array');
|
||||
}
|
||||
|
||||
if (!isset($entry['directory'])) {
|
||||
throw new InvalidArgumentException('XSendFile mapping entry must contain at least a "directory" key');
|
||||
}
|
||||
|
||||
if (false === is_dir(trim($entry['directory']))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$final[] = array(
|
||||
'directory' => $this->sanitizePath(realpath($entry['directory']))
|
||||
);
|
||||
}
|
||||
|
||||
$this->mapping = $final;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVirtualHostConfiguration()
|
||||
{
|
||||
$output = "\n";
|
||||
$output .= "<IfModule mod_xsendfile.c>\n";
|
||||
$output .= " <Files *>\n";
|
||||
$output .= " XSendFile on\n";
|
||||
foreach ($this->mapping as $entry) {
|
||||
$output .= ' XSendFilePath ' . $entry['directory'] . "\n";
|
||||
}
|
||||
$output .= " </Files>\n";
|
||||
$output .= "</IfModule>\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
31
lib/Alchemy/Phrasea/Http/XSendFile/ModeInterface.php
Normal file
31
lib/Alchemy/Phrasea/Http/XSendFile/ModeInterface.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Http\XSendFile;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
interface ModeInterface
|
||||
{
|
||||
/**
|
||||
* Sets XSendFile headers.
|
||||
*
|
||||
* @params Request $request
|
||||
*/
|
||||
public function setHeaders(Request $request);
|
||||
|
||||
/**
|
||||
* Prints virtualhost configuration for current XSendFile mode.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getVirtualHostConfiguration();
|
||||
}
|
88
lib/Alchemy/Phrasea/Http/XSendFile/NginxMode.php
Normal file
88
lib/Alchemy/Phrasea/Http/XSendFile/NginxMode.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Http\XSendFile;
|
||||
|
||||
use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class NginxMode extends AbstractXSendFileMode implements ModeInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setHeaders(Request $request)
|
||||
{
|
||||
$xAccelMapping = array();
|
||||
|
||||
foreach ($this->mapping as $entry) {
|
||||
$xAccelMapping[] = sprintf('%s=%s', $entry['mount-point'], $entry['directory']);
|
||||
}
|
||||
|
||||
if (count($xAccelMapping) > 0 ) {
|
||||
$request->headers->add(array(
|
||||
'X-Sendfile-Type' => 'X-Accel-Redirect',
|
||||
'X-Accel-Mapping' => implode(',', $xAccelMapping),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMapping(array $mapping)
|
||||
{
|
||||
$final = array();
|
||||
|
||||
foreach ($mapping as $entry) {
|
||||
if (!is_array($entry)) {
|
||||
throw new InvalidArgumentException('XSendFile mapping entry must be an array');
|
||||
}
|
||||
|
||||
if (!isset($entry['directory'])) {
|
||||
throw new InvalidArgumentException('XSendFile mapping entry must contain at least a "directory" key');
|
||||
}
|
||||
|
||||
if (!isset($entry['mount-point'])) {
|
||||
throw new InvalidArgumentException('XSendFile mapping entry must contain at least a "mount-point" key');
|
||||
}
|
||||
|
||||
if (false === is_dir(trim($entry['directory'])) || '' === trim($entry['mount-point'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$final[] = array(
|
||||
'directory' => $this->sanitizePath(realpath($entry['directory'])),
|
||||
'mount-point' => $this->sanitizeMountPoint($entry['mount-point'])
|
||||
);
|
||||
}
|
||||
|
||||
$this->mapping = $final;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVirtualHostConfiguration()
|
||||
{
|
||||
$output = "\n";
|
||||
foreach ($this->mapping as $entry) {
|
||||
$output .= " location " . $entry['mount-point']. " {\n";
|
||||
$output .= " internal;\n";
|
||||
$output .= " add_header Etag \$upstream_http_etag;\n";
|
||||
$output .= " add_header Link \$upstream_http_link;\n";
|
||||
$output .= " alias " . $entry['directory'] . ";\n";
|
||||
$output .= " }\n";
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
32
lib/Alchemy/Phrasea/Http/XSendFile/NullMode.php
Normal file
32
lib/Alchemy/Phrasea/Http/XSendFile/NullMode.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Http\XSendFile;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class NullMode implements ModeInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setHeaders(Request $request)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getVirtualHostConfiguration()
|
||||
{
|
||||
return "\n";
|
||||
}
|
||||
}
|
124
lib/Alchemy/Phrasea/Http/XSendFile/XSendFileFactory.php
Normal file
124
lib/Alchemy/Phrasea/Http/XSendFile/XSendFileFactory.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Http\XSendFile;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class XSendFileFactory
|
||||
{
|
||||
private $enabled;
|
||||
private $logger;
|
||||
private $type;
|
||||
private $mapping;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param LoggerInterface $logger
|
||||
* @param boolean $enabled
|
||||
* @param string $type
|
||||
* @param array $mapping
|
||||
*/
|
||||
public function __construct(LoggerInterface $logger, $enabled, $type, array $mapping)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->enabled = (Boolean) $enabled;
|
||||
$this->type = strtolower($type);
|
||||
$this->mapping = $mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of XSendFile Factory according to the application
|
||||
* configuration.
|
||||
*
|
||||
* @param Application $app
|
||||
* @return XSendFileFactory
|
||||
*/
|
||||
public static function create(Application $app)
|
||||
{
|
||||
$conf = $app['phraseanet.configuration']['xsendfile'];
|
||||
|
||||
$mapping = array();
|
||||
|
||||
if (isset($conf['mapping'])) {
|
||||
$mapping = $conf['mapping'];
|
||||
}
|
||||
|
||||
$mapping[] = array(
|
||||
'directory' => $app['root.path'] . '/tmp/download/',
|
||||
'mount-point' => '/download/',
|
||||
);
|
||||
|
||||
$mapping[] = array(
|
||||
'directory' => $app['root.path'] . '/tmp/lazaret/',
|
||||
'mount-point' => '/lazaret/',
|
||||
);
|
||||
|
||||
return new self($app['monolog'], $conf['enabled'], $conf['type'], $mapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of XSendFileModeInterface.
|
||||
*
|
||||
* @return null|ModeInterface
|
||||
*
|
||||
* @throws InvalidArgumentException if mode type is unknown
|
||||
*/
|
||||
public function getMode($throwException = false)
|
||||
{
|
||||
if (false === $this->enabled) {
|
||||
return new NullMode();
|
||||
}
|
||||
|
||||
switch ($this->type) {
|
||||
case 'nginx':
|
||||
case 'sendfile':
|
||||
case 'xaccel':
|
||||
case 'xaccelredirect':
|
||||
case 'x-accel':
|
||||
case 'x-accel-redirect':
|
||||
if (2 >= count($this->mapping)) {
|
||||
$this->logger->error('Invalid xsendfile mapping configuration.');
|
||||
if ($throwException) {
|
||||
throw new RuntimeException('Mapping is not set up.');
|
||||
}
|
||||
}
|
||||
|
||||
return new NginxMode($this->mapping);
|
||||
case 'apache':
|
||||
case 'apache2':
|
||||
case 'xsendfile':
|
||||
return new ApacheMode($this->mapping);
|
||||
default:
|
||||
$this->logger->error('Invalid xsendfile type configuration.');
|
||||
if ($throwException) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Invalid xsendfile type value "%s"',
|
||||
$this->type
|
||||
));
|
||||
}
|
||||
|
||||
return new NullMode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isXSendFileModeEnabled()
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
}
|
@@ -1,85 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2013 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Http;
|
||||
|
||||
use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
||||
|
||||
class XsendfileMapping
|
||||
{
|
||||
private $mapping;
|
||||
|
||||
/**
|
||||
* @param array $mapping
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct(array $mapping)
|
||||
{
|
||||
$this->validate($mapping);
|
||||
|
||||
$final = array();
|
||||
|
||||
foreach($mapping as $entry) {
|
||||
if (!is_dir(trim($entry['directory'])) || '' === trim($entry['mount-point'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$entry = array(
|
||||
'directory' => $this->sanitizePath(realpath($entry['directory'])),
|
||||
'mount-point' => $this->sanitizeMountPoint($entry['mount-point']),
|
||||
);
|
||||
|
||||
$final[] = $entry;
|
||||
}
|
||||
|
||||
$this->mapping = $final;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$final = array();
|
||||
|
||||
foreach($this->mapping as $entry) {
|
||||
$final[] = sprintf('%s=%s', $entry['mount-point'], $entry['directory']);
|
||||
}
|
||||
|
||||
return implode(',', $final);
|
||||
}
|
||||
|
||||
public function getMapping()
|
||||
{
|
||||
return $this->mapping;
|
||||
}
|
||||
|
||||
public function sanitizePath($path)
|
||||
{
|
||||
return sprintf('/%s', trim($path, '/'));
|
||||
}
|
||||
|
||||
public function sanitizeMountPoint($mountPoint)
|
||||
{
|
||||
return sprintf('/%s', trim($mountPoint, '/'));
|
||||
}
|
||||
|
||||
private function validate(array $mapping)
|
||||
{
|
||||
foreach ($mapping as $entry) {
|
||||
if (!is_array($entry)) {
|
||||
throw new InvalidArgumentException('XSendFile mapping entry must be an array');
|
||||
}
|
||||
|
||||
if (!isset($entry['directory']) || !isset($entry['mount-point'])) {
|
||||
throw new InvalidArgumentException('XSendFile mapping entry must contain at least two keys "directory" and "mount-point"');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -56,6 +56,7 @@ class patch_3813 implements patchInterface
|
||||
->getConfig();
|
||||
|
||||
$config['xsendfile']['enabled'] = (Boolean) $app['phraseanet.registry']->get('GV_modxsendfile', false);
|
||||
$config['xsendfile']['type'] = $config['xsendfile']['enabled'] ? 'nginx' : '';
|
||||
|
||||
if (null !== $xsendfilePath && null !== $xsendfileMountPoint) {
|
||||
$config['xsendfile']['mapping'] = array(array(
|
||||
|
@@ -135,6 +135,7 @@ registration-fields:
|
||||
required: true
|
||||
xsendfile:
|
||||
enabled: false
|
||||
type: nginx|apache2
|
||||
mapping:
|
||||
-
|
||||
directory: ''
|
||||
|
@@ -145,7 +145,7 @@
|
||||
<option value="{{ template.get_id() }}">{{ template.get_display_name() }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type='button' id='reset_rights'>{% trans 'Delete all users rights' %}</button>
|
||||
<button class="btn" type='button' id='reset_rights'>{% trans 'Delete all users rights' %}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -565,7 +565,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="PNB10" style="top:auto;height:20px;">
|
||||
<button class="users_rights_valid">{% trans 'boutton::valider' %}</button>
|
||||
<button class="users_rights_valid btn">{% trans 'boutton::valider' %}</button>
|
||||
<a href="{{ path('admin_users_search') }}" class="users_rights_cancel">{% trans 'boutton::retour' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -20,7 +20,7 @@
|
||||
<input type="checkbox" name="date_fields[]" value="{{ field }}" {% if field in configuration['date_fields'] %}checked="checked"{% endif %} > {{ field }}
|
||||
{% endfor %}
|
||||
|
||||
<button type="submit">{% trans 'boutton::valider' %}</button>
|
||||
<button type="submit" class="btn btn-warning" >{% trans 'boutton::valider' %}</button>
|
||||
</form>
|
||||
|
||||
<textarea style="font-family: monospace;width:90%;height:70%">{{ configfile }}</textarea>
|
@@ -116,6 +116,7 @@ registration-fields:
|
||||
required: true
|
||||
xsendfile:
|
||||
enabled: false
|
||||
type: ''
|
||||
mapping:
|
||||
-
|
||||
directory: ''
|
||||
|
@@ -116,6 +116,7 @@ registration-fields:
|
||||
required: true
|
||||
xsendfile:
|
||||
enabled: false
|
||||
type: ''
|
||||
mapping:
|
||||
-
|
||||
directory: ''
|
||||
|
@@ -141,6 +141,7 @@ registration-fields:
|
||||
required: true
|
||||
xsendfile:
|
||||
enabled: false
|
||||
type: ''
|
||||
mapping:
|
||||
-
|
||||
directory: ''
|
||||
|
@@ -141,6 +141,7 @@ registration-fields:
|
||||
required: true
|
||||
xsendfile:
|
||||
enabled: false
|
||||
type: ''
|
||||
mapping:
|
||||
-
|
||||
directory: ''
|
||||
|
@@ -21,32 +21,24 @@ class FileServeServiceProviderTest extends ServiceProviderTestCase
|
||||
),
|
||||
array(
|
||||
'Alchemy\Phrasea\Core\Provider\FileServeServiceProvider',
|
||||
'phraseanet.xsendfile-mapping',
|
||||
'Alchemy\Phrasea\Http\XsendfileMapping'
|
||||
'phraseanet.xsendfile-factory',
|
||||
'Alchemy\Phrasea\Http\XSendFile\XSendFileFactory'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function testMapping()
|
||||
{
|
||||
$app = new Application();
|
||||
|
||||
$app = clone self::$DI['app'];
|
||||
$app['root.path'] = __DIR__ . '/../../../../../..';
|
||||
$app->register(new ConfigurationServiceProvider());
|
||||
$app->register(new FileServeServiceProvider());
|
||||
$app['phraseanet.configuration.config-path'] = __DIR__ . '/fixtures/config-mapping.yml';
|
||||
$app['phraseanet.configuration.config-compiled-path'] = __DIR__ . '/fixtures/config-mapping.php';
|
||||
$this->assertEquals(array(array(
|
||||
'directory' => '/tmp',
|
||||
'mount-point' => 'mount',
|
||||
),array(
|
||||
'directory' => __DIR__ . '/../../../../../../tmp/download/',
|
||||
'mount-point' => '/download/',
|
||||
),array(
|
||||
'directory' => __DIR__ . '/../../../../../../tmp/lazaret/',
|
||||
'mount-point' => '/lazaret/',
|
||||
)), $app['xsendfile.mapping']);
|
||||
$this->assertInstanceOf('Alchemy\Phrasea\Http\XSendFile\NginxMode', $app['phraseanet.xsendfile-factory']->getMode());
|
||||
$this->assertEquals(3, count($app['phraseanet.xsendfile-factory']->getMode()->getMapping()));
|
||||
|
||||
unlink($app['phraseanet.configuration.config-compiled-path']);
|
||||
unset($app);
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
xsendfile:
|
||||
enabled: false
|
||||
enabled: true
|
||||
type: 'nginx'
|
||||
mapping:
|
||||
-
|
||||
directory: '/tmp'
|
||||
|
@@ -3,16 +3,23 @@
|
||||
namespace Alchemy\Tests\Phrasea\Http;
|
||||
|
||||
use Alchemy\Phrasea\Http\ServeFileResponseFactory;
|
||||
use Alchemy\Phrasea\Http\XsendfileMapping;
|
||||
use Alchemy\Phrasea\Http\XSendFile\NginxMode;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class ServeFileResponseFactoryTest extends \PhraseanetWebTestCaseAbstract
|
||||
{
|
||||
protected $factory;
|
||||
|
||||
public function testDeliverFileFactoryCreation()
|
||||
{
|
||||
$factory = ServeFileResponseFactory::create(self::$DI['app']);
|
||||
$this->assertInstanceOf('Alchemy\Phrasea\Http\ServeFileResponseFactory', $factory);
|
||||
}
|
||||
|
||||
public function testDeliverFile()
|
||||
{
|
||||
$this->factory = new ServeFileResponseFactory(false, new \unicode());
|
||||
$this->factory = new ServeFileResponseFactory(new \unicode());
|
||||
|
||||
$response = $this->factory->deliverFile(__DIR__ . '/../../../../files/cestlafete.jpg');
|
||||
|
||||
@@ -25,7 +32,7 @@ class ServeFileResponseFactoryTest extends \PhraseanetWebTestCaseAbstract
|
||||
|
||||
public function testDeliverFileWithDuration()
|
||||
{
|
||||
$this->factory = new ServeFileResponseFactory(false, new \unicode());
|
||||
$this->factory = new ServeFileResponseFactory(new \unicode());
|
||||
|
||||
$response = $this->factory->deliverFile(__DIR__ . '/../../../../files/cestlafete.jpg', 'hello', 'attachment', 'application/json', 23456);
|
||||
|
||||
@@ -35,7 +42,7 @@ class ServeFileResponseFactoryTest extends \PhraseanetWebTestCaseAbstract
|
||||
|
||||
public function testDeliverFileWithFilename()
|
||||
{
|
||||
$this->factory = new ServeFileResponseFactory(false, new \unicode());
|
||||
$this->factory = new ServeFileResponseFactory(new \unicode());
|
||||
|
||||
$response = $this->factory->deliverFile(__DIR__ . '/../../../../files/cestlafete.jpg', 'toto.jpg');
|
||||
|
||||
@@ -45,7 +52,7 @@ class ServeFileResponseFactoryTest extends \PhraseanetWebTestCaseAbstract
|
||||
|
||||
public function testDeliverFileWithFilenameAndDisposition()
|
||||
{
|
||||
$this->factory = new ServeFileResponseFactory(false, new \unicode());
|
||||
$this->factory = new ServeFileResponseFactory(new \unicode());
|
||||
|
||||
$response = $this->factory->deliverFile(__DIR__ . '/../../../../files/cestlafete.jpg', 'toto.jpg', 'attachment');
|
||||
|
||||
@@ -55,15 +62,18 @@ class ServeFileResponseFactoryTest extends \PhraseanetWebTestCaseAbstract
|
||||
|
||||
public function testDeliverFileWithFilenameAndDispositionAndXSendFile()
|
||||
{
|
||||
$this->factory = new ServeFileResponseFactory(true, new \unicode());
|
||||
$request = Request::create('/');
|
||||
$request->headers->set('X-SendFile-Type', 'X-Accel-Redirect');
|
||||
$request->headers->set('X-Accel-Mapping', (string) new XsendfileMapping(array(
|
||||
BinaryFileResponse::trustXSendfileTypeHeader();
|
||||
$this->factory = new ServeFileResponseFactory(new \unicode());
|
||||
$mode = new NginxMode(
|
||||
array(
|
||||
'directory' => __DIR__ . '/../../../../files/',
|
||||
'mount-point' => '/protected/'
|
||||
array(
|
||||
'directory' => __DIR__ . '/../../../../files/',
|
||||
'mount-point' => '/protected/'
|
||||
)
|
||||
)
|
||||
)));
|
||||
);
|
||||
$request = Request::create('/');
|
||||
$mode->setHeaders($request);
|
||||
|
||||
$response = $this->factory->deliverFile(__DIR__ . '/../../../../files/cestlafete.jpg', 'toto.jpg', 'attachment');
|
||||
$response->prepare($request);
|
||||
@@ -75,15 +85,18 @@ class ServeFileResponseFactoryTest extends \PhraseanetWebTestCaseAbstract
|
||||
|
||||
public function testDeliverFileWithFilenameAndDispositionAndXSendFileAndNoTrailingSlashes()
|
||||
{
|
||||
$this->factory = new ServeFileResponseFactory(true, new \unicode());
|
||||
$request = Request::create('/');
|
||||
$request->headers->set('X-SendFile-Type', 'X-Accel-Redirect');
|
||||
$request->headers->set('X-Accel-Mapping', (string) new XsendfileMapping(array(
|
||||
BinaryFileResponse::trustXSendfileTypeHeader();
|
||||
$this->factory = new ServeFileResponseFactory(new \unicode());
|
||||
$mode = new NginxMode(
|
||||
array(
|
||||
'directory' => __DIR__ . '/../../../../files/',
|
||||
'mount-point' => '/protected/'
|
||||
array(
|
||||
'directory' => __DIR__ . '/../../../../files',
|
||||
'mount-point' => '/protected'
|
||||
)
|
||||
)
|
||||
)));
|
||||
);
|
||||
$request = Request::create('/');
|
||||
$mode->setHeaders($request);
|
||||
|
||||
$response = $this->factory->deliverFile(__DIR__ . '/../../../../files/cestlafete.jpg', 'toto.jpg', 'attachment');
|
||||
$response->prepare($request);
|
||||
@@ -98,22 +111,26 @@ class ServeFileResponseFactoryTest extends \PhraseanetWebTestCaseAbstract
|
||||
*/
|
||||
public function testDeliverUnexistingFile()
|
||||
{
|
||||
$this->factory = new ServeFileResponseFactory(true, new \unicode());
|
||||
BinaryFileResponse::trustXSendfileTypeHeader();
|
||||
$this->factory = new ServeFileResponseFactory(new \unicode());
|
||||
|
||||
$this->factory->deliverFile(__DIR__ . '/../../../../files/does_not_exists.jpg', 'toto.jpg', 'attachment');
|
||||
}
|
||||
|
||||
public function testDeliverFileWithFilenameAndDispositionAndXSendFileButFileNotInXAccelMapping()
|
||||
{
|
||||
$this->factory = new ServeFileResponseFactory(true, new \unicode());
|
||||
$request = Request::create('/');
|
||||
$request->headers->set('X-SendFile-Type', 'X-Accel-Redirect');
|
||||
$request->headers->set('X-Accel-Mapping', (string) new XsendfileMapping(array(
|
||||
BinaryFileResponse::trustXSendfileTypeHeader();
|
||||
$this->factory = new ServeFileResponseFactory(new \unicode());
|
||||
$mode = new NginxMode(
|
||||
array(
|
||||
'directory' => __DIR__ . '/../../../../files/',
|
||||
'mount-point' => '/protected/'
|
||||
array(
|
||||
'directory' => __DIR__ . '/../../../../files/',
|
||||
'mount-point' => '/protected/'
|
||||
)
|
||||
)
|
||||
)));
|
||||
);
|
||||
$request = Request::create('/');
|
||||
$mode->setHeaders($request);
|
||||
|
||||
$file = __DIR__ . '/../../../../classes/PhraseanetPHPUnitAbstract.php';
|
||||
|
||||
@@ -127,7 +144,7 @@ class ServeFileResponseFactoryTest extends \PhraseanetWebTestCaseAbstract
|
||||
|
||||
public function testDeliverDatas()
|
||||
{
|
||||
$this->factory = new ServeFileResponseFactory(false, new \unicode());
|
||||
$this->factory = new ServeFileResponseFactory(new \unicode());
|
||||
|
||||
$data = 'Sex,Name,Birthday
|
||||
M,Alphonse,1932
|
||||
|
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Http\XSendFile;
|
||||
|
||||
use Alchemy\Phrasea\Http\XSendFile\ApacheMode;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class ApacheModeTest extends \PhraseanetPHPUnitAbstract
|
||||
{
|
||||
public function testGetVirtualHost()
|
||||
{
|
||||
$mode = new ApacheMode(array(array('directory' => __DIR__ )));
|
||||
$conf = $mode->getVirtualHostConfiguration();
|
||||
$this->assertRegExp('#'.__DIR__ . '#', $conf);
|
||||
}
|
||||
|
||||
public function testSetValidHeaders()
|
||||
{
|
||||
$request = Request::create('/');
|
||||
$mode = new ApacheMode(array(array('directory' => __DIR__ )));
|
||||
$mode->setHeaders($request);
|
||||
$this->assertArrayHasKey('x-sendfile-type', $request->headers->all());
|
||||
}
|
||||
|
||||
public function testUnextingDirectoryMapping()
|
||||
{
|
||||
$mode = new ApacheMode(array(array('directory' => __DIR__ . '/Unknown/Dir')));
|
||||
$this->assertEquals(array(), $mode->getMapping());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideMappings
|
||||
* @expectedException Alchemy\Phrasea\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testInvalidMapping($mapping)
|
||||
{
|
||||
new ApacheMode($mapping);
|
||||
}
|
||||
|
||||
public function provideMappings()
|
||||
{
|
||||
return array(
|
||||
array(array(array('wrong-key' => __DIR__))),
|
||||
array(array('not-an-array')),
|
||||
);
|
||||
}
|
||||
}
|
82
tests/Alchemy/Tests/Phrasea/Http/XSendFile/NginxModeTest.php
Normal file
82
tests/Alchemy/Tests/Phrasea/Http/XSendFile/NginxModeTest.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Http\XSendFile;
|
||||
|
||||
use Alchemy\Phrasea\Http\XSendFile\NginxMode;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class XSendFileModeNginxTest extends \PhraseanetPHPUnitAbstract
|
||||
{
|
||||
public function testGetVirtualHost()
|
||||
{
|
||||
$mode = new NginxMode(array(array(
|
||||
'directory' => __DIR__, 'mount-point' => '/download')));
|
||||
$conf = $mode->getVirtualHostConfiguration();
|
||||
$this->assertRegExp('#'.__DIR__ . '#', $conf);
|
||||
}
|
||||
|
||||
public function testSetValidHeaders()
|
||||
{
|
||||
$request = Request::create('/');
|
||||
$mode = new NginxMode(array(array('directory' => __DIR__, 'mount-point' => '/download')));
|
||||
$mode->setHeaders($request);
|
||||
$this->assertArrayHasKey('x-sendfile-type', $request->headers->all());
|
||||
$this->assertArrayHasKey('x-accel-mapping', $request->headers->all());
|
||||
}
|
||||
|
||||
public function testSetValidMultiHeaders()
|
||||
{
|
||||
$protected = __DIR__ . '/../../../../../files/';
|
||||
$upload = __DIR__ . '/../../../../../';
|
||||
|
||||
$request = Request::create('/');
|
||||
$mode = new NginxMode(array(
|
||||
array(
|
||||
'directory' => $protected,
|
||||
'mount-point' => '/protected/'
|
||||
),
|
||||
array(
|
||||
'directory' => $upload,
|
||||
'mount-point' => '/uploads/'
|
||||
),
|
||||
));
|
||||
$mode->setHeaders($request);
|
||||
$this->assertArrayHasKey('x-sendfile-type', $request->headers->all());
|
||||
$this->assertArrayHasKey('x-accel-mapping', $request->headers->all());
|
||||
$this->assertEquals('/protected='.realpath($protected).',/uploads='.realpath($upload), $request->headers->get('X-Accel-Mapping'));
|
||||
}
|
||||
|
||||
public function testSetInvalidHeaders()
|
||||
{
|
||||
$request = Request::create('/');
|
||||
$mode = new NginxMode(array(array('directory' => __DIR__ . '/Unknown/Dir', 'mount-point' => '/download')));
|
||||
$mode->setHeaders($request);
|
||||
$this->assertArrayNotHasKey('x-sendfile-type', $request->headers->all());
|
||||
$this->assertArrayNotHasKey('x-accel-mapping', $request->headers->all());
|
||||
}
|
||||
|
||||
public function testUnextingDirectoryMapping()
|
||||
{
|
||||
$mode = new NginxMode(array(array('directory' => __DIR__ . '/Unknown/Dir', 'mount-point' => '/download')));
|
||||
$this->assertEquals(array(), $mode->getMapping());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideMappings
|
||||
* @expectedException Alchemy\Phrasea\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testInvalidMapping($mapping)
|
||||
{
|
||||
new NginxMode($mapping);
|
||||
}
|
||||
|
||||
public function provideMappings()
|
||||
{
|
||||
return array(
|
||||
array(array(array('Directory' => __DIR__))),
|
||||
array(array(array('wrong-key' => __DIR__, 'mount-point' => '/'))),
|
||||
array(array(array('directory' => __DIR__, 'wrong-key' => '/'))),
|
||||
array(array('not-an-array')),
|
||||
);
|
||||
}
|
||||
}
|
25
tests/Alchemy/Tests/Phrasea/Http/XSendFile/NullModeTest.php
Normal file
25
tests/Alchemy/Tests/Phrasea/Http/XSendFile/NullModeTest.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Http\XSendFile;
|
||||
|
||||
use Alchemy\Phrasea\Http\XSendFile\NullMode;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class NullModeTest extends \PhraseanetPHPUnitAbstract
|
||||
{
|
||||
public function testGetVirtualHost()
|
||||
{
|
||||
$mode = new NullMode();
|
||||
$conf = $mode->getVirtualHostConfiguration();
|
||||
$this->assertSame("\n", $conf);
|
||||
}
|
||||
|
||||
public function testSetHeaders()
|
||||
{
|
||||
$mode = new NullMode();
|
||||
$request = Request::create('/');
|
||||
$before = (string) $request->headers;
|
||||
$mode->setHeaders($request);
|
||||
$this->assertSame($before, (string) $request->headers);
|
||||
}
|
||||
}
|
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Http\XSendFile;
|
||||
|
||||
use Alchemy\Phrasea\Http\XSendFile\XSendFileFactory;
|
||||
|
||||
class XSendFileFactoryTest extends \PhraseanetPHPUnitAbstract
|
||||
{
|
||||
public function testFactoryCreation()
|
||||
{
|
||||
$factory = XSendFileFactory::create(self::$DI['app']);
|
||||
$this->assertInstanceOf('Alchemy\Phrasea\Http\XSendFile\XSendFileFactory', $factory);
|
||||
}
|
||||
|
||||
public function testFactoryWithXsendFileEnable()
|
||||
{
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
|
||||
$factory = new XSendFileFactory($logger, true, 'nginx', $this->getNginxMapping());
|
||||
$this->assertInstanceOf('Alchemy\Phrasea\Http\XSendFile\ModeInterface', $factory->getMode());
|
||||
}
|
||||
|
||||
public function testFactoryWithXsendFileDisabled()
|
||||
{
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
|
||||
$factory = new XSendFileFactory($logger, false, 'nginx',$this->getNginxMapping());
|
||||
$this->assertInstanceOf('Alchemy\Phrasea\Http\XSendFile\NullMode', $factory->getMode());
|
||||
$this->assertFalse($factory->isXSendFileModeEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Alchemy\Phrasea\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testFactoryWithWrongTypeThrowsAnExceptionIfRequired()
|
||||
{
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
|
||||
$factory = new XSendFileFactory($logger, true, 'wrong-type', $this->getNginxMapping());
|
||||
$factory->getMode(true);
|
||||
}
|
||||
|
||||
public function testFactoryWithWrongTypeDoesNotThrowsAnExceptio()
|
||||
{
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
|
||||
$logger->expects($this->once())
|
||||
->method('error')
|
||||
->with($this->isType('string'));
|
||||
|
||||
$factory = new XSendFileFactory($logger, true, 'wrong-type', $this->getNginxMapping());
|
||||
$this->assertInstanceOf('Alchemy\Phrasea\Http\XSendFile\NullMode', $factory->getMode(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideTypes
|
||||
*/
|
||||
public function testFactoryType($type, $mapping, $classmode)
|
||||
{
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
|
||||
$factory = new XSendFileFactory($logger, true, $type, $mapping);
|
||||
$this->assertInstanceOf($classmode, $factory->getMode());
|
||||
}
|
||||
|
||||
public function provideTypes()
|
||||
{
|
||||
return array(
|
||||
array('apache', $this->getApacheMapping(), 'Alchemy\Phrasea\Http\XSendFile\ApacheMode'),
|
||||
array('apache2', $this->getApacheMapping(), 'Alchemy\Phrasea\Http\XSendFile\ApacheMode'),
|
||||
array('xsendfile', $this->getApacheMapping(), 'Alchemy\Phrasea\Http\XSendFile\ApacheMode'),
|
||||
array('nginx',$this->getNginxMapping(), 'Alchemy\Phrasea\Http\XSendFile\NginxMode'),
|
||||
array('sendfile',$this->getNginxMapping(), 'Alchemy\Phrasea\Http\XSendFile\NginxMode'),
|
||||
array('xaccel',$this->getNginxMapping(), 'Alchemy\Phrasea\Http\XSendFile\NginxMode'),
|
||||
array('xaccelredirect',$this->getNginxMapping(), 'Alchemy\Phrasea\Http\XSendFile\NginxMode'),
|
||||
array('x-accel',$this->getNginxMapping(), 'Alchemy\Phrasea\Http\XSendFile\NginxMode'),
|
||||
array('x-accel-redirect',$this->getNginxMapping(), 'Alchemy\Phrasea\Http\XSendFile\NginxMode'),
|
||||
);
|
||||
}
|
||||
|
||||
public function testInvalidMappingThrowsAnExceptionIfRequired()
|
||||
{
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
|
||||
$logger->expects($this->once())
|
||||
->method('error')
|
||||
->with($this->isType('string'));
|
||||
|
||||
$factory = new XSendFileFactory($logger, true, 'nginx', array());
|
||||
$this->setExpectedException('Alchemy\Phrasea\Exception\RuntimeException');
|
||||
$factory->getMode(true);
|
||||
}
|
||||
|
||||
public function testInvalidMappingDoesNotThrowsAnException()
|
||||
{
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
|
||||
$logger->expects($this->once())
|
||||
->method('error')
|
||||
->with($this->isType('string'));
|
||||
|
||||
$factory = new XSendFileFactory($logger, true, 'nginx', array());
|
||||
$this->assertInstanceOf('Alchemy\Phrasea\Http\XSendFile\NginxMode', $factory->getMode(false));
|
||||
}
|
||||
|
||||
public function testInvalidMappingDoesNotThrowsAnExceptionByDefault()
|
||||
{
|
||||
$logger = $this->getMock('Psr\Log\LoggerInterface');
|
||||
|
||||
$logger->expects($this->once())
|
||||
->method('error')
|
||||
->with($this->isType('string'));
|
||||
|
||||
$factory = new XSendFileFactory($logger, true, 'nginx', array());
|
||||
$this->assertInstanceOf('Alchemy\Phrasea\Http\XSendFile\NginxMode', $factory->getMode());
|
||||
}
|
||||
|
||||
private function getNginxMapping()
|
||||
{
|
||||
return array(array(
|
||||
'directory' => __DIR__ . '/../../../../files/',
|
||||
'mount-point' => '/protected/'
|
||||
));
|
||||
}
|
||||
|
||||
private function getApacheMapping()
|
||||
{
|
||||
return array(array(
|
||||
'directory' => __DIR__ . '/../../../../files/',
|
||||
));
|
||||
}
|
||||
}
|
@@ -1,103 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\Http;
|
||||
|
||||
use Alchemy\Phrasea\Http\XsendfileMapping;
|
||||
|
||||
class XsendfileMappingTest extends \PhraseanetWebTestCaseAbstract
|
||||
{
|
||||
public function testOneMapping()
|
||||
{
|
||||
$dir = __DIR__ . '/../../../../files/';
|
||||
$mapping = new XsendfileMapping(array(
|
||||
array(
|
||||
'directory' => $dir,
|
||||
'mount-point' => '/protected/'
|
||||
)
|
||||
));
|
||||
|
||||
$this->assertEquals('/protected='.realpath($dir), (string) $mapping);
|
||||
}
|
||||
|
||||
public function testMultiMapping()
|
||||
{
|
||||
$protected = __DIR__ . '/../../../../files/';
|
||||
$upload = __DIR__ . '/../../../../';
|
||||
$mapping = new XsendfileMapping(array(
|
||||
array(
|
||||
'directory' => $protected,
|
||||
'mount-point' => '/protected/'
|
||||
),
|
||||
array(
|
||||
'directory' => $upload,
|
||||
'mount-point' => '/uploads/'
|
||||
),
|
||||
));
|
||||
|
||||
$this->assertEquals('/protected='.realpath($protected).',/uploads='.realpath($upload), (string) $mapping);
|
||||
}
|
||||
|
||||
public function testMultiMappingWithANotExsistingDir()
|
||||
{
|
||||
$protected = __DIR__ . '/../../../../files/';
|
||||
$mapping = new XsendfileMapping(array(
|
||||
array(
|
||||
'directory' => $protected,
|
||||
'mount-point' => '/protected/'
|
||||
),
|
||||
array(
|
||||
'directory' => '/path/to/nonexistent/directory',
|
||||
'mount-point' => '/test/'
|
||||
),
|
||||
));
|
||||
|
||||
$this->assertEquals('/protected='.realpath($protected), (string) $mapping);
|
||||
}
|
||||
|
||||
public function testEmptyMapping()
|
||||
{
|
||||
$mapping = new XsendfileMapping(array());
|
||||
|
||||
$this->assertEquals('', (string) $mapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideVariousMappings
|
||||
*/
|
||||
public function testGetMapping($map, $expected)
|
||||
{
|
||||
$mapping = new XsendfileMapping($map);
|
||||
|
||||
$this->assertEquals($expected, $mapping->getMapping());
|
||||
}
|
||||
|
||||
public function provideVariousMappings()
|
||||
{
|
||||
return array(
|
||||
array(array(), array()),
|
||||
array(array(array('mount-point' => false, 'directory' => false)), array()),
|
||||
array(array(array('mount-point' => 'mount', 'directory' => false)), array()),
|
||||
array(array(array('mount-point' => false, 'directory' => __DIR__)), array()),
|
||||
array(array(array('mount-point' => 'mount', 'directory' => __DIR__)), array(array('mount-point' => '/mount', 'directory' => __DIR__))),
|
||||
array(array(array('mount-point' => '/mount/', 'directory' => __DIR__ . '/../..')), array(array('mount-point' => '/mount', 'directory' => realpath(__DIR__.'/../..')))),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideInvalidMappings
|
||||
* @expectedException Alchemy\Phrasea\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function testInvalidMapping($map)
|
||||
{
|
||||
new XsendfileMapping($map);
|
||||
}
|
||||
|
||||
public function provideInvalidMappings()
|
||||
{
|
||||
return array(
|
||||
array(array('mount-point' => '/mount', 'directory' => __DIR__)),
|
||||
array(array(array('mount-point' => '/mount'))),
|
||||
array(array(array('directory' => __DIR__))),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user