From d5b9ffe561b33bd8688fdd2c65cf6d83cb0d8c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20G=C3=B6r=C3=B6g?= Date: Thu, 26 Sep 2019 09:11:44 +0200 Subject: [PATCH 1/5] Make constructor more generic --- src/Driver/DropzoneUploadDriver.php | 48 +++------ src/Range/RequestBodyRange.php | 129 +++++++++++++++++++++++ src/Range/RequestRange.php | 76 -------------- tests/Range/RequestBodyRangeTest.php | 146 +++++++++++++++++++++++++++ 4 files changed, 290 insertions(+), 109 deletions(-) create mode 100644 src/Range/RequestBodyRange.php delete mode 100644 src/Range/RequestRange.php create mode 100644 tests/Range/RequestBodyRangeTest.php diff --git a/src/Driver/DropzoneUploadDriver.php b/src/Driver/DropzoneUploadDriver.php index afac9f5..64025e2 100644 --- a/src/Driver/DropzoneUploadDriver.php +++ b/src/Driver/DropzoneUploadDriver.php @@ -6,10 +6,11 @@ use Illuminate\Http\Request; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Storage; +use InvalidArgumentException; use LaraCrafts\ChunkUploader\Exception\UploadHttpException; use LaraCrafts\ChunkUploader\Helper\ChunkHelpers; use LaraCrafts\ChunkUploader\Identifier\Identifier; -use LaraCrafts\ChunkUploader\Range\RequestRange; +use LaraCrafts\ChunkUploader\Range\RequestBodyRange; use LaraCrafts\ChunkUploader\Response\PercentageJsonResponse; use LaraCrafts\ChunkUploader\StorageConfig; use Symfony\Component\HttpFoundation\Response; @@ -134,14 +135,17 @@ private function saveMonolith(UploadedFile $file, Identifier $identifier, Storag */ private function saveChunk(UploadedFile $file, Request $request, StorageConfig $config, Closure $fileUploaded = null): Response { - $numberOfChunks = $request->post('dztotalchunkcount'); - - $range = new RequestRange( - $request->post('dzchunkindex'), - $numberOfChunks, - $request->post('dzchunksize'), - $request->post('dztotalfilesize') - ); + try { + $range = new RequestBodyRange( + $request, + 'dzchunkindex', + 'dztotalchunkcount', + 'dzchunksize', + 'dztotalfilesize' + ); + } catch (InvalidArgumentException $e) { + throw new BadRequestHttpException($e->getMessage()); + } $filename = $request->post('dzuuid'); @@ -152,8 +156,8 @@ private function saveChunk(UploadedFile $file, Request $request, StorageConfig $ $chunks = $this->storeChunk($config, $range, $file, $filename); - if (!$this->isFinished($numberOfChunks, $chunks)) { - return new PercentageJsonResponse($this->getPercentage($chunks, $numberOfChunks)); + if (!$range->isFinished($chunks)) { + return new PercentageJsonResponse($range->getPercentage($chunks)); } $path = $this->mergeChunks($config, $chunks, $filename); @@ -166,26 +170,4 @@ private function saveChunk(UploadedFile $file, Request $request, StorageConfig $ return new PercentageJsonResponse(100); } - - /** - * @param $numberOfChunks - * @param $chunks - * - * @return bool - */ - private function isFinished($numberOfChunks, $chunks) - { - return $numberOfChunks === count($chunks); - } - - /** - * @param array $chunks - * @param $numberOfChunks - * - * @return float|int - */ - private function getPercentage(array $chunks, $numberOfChunks) - { - return floor(count($chunks) / $numberOfChunks * 100); - } } diff --git a/src/Range/RequestBodyRange.php b/src/Range/RequestBodyRange.php new file mode 100644 index 0000000..e1b8cd5 --- /dev/null +++ b/src/Range/RequestBodyRange.php @@ -0,0 +1,129 @@ +request; + } + + $this->index = $request->get($indexKey); + $this->numberOfChunks = $request->get($numberOfChunksKey); + $this->chunkSize = $request->get($chunkSizeKey); + $this->totalSize = $request->get($totalSizeKey); + + if ($this->numberOfChunks <= 0) { + throw new InvalidArgumentException(sprintf('`%s` must be greater than to zero', $numberOfChunksKey)); + } + if ($this->index < 0) { + throw new InvalidArgumentException(sprintf('`%s` must be greater than or equal to zero', $indexKey)); + } + if ($this->index >= $this->numberOfChunks) { + throw new InvalidArgumentException(sprintf('`%s` must be smaller than `%s`', $indexKey, $numberOfChunksKey)); + } + if ($this->chunkSize < 1) { + throw new InvalidArgumentException(sprintf('`%s` must be greater than zero', $chunkSizeKey)); + } + if ($this->totalSize < 1) { + throw new InvalidArgumentException(sprintf('`%s` must be greater than zero', $totalSizeKey)); + } elseif ($this->totalSize <= $this->index * $this->chunkSize) { + throw new InvalidArgumentException( + sprintf('`%s` must be greater than the multiple of `%s` and `%s`', $totalSizeKey, $chunkSizeKey, $indexKey) + ); + } elseif ($this->totalSize > $this->numberOfChunks * $this->chunkSize) { + throw new InvalidArgumentException( + sprintf('`%s` must be smaller than or equal to the multiple of `%s` and `%s`', $totalSizeKey, $chunkSizeKey, $numberOfChunksKey) + ); + } + } + + /** + * {@inheritDoc} + */ + public function getStart(): float + { + return $this->index * $this->chunkSize; + } + + /** + * {@inheritDoc} + */ + public function getEnd(): float + { + $end = (($this->index + 1) * $this->chunkSize) - 1; + + $sizeIndex = $this->totalSize - 1; + if ($end > ($sizeIndex)) { + return $sizeIndex; + } + + return $end; + } + + /** + * {@inheritDoc} + */ + public function getTotal(): float + { + return $this->totalSize; + } + + /** + * {@inheritDoc} + */ + public function isFirst(): bool + { + return $this->index === 0; + } + + /** + * {@inheritDoc} + */ + public function isLast(): bool + { + return $this->index === $this->numberOfChunks - 1; + } + + /** + * @param $uploadedChunks + * + * @return float + */ + public function getPercentage($uploadedChunks): float + { + return floor(count($uploadedChunks) / $this->numberOfChunks * 100); + } + + /** + * @param $uploadedChunks + * + * @return bool + */ + public function isFinished($uploadedChunks): bool + { + return $this->numberOfChunks === count($uploadedChunks); + } +} diff --git a/src/Range/RequestRange.php b/src/Range/RequestRange.php deleted file mode 100644 index 782ebe8..0000000 --- a/src/Range/RequestRange.php +++ /dev/null @@ -1,76 +0,0 @@ -index = $index; - $this->numberOfChunks = $numberOfChunks; - $this->totalSize = $totalSize; - $this->chunkSize = $chunkSize; - } - - /** - * {@inheritDoc} - */ - public function getStart(): float - { - return $this->index * $this->chunkSize; - } - - /** - * {@inheritDoc} - */ - public function getEnd(): float - { - $end = (($this->index + 1) * $this->chunkSize) - 1; - - if ($end > ($this->totalSize - 1)) { - return $this->totalSize - 1; - } - - return $end; - } - - /** - * {@inheritDoc} - */ - public function getTotal(): float - { - return $this->totalSize; - } - - /** - * {@inheritDoc} - */ - public function isFirst(): bool - { - return $this->index === 0; - } - - /** - * {@inheritDoc} - */ - public function isLast(): bool - { - return $this->index === $this->numberOfChunks - 1; - } -} diff --git a/tests/Range/RequestBodyRangeTest.php b/tests/Range/RequestBodyRangeTest.php new file mode 100644 index 0000000..4a37454 --- /dev/null +++ b/tests/Range/RequestBodyRangeTest.php @@ -0,0 +1,146 @@ + [4, 0, 20, 190, '`numberOfChunks` must be greater than to zero'], + 'Number of chunks size smaller than zero' => [4, -1, 20, 190, '`numberOfChunks` must be greater than to zero'], + 'Index smaller than zero' => [-1, 10, 20, 190, '`index` must be greater than or equal to zero'], + 'Index equal to the number of chunks' => [10, 10, 20, 190, '`index` must be smaller than `numberOfChunks`'], + 'Index greater than the number of chunks' => [14, 10, 20, 190, '`index` must be smaller than `numberOfChunks`'], + 'Chunk size equal to zero' => [4, 10, 0, 190, '`chunkSize` must be greater than zero'], + 'Chunk size smaller than zero' => [4, 10, -1, 190, '`chunkSize` must be greater than zero'], + 'Total size equal to zero' => [4, 10, 20, 0, '`totalSize` must be greater than zero'], + 'Total size smaller than zero' => [4, 10, 20, -1, '`totalSize` must be greater than zero'], + 'Total size too small' => [4, 10, 20, 80, '`totalSize` must be greater than the multiple of `chunkSize` and `index`'], + 'Total size too big' => [4, 10, 20, 201, '`totalSize` must be smaller than or equal to the multiple of `chunkSize` and `numberOfChunks`'], + ]; + } + + /** + * @dataProvider invalidArgumentProvider + * + * @param $index + * @param $numberOfChunks + * @param $chunkSize + * @param $totalSize + * @param $expectedExceptionMessage + */ + public function testArgumentValidation($index, $numberOfChunks, $chunkSize, $totalSize, $expectedExceptionMessage) + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage($expectedExceptionMessage); + + $this->createRequestBodyRange($index, $numberOfChunks, $chunkSize, $totalSize); + } + + public function testIsFirst() + { + $range = $this->createRequestBodyRange(0, 2, 1, 2); + $this->assertTrue($range->isFirst()); + + $range = $this->createRequestBodyRange(1, 2, 1, 2); + $this->assertFalse($range->isFirst()); + } + + public function testIsLast() + { + $range = $this->createRequestBodyRange(1, 2, 1, 2); + $this->assertTrue($range->isLast()); + + $range = $this->createRequestBodyRange(0, 2, 1, 2); + $this->assertFalse($range->isLast()); + } + + public function testIsFirstAndIsLast() + { + $range = $this->createRequestBodyRange(0, 1, 1, 1); + $this->assertTrue($range->isLast()); + $this->assertTrue($range->isLast()); + } + + public function testGetTotal() + { + $range = $this->createRequestBodyRange(4, 10, 20, 190); + $this->assertEquals(190, $range->getTotal()); + } + + public function testGetStart() + { + $range = $this->createRequestBodyRange(4, 10, 20, 190); + $this->assertEquals(80, $range->getStart()); + } + + public function testGetEnd() + { + $range = $this->createRequestBodyRange(4, 10, 20, 190); + $this->assertEquals(99, $range->getEnd()); + + $range = $this->createRequestBodyRange(9, 10, 20, 190); + $this->assertEquals(189, $range->getEnd()); + } + + public function testGetPercentage() + { + $range = $this->createRequestBodyRange(4, 10, 20, 190); + $this->assertEquals(100, $range->getPercentage(range(0, 9))); + + $range = $this->createRequestBodyRange(4, 10, 20, 190); + $this->assertEquals(90, $range->getPercentage(range(0, 8))); + } + + public function testIsFinished() + { + $range = $this->createRequestBodyRange(4, 10, 20, 190); + $this->assertTrue($range->isFinished(range(0, 9))); + + $range = $this->createRequestBodyRange(4, 10, 20, 190); + $this->assertFalse($range->isFinished(range(0, 8))); + } + + public function testCreateFromRequest() + { + $request = new Request([], [ + 'index' => 4, + 'numberOfChunks' => 10, + 'chunkSize' => 20, + 'totalSize' => 190, + ]); + + $range = new RequestBodyRange($request, 'index', 'numberOfChunks', 'chunkSize', 'totalSize'); + + $this->assertEquals(80, $range->getStart()); + $this->assertEquals(99, $range->getEnd()); + $this->assertEquals(190, $range->getTotal()); + } + + /** + * @param $index + * @param $numberOfChunks + * @param $chunkSize + * @param $totalSize + * + * @return \LaraCrafts\ChunkUploader\Range\RequestBodyRange + */ + private function createRequestBodyRange($index, $numberOfChunks, $chunkSize, $totalSize) + { + $request = new ParameterBag([ + 'index' => $index, + 'numberOfChunks' => $numberOfChunks, + 'chunkSize' => $chunkSize, + 'totalSize' => $totalSize, + ]); + + return new RequestBodyRange($request, 'index', 'numberOfChunks', 'chunkSize', 'totalSize'); + } +} From a5792de1266f05e4478d4f53815945e3bc233ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20G=C3=B6r=C3=B6g?= Date: Sat, 28 Sep 2019 11:34:36 +0200 Subject: [PATCH 2/5] Update src/Range/RequestBodyRange.php Co-Authored-By: Choraimy Kroonstuiver --- src/Range/RequestBodyRange.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Range/RequestBodyRange.php b/src/Range/RequestBodyRange.php index e1b8cd5..448affe 100644 --- a/src/Range/RequestBodyRange.php +++ b/src/Range/RequestBodyRange.php @@ -36,7 +36,7 @@ public function __construct($request, string $indexKey, string $numberOfChunksKe $this->totalSize = $request->get($totalSizeKey); if ($this->numberOfChunks <= 0) { - throw new InvalidArgumentException(sprintf('`%s` must be greater than to zero', $numberOfChunksKey)); + throw new InvalidArgumentException(sprintf('`%s` must be greater than zero', $numberOfChunksKey)); } if ($this->index < 0) { throw new InvalidArgumentException(sprintf('`%s` must be greater than or equal to zero', $indexKey)); From 7f7fdc999dbede9ed6e00788a5655d190ce9446e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20G=C3=B6r=C3=B6g?= Date: Sat, 28 Sep 2019 11:34:43 +0200 Subject: [PATCH 3/5] Update tests/Range/RequestBodyRangeTest.php Co-Authored-By: Choraimy Kroonstuiver --- tests/Range/RequestBodyRangeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Range/RequestBodyRangeTest.php b/tests/Range/RequestBodyRangeTest.php index 4a37454..b66a857 100644 --- a/tests/Range/RequestBodyRangeTest.php +++ b/tests/Range/RequestBodyRangeTest.php @@ -14,7 +14,7 @@ public function invalidArgumentProvider() { return [ 'Number of chunks size equal to zero' => [4, 0, 20, 190, '`numberOfChunks` must be greater than to zero'], - 'Number of chunks size smaller than zero' => [4, -1, 20, 190, '`numberOfChunks` must be greater than to zero'], + 'Number of chunks size smaller than zero' => [4, -1, 20, 190, '`numberOfChunks` must be greater than zero'], 'Index smaller than zero' => [-1, 10, 20, 190, '`index` must be greater than or equal to zero'], 'Index equal to the number of chunks' => [10, 10, 20, 190, '`index` must be smaller than `numberOfChunks`'], 'Index greater than the number of chunks' => [14, 10, 20, 190, '`index` must be smaller than `numberOfChunks`'], From 33ef22158af7c9594c592ef175bdfdab84e6c870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20G=C3=B6r=C3=B6g?= Date: Sat, 28 Sep 2019 11:34:50 +0200 Subject: [PATCH 4/5] Update tests/Range/RequestBodyRangeTest.php Co-Authored-By: Choraimy Kroonstuiver --- tests/Range/RequestBodyRangeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Range/RequestBodyRangeTest.php b/tests/Range/RequestBodyRangeTest.php index b66a857..33262e7 100644 --- a/tests/Range/RequestBodyRangeTest.php +++ b/tests/Range/RequestBodyRangeTest.php @@ -13,7 +13,7 @@ class RequestBodyRangeTest extends TestCase public function invalidArgumentProvider() { return [ - 'Number of chunks size equal to zero' => [4, 0, 20, 190, '`numberOfChunks` must be greater than to zero'], + 'Number of chunks size equal to zero' => [4, 0, 20, 190, '`numberOfChunks` must be greater than zero'], 'Number of chunks size smaller than zero' => [4, -1, 20, 190, '`numberOfChunks` must be greater than zero'], 'Index smaller than zero' => [-1, 10, 20, 190, '`index` must be greater than or equal to zero'], 'Index equal to the number of chunks' => [10, 10, 20, 190, '`index` must be smaller than `numberOfChunks`'], From 63ca7eae8d3b6f3cd7c77b42959090763b5c2a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20G=C3=B6r=C3=B6g?= Date: Fri, 14 Feb 2020 22:40:18 +0100 Subject: [PATCH 5/5] Preserve exception --- src/Driver/BlueimpUploadDriver.php | 2 +- src/Driver/DropzoneUploadDriver.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Driver/BlueimpUploadDriver.php b/src/Driver/BlueimpUploadDriver.php index aaa29ea..01f5ab2 100644 --- a/src/Driver/BlueimpUploadDriver.php +++ b/src/Driver/BlueimpUploadDriver.php @@ -136,7 +136,7 @@ public function save(Request $request, StorageConfig $config, Closure $fileUploa try { $range = new ContentRange($request->headers); } catch (InvalidArgumentException $e) { - throw new BadRequestHttpException($e->getMessage()); + throw new BadRequestHttpException($e->getMessage(), $e); } $filename = $this->identifier->generateUploadedFileIdentifierName($file); diff --git a/src/Driver/DropzoneUploadDriver.php b/src/Driver/DropzoneUploadDriver.php index 9f3e5ed..cbdaa67 100644 --- a/src/Driver/DropzoneUploadDriver.php +++ b/src/Driver/DropzoneUploadDriver.php @@ -13,6 +13,7 @@ use LaraCrafts\ChunkUploader\Response\PercentageJsonResponse; use LaraCrafts\ChunkUploader\StorageConfig; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; class DropzoneUploadDriver extends UploadDriver @@ -134,7 +135,7 @@ private function saveChunk(UploadedFile $file, Request $request, StorageConfig $ 'dztotalfilesize' ); } catch (InvalidArgumentException $e) { - throw new BadRequestHttpException($e->getMessage()); + throw new BadRequestHttpException($e->getMessage(), $e); } $filename = $request->post('dzuuid');