From 94afd46898053d1e4f6bf4750f7d37a8172efe43 Mon Sep 17 00:00:00 2001 From: Cyperghost Date: Wed, 11 Sep 2024 10:42:47 +0200 Subject: [PATCH] Accept the HTTP header `Range` for file downloads --- .../lib/action/FileDownloadAction.class.php | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/wcfsetup/install/files/lib/action/FileDownloadAction.class.php b/wcfsetup/install/files/lib/action/FileDownloadAction.class.php index 224697e674..01f9f589d4 100644 --- a/wcfsetup/install/files/lib/action/FileDownloadAction.class.php +++ b/wcfsetup/install/files/lib/action/FileDownloadAction.class.php @@ -3,6 +3,7 @@ namespace wcf\action; use GuzzleHttp\Psr7\Header; +use GuzzleHttp\Psr7\LimitStream; use Laminas\Diactoros\Response; use Laminas\Diactoros\Response\EmptyResponse; use Laminas\Diactoros\Stream; @@ -14,6 +15,7 @@ use wcf\http\ContentDisposition; use wcf\http\Helper; use wcf\system\exception\IllegalLinkException; use wcf\system\exception\PermissionDeniedException; +use wcf\system\Regex; use wcf\util\FileUtil; /** @@ -70,6 +72,33 @@ final class FileDownloadAction implements RequestHandlerInterface default => ContentDisposition::Attachment, }; + [$startByte, $endByte] = $this->parseRangeHeader($request, $file->fileSize); + + // check if the range is valid + if ( + $file->fileSize > 0 + && ( + $startByte < 0 + || $startByte >= $file->fileSize + || $endByte < $startByte + ) + ) { + return $response + ->withStatus(416) + ->withHeader('accept-ranges', 'bytes') + ->withHeader('content-range', "bytes */{$file->fileSize}"); + } + + if ($startByte > 0 || $endByte < $file->fileSize - 1) { + $response = $response + ->withStatus(206) + ->withHeader('content-range', \sprintf('bytes %d-%d/%d', $startByte, $endByte, $file->fileSize)); + + $response = $response->withBody( + new LimitStream($response->getBody(), $endByte - $startByte + 1, $startByte) + ); + } + // Prevent