Additional work to fix zip downloading directories with URL special characters

This commit is contained in:
Chris Kankiewicz
2020-04-06 11:40:45 -07:00
parent aef71d0168
commit 7ed461e2d4
4 changed files with 87 additions and 36 deletions

View File

@@ -3,6 +3,7 @@
namespace App\ViewFunctions;
use App\Support\Str;
use RuntimeException;
class Url extends ViewFunction
{
@@ -23,21 +24,33 @@ class Url extends ViewFunction
}
/**
* Return the URL for a given path.
* Return the URL for a given path and action.
*
* @param string $path
* @param string $path
* @param string|null $action
*
* @return string
*/
public function __invoke(string $path = '/'): string
public function __invoke(string $path = '/', string $action = null): string
{
$path = preg_replace('/^.?(\/|\\\)+/', '', $path);
if (is_file($path)) {
return $this->escape($path);
}
switch ($action) {
case null:
return $this->escape($path);
return empty($path) ? '' : sprintf('?dir=%s', $this->escape($path));
case 'dir':
return empty($path) ? '' : sprintf('?dir=%s', $this->escape($path));
case 'info':
return empty($path) ? '?info=.' : sprintf('?info=%s', $this->escape($path));
case 'zip':
return empty($path) ? '?zip=.' : sprintf('?zip=%s', $this->escape($path));
default:
throw new RuntimeException(sprintf('Invalid action "%s"', $action));
}
}
/**

View File

@@ -1,5 +1,5 @@
<a
href="{{ parentDir ? parent_dir(path) : url(file.getPathname) }}"
href="{{ parentDir ? parent_dir(path) : url(file.getPathname, 'dir') }}"
class="flex flex-col items-center rounded-lg font-mono group hover:bg-gray-200 hover:shadow"
>
<div class="flex justify-between items-center p-4 w-full">

View File

@@ -14,7 +14,7 @@
<div class="flex justify-end items-center">
{% if path and config('zip_downloads', true) %}
<a href="?zip={{ path }}" title="{{ translate('download') }}" class="inline-block text-white mx-2 p-1 hover:text-gray-400">
<a href="{{ url(path, 'zip') }}" title="{{ translate('download') }}" class="inline-block text-white mx-2 p-1 hover:text-gray-400">
<i class="fas fa-download fa-lg"></i>
</a>
{% endif %}

View File

@@ -3,53 +3,91 @@
namespace Tests\ViewFunctions;
use App\ViewFunctions\Url;
use RuntimeException;
use Tests\TestCase;
class UrlTest extends TestCase
{
public function test_it_can_return_a_url_for_a_directory(): void
public function test_it_can_return_a_url(): void
{
$url = new Url;
$this->assertEquals('', $url('/'));
$this->assertEquals('', $url('./'));
$this->assertEquals('?dir=some/path', $url('some/path'));
$this->assertEquals('?dir=some/path', $url('./some/path'));
$this->assertEquals('?dir=some/path', $url('./some/path'));
$this->assertEquals('?dir=some/file.test', $url('some/file.test'));
$this->assertEquals('?dir=some/file.test', $url('./some/file.test'));
$this->assertEquals('some/path', $url('some/path'));
$this->assertEquals('some/path', $url('./some/path'));
$this->assertEquals('some/path', $url('./some/path'));
$this->assertEquals('some/file.test', $url('some/file.test'));
$this->assertEquals('some/file.test', $url('./some/file.test'));
}
public function test_it_can_return_a_url_for_a_directory_using_back_slashes(): void
public function test_it_can_return_a_directory_url(): void
{
$url = new Url;
$this->assertEquals('', $url('/', 'dir'));
$this->assertEquals('', $url('./', 'dir'));
$this->assertEquals('?dir=some/path', $url('some/path', 'dir'));
$this->assertEquals('?dir=some/path', $url('./some/path', 'dir'));
$this->assertEquals('?dir=some/path', $url('./some/path', 'dir'));
$this->assertEquals('?dir=some/file.test', $url('some/file.test', 'dir'));
$this->assertEquals('?dir=some/file.test', $url('./some/file.test', 'dir'));
}
public function test_it_can_return_a_file_info_url(): void
{
$url = new Url;
$this->assertEquals('?info=.', $url('/', 'info'));
$this->assertEquals('?info=.', $url('./', 'info'));
$this->assertEquals('?info=some/path', $url('some/path', 'info'));
$this->assertEquals('?info=some/path', $url('./some/path', 'info'));
$this->assertEquals('?info=some/path', $url('./some/path', 'info'));
$this->assertEquals('?info=some/file.test', $url('some/file.test', 'info'));
$this->assertEquals('?info=some/file.test', $url('./some/file.test', 'info'));
}
public function test_it_can_return_a_zip_url(): void
{
$url = new Url;
$this->assertEquals('?zip=.', $url('/', 'zip'));
$this->assertEquals('?zip=.', $url('./', 'zip'));
$this->assertEquals('?zip=some/path', $url('some/path', 'zip'));
$this->assertEquals('?zip=some/path', $url('./some/path', 'zip'));
$this->assertEquals('?zip=some/path', $url('./some/path', 'zip'));
}
public function test_it_can_return_a_url_with_back_slashes(): void
{
$url = new Url('\\');
$this->assertEquals('', $url('\\'));
$this->assertEquals('', $url('.\\'));
$this->assertEquals('?dir=some\path', $url('some\path'));
$this->assertEquals('?dir=some\path', $url('.\some\path'));
$this->assertEquals('?dir=some\file.test', $url('some\file.test'));
$this->assertEquals('?dir=some\file.test', $url('.\some\file.test'));
$this->assertEquals('some\path', $url('some\path'));
$this->assertEquals('some\path', $url('.\some\path'));
$this->assertEquals('some\file.test', $url('some\file.test'));
$this->assertEquals('some\file.test', $url('.\some\file.test'));
$this->assertEquals('?dir=some\path', $url('some\path', 'dir'));
$this->assertEquals('?info=some\path', $url('some\path', 'info'));
$this->assertEquals('?zip=some\path', $url('some\path', 'zip'));
}
public function test_it_can_return_a_url_for_a_file(): void
{
chdir($this->filePath('.'));
$url = new Url;
$this->assertEquals('README.md', $url('README.md'));
$this->assertEquals('README.md', $url('./README.md'));
$this->assertEquals('subdir/alpha.scss', $url('subdir/alpha.scss'));
$this->assertEquals('subdir/alpha.scss', $url('./subdir/alpha.scss'));
}
public function test_it_url_encodes_directory_names(): void
public function test_it_throws_an_exception_for_an_invalid_action(): void
{
$url = new Url;
$this->assertEquals('?dir=foo/bar%2Bbaz', $url('foo/bar+baz'));
$this->assertEquals('?dir=foo/bar%23baz', $url('foo/bar#baz'));
$this->assertEquals('?dir=foo/bar%26baz', $url('foo/bar&baz'));
$this->expectException(RuntimeException::class);
$url('some/path', 'INVALID_ACTION');
}
public function test_segments_are_url_encoded(): void
{
$url = new Url;
$this->assertEquals('foo/bar%2Bbaz', $url('foo/bar+baz'));
$this->assertEquals('foo/bar%23baz', $url('foo/bar#baz'));
$this->assertEquals('foo/bar%26baz', $url('foo/bar&baz'));
}
}