diff --git a/bin/console b/bin/console
index b47b654126..8a73b4088c 100755
--- a/bin/console
+++ b/bin/console
@@ -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) {
diff --git a/lib/Alchemy/Phrasea/Command/Setup/XSendFileMappingApacheDumper.php b/lib/Alchemy/Phrasea/Command/Setup/XSendFileMappingApacheDumper.php
deleted file mode 100644
index 96496136c2..0000000000
--- a/lib/Alchemy/Phrasea/Command/Setup/XSendFileMappingApacheDumper.php
+++ /dev/null
@@ -1,50 +0,0 @@
-setDescription('Dump XSendFile mapping for Apache web server');
- }
-
- /**
- * {@inheritdoc}
- */
- protected function doDump(InputInterface $input, OutputInterface $output)
- {
- $mapper = $this->container['phraseanet.xsendfile-mapping'];
-
- $output->writeln('Apache XSendfile configuration');
- $output->writeln('');
- $output->writeln('');
- $output->writeln(' ');
- $output->writeln(' XSendFile on');
- foreach ($this->container['phraseanet.xsendfile-mapping']->getMapping() as $entry) {
- $output->writeln(' XSendFilePath ' . $mapper->sanitizePath($entry['directory']));
- }
- $output->writeln(' ');
- $output->writeln('');
- $output->writeln('');
-
- return 0;
- }
-}
diff --git a/lib/Alchemy/Phrasea/Command/Setup/AbstractXSendFileMappingDumper.php b/lib/Alchemy/Phrasea/Command/Setup/XSendFileMappingDumper.php
similarity index 55%
rename from lib/Alchemy/Phrasea/Command/Setup/AbstractXSendFileMappingDumper.php
rename to lib/Alchemy/Phrasea/Command/Setup/XSendFileMappingDumper.php
index ef44829d4f..aa61c2a83e 100644
--- a/lib/Alchemy/Phrasea/Command/Setup/AbstractXSendFileMappingDumper.php
+++ b/lib/Alchemy/Phrasea/Command/Setup/XSendFileMappingDumper.php
@@ -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 enabled');
- } else {
+
+ if (!$this->container['phraseanet.xsendfile-factory']->isXSendFileModeEnabled()) {
$output->writeln('XSendFile support is disabled');
- $configuration++;
+
+ return 1;
}
- if (2 < count($this->container['phraseanet.xsendfile-mapping']->getMapping())) {
+
+ $output->writeln('XSendFile support is enabled');
+
+ try {
+ $configuration = $this->container['phraseanet.xsendfile-factory']->getMode(true)->getVirtualHostConfiguration();
$output->writeln('XSendFile configuration seems OK');
- } else {
+ $output->writeln($configuration);
+
+ return 0;
+ } catch (RuntimeException $e) {
$output->writeln('XSendFile configuration seems invalid');
- $configuration++;
+
+ return 1;
}
+
$output->writeln('');
- return $configuration + $this->doDump($input, $output);
+ return 0;
}
-
- abstract protected function doDump(InputInterface $input, OutputInterface $output);
}
diff --git a/lib/Alchemy/Phrasea/Command/Setup/XSendFileMappingNginxDumper.php b/lib/Alchemy/Phrasea/Command/Setup/XSendFileMappingNginxDumper.php
deleted file mode 100644
index 1b949c5be0..0000000000
--- a/lib/Alchemy/Phrasea/Command/Setup/XSendFileMappingNginxDumper.php
+++ /dev/null
@@ -1,49 +0,0 @@
-setDescription('Dump xsendfile mapping for Nginx web server');
- }
-
- /**
- * {@inheritdoc}
- */
- protected function doDump(InputInterface $input, OutputInterface $output)
- {
- $mapper = $this->container['phraseanet.xsendfile-mapping'];
- $output->writeln('Nginx XSendfile configuration');
- $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;
- }
-}
diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/XSendFileSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/XSendFileSubscriber.php
index 8b9381f82a..d6aff6bc14 100644
--- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/XSendFileSubscriber.php
+++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/XSendFileSubscriber.php
@@ -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());
}
}
}
diff --git a/lib/Alchemy/Phrasea/Core/Provider/FileServeServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/FileServeServiceProvider.php
index 0c288b197f..3125e12ff2 100644
--- a/lib/Alchemy/Phrasea/Core/Provider/FileServeServiceProvider.php
+++ b/lib/Alchemy/Phrasea/Core/Provider/FileServeServiceProvider.php
@@ -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) {
diff --git a/lib/Alchemy/Phrasea/Http/DeliverDataInterface.php b/lib/Alchemy/Phrasea/Http/DeliverDataInterface.php
index 11576cc9c3..a1233950fe 100644
--- a/lib/Alchemy/Phrasea/Http/DeliverDataInterface.php
+++ b/lib/Alchemy/Phrasea/Http/DeliverDataInterface.php
@@ -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);
diff --git a/lib/Alchemy/Phrasea/Http/ServeFileResponseFactory.php b/lib/Alchemy/Phrasea/Http/ServeFileResponseFactory.php
index 94aaf5f90b..fd709afbdd 100644
--- a/lib/Alchemy/Phrasea/Http/ServeFileResponseFactory.php
+++ b/lib/Alchemy/Phrasea/Http/ServeFileResponseFactory.php
@@ -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);
diff --git a/lib/Alchemy/Phrasea/Http/XSendFile/AbstractXSendFileMode.php b/lib/Alchemy/Phrasea/Http/XSendFile/AbstractXSendFileMode.php
new file mode 100644
index 0000000000..cfc09ffc92
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Http/XSendFile/AbstractXSendFileMode.php
@@ -0,0 +1,68 @@
+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, '/'));
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Http/XSendFile/ApacheMode.php b/lib/Alchemy/Phrasea/Http/XSendFile/ApacheMode.php
new file mode 100644
index 0000000000..1102205288
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Http/XSendFile/ApacheMode.php
@@ -0,0 +1,74 @@
+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 .= "\n";
+ $output .= " \n";
+ $output .= " XSendFile on\n";
+ foreach ($this->mapping as $entry) {
+ $output .= ' XSendFilePath ' . $entry['directory'] . "\n";
+ }
+ $output .= " \n";
+ $output .= "\n";
+
+ return $output;
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Http/XSendFile/ModeInterface.php b/lib/Alchemy/Phrasea/Http/XSendFile/ModeInterface.php
new file mode 100644
index 0000000000..0ba0d2638d
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Http/XSendFile/ModeInterface.php
@@ -0,0 +1,31 @@
+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;
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Http/XSendFile/NullMode.php b/lib/Alchemy/Phrasea/Http/XSendFile/NullMode.php
new file mode 100644
index 0000000000..b8e3bea3dc
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Http/XSendFile/NullMode.php
@@ -0,0 +1,32 @@
+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;
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Http/XsendfileMapping.php b/lib/Alchemy/Phrasea/Http/XsendfileMapping.php
deleted file mode 100644
index 094ee5d21f..0000000000
--- a/lib/Alchemy/Phrasea/Http/XsendfileMapping.php
+++ /dev/null
@@ -1,85 +0,0 @@
-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"');
- }
- }
- }
-}
diff --git a/lib/classes/patch/3813.php b/lib/classes/patch/3813.php
index f458cf2200..f39f3628e2 100644
--- a/lib/classes/patch/3813.php
+++ b/lib/classes/patch/3813.php
@@ -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(
diff --git a/lib/conf.d/configuration.yml b/lib/conf.d/configuration.yml
index fa1365a9c7..faebf9dd06 100644
--- a/lib/conf.d/configuration.yml
+++ b/lib/conf.d/configuration.yml
@@ -135,6 +135,7 @@ registration-fields:
required: true
xsendfile:
enabled: false
+ type: nginx|apache2
mapping:
-
directory: ''
diff --git a/templates/web/admin/editusers.html.twig b/templates/web/admin/editusers.html.twig
index 769cd92607..27fc2ec927 100644
--- a/templates/web/admin/editusers.html.twig
+++ b/templates/web/admin/editusers.html.twig
@@ -145,7 +145,7 @@
{% endfor %}
-
+
@@ -565,7 +565,7 @@
{% endif %}
diff --git a/templates/web/admin/search-engine/sphinx-search.html.twig b/templates/web/admin/search-engine/sphinx-search.html.twig
index 324313e4b8..f6b290c7b0 100644
--- a/templates/web/admin/search-engine/sphinx-search.html.twig
+++ b/templates/web/admin/search-engine/sphinx-search.html.twig
@@ -2,14 +2,14 @@
\ No newline at end of file
diff --git a/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration-setup.yml b/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration-setup.yml
index c449b45cfd..55b4553acd 100644
--- a/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration-setup.yml
+++ b/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration-setup.yml
@@ -116,6 +116,7 @@ registration-fields:
required: true
xsendfile:
enabled: false
+ type: ''
mapping:
-
directory: ''
diff --git a/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml b/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml
index c449b45cfd..55b4553acd 100644
--- a/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml
+++ b/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml
@@ -116,6 +116,7 @@ registration-fields:
required: true
xsendfile:
enabled: false
+ type: ''
mapping:
-
directory: ''
diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/Fixtures/configuration-debugger.yml b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/Fixtures/configuration-debugger.yml
index d29c6648a9..85d4fe3e4a 100644
--- a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/Fixtures/configuration-debugger.yml
+++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/Fixtures/configuration-debugger.yml
@@ -141,6 +141,7 @@ registration-fields:
required: true
xsendfile:
enabled: false
+ type: ''
mapping:
-
directory: ''
diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/Fixtures/configuration-maintenance.yml b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/Fixtures/configuration-maintenance.yml
index 4a9cd110d4..42f4b2f2ba 100644
--- a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/Fixtures/configuration-maintenance.yml
+++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/Fixtures/configuration-maintenance.yml
@@ -141,6 +141,7 @@ registration-fields:
required: true
xsendfile:
enabled: false
+ type: ''
mapping:
-
directory: ''
diff --git a/tests/Alchemy/Tests/Phrasea/Core/Provider/FileServeServiceProviderTest.php b/tests/Alchemy/Tests/Phrasea/Core/Provider/FileServeServiceProviderTest.php
index 331603bbce..53d71d627e 100644
--- a/tests/Alchemy/Tests/Phrasea/Core/Provider/FileServeServiceProviderTest.php
+++ b/tests/Alchemy/Tests/Phrasea/Core/Provider/FileServeServiceProviderTest.php
@@ -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);
}
}
diff --git a/tests/Alchemy/Tests/Phrasea/Core/Provider/fixtures/config-mapping.yml b/tests/Alchemy/Tests/Phrasea/Core/Provider/fixtures/config-mapping.yml
index a671526952..707126a9a9 100644
--- a/tests/Alchemy/Tests/Phrasea/Core/Provider/fixtures/config-mapping.yml
+++ b/tests/Alchemy/Tests/Phrasea/Core/Provider/fixtures/config-mapping.yml
@@ -1,5 +1,6 @@
xsendfile:
- enabled: false
+ enabled: true
+ type: 'nginx'
mapping:
-
directory: '/tmp'
diff --git a/tests/Alchemy/Tests/Phrasea/Http/ServeFileResponseFactoryTest.php b/tests/Alchemy/Tests/Phrasea/Http/ServeFileResponseFactoryTest.php
index ef11c49119..a355a61e66 100644
--- a/tests/Alchemy/Tests/Phrasea/Http/ServeFileResponseFactoryTest.php
+++ b/tests/Alchemy/Tests/Phrasea/Http/ServeFileResponseFactoryTest.php
@@ -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
diff --git a/tests/Alchemy/Tests/Phrasea/Http/XSendFile/ApacheModeTest.php b/tests/Alchemy/Tests/Phrasea/Http/XSendFile/ApacheModeTest.php
new file mode 100644
index 0000000000..7941d732a6
--- /dev/null
+++ b/tests/Alchemy/Tests/Phrasea/Http/XSendFile/ApacheModeTest.php
@@ -0,0 +1,47 @@
+ __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')),
+ );
+ }
+}
diff --git a/tests/Alchemy/Tests/Phrasea/Http/XSendFile/NginxModeTest.php b/tests/Alchemy/Tests/Phrasea/Http/XSendFile/NginxModeTest.php
new file mode 100644
index 0000000000..38685e359f
--- /dev/null
+++ b/tests/Alchemy/Tests/Phrasea/Http/XSendFile/NginxModeTest.php
@@ -0,0 +1,82 @@
+ __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')),
+ );
+ }
+}
diff --git a/tests/Alchemy/Tests/Phrasea/Http/XSendFile/NullModeTest.php b/tests/Alchemy/Tests/Phrasea/Http/XSendFile/NullModeTest.php
new file mode 100644
index 0000000000..fee4729fc2
--- /dev/null
+++ b/tests/Alchemy/Tests/Phrasea/Http/XSendFile/NullModeTest.php
@@ -0,0 +1,25 @@
+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);
+ }
+}
diff --git a/tests/Alchemy/Tests/Phrasea/Http/XSendFile/XSendFileFactoryTest.php b/tests/Alchemy/Tests/Phrasea/Http/XSendFile/XSendFileFactoryTest.php
new file mode 100644
index 0000000000..39beb2f9f4
--- /dev/null
+++ b/tests/Alchemy/Tests/Phrasea/Http/XSendFile/XSendFileFactoryTest.php
@@ -0,0 +1,132 @@
+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/',
+ ));
+ }
+}
diff --git a/tests/Alchemy/Tests/Phrasea/Http/XsendfileMappingTest.php b/tests/Alchemy/Tests/Phrasea/Http/XsendfileMappingTest.php
deleted file mode 100644
index fabc4fcbf8..0000000000
--- a/tests/Alchemy/Tests/Phrasea/Http/XsendfileMappingTest.php
+++ /dev/null
@@ -1,103 +0,0 @@
- $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__))),
- );
- }
-}