From c6f28407e948d4d977a42c6a4e466144b5accb69 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim=20D=C3=BCsterhus?= Date: Sun, 23 Apr 2017 16:20:24 +0200 Subject: [PATCH] Fix `Range` handling in \wcf\util\FileReader - Disallow invalid Range: bytes=100 without a trailing hyphen. - Disallow invalid Range: bytes=2-1 with start > end. - Support valid Range: bytes=0-0 with end = 0. - Support maximum offset > filesize as per RFC 7233: A client can limit the number of bytes requested without knowing the size of the selected representation. If the last-byte-pos value is absent, or if the value is greater than or equal to the current length of the representation data, the byte range is interpreted as the remainder of the representation (i.e., the server replaces the value of last-byte-pos with a value that is one less than the current length of the selected representation). --- .../files/lib/util/FileReader.class.php | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/wcfsetup/install/files/lib/util/FileReader.class.php b/wcfsetup/install/files/lib/util/FileReader.class.php index 14625bd9ae..a339f4f721 100644 --- a/wcfsetup/install/files/lib/util/FileReader.class.php +++ b/wcfsetup/install/files/lib/util/FileReader.class.php @@ -105,20 +105,25 @@ class FileReader { $this->endByte = $this->options['filesize'] - 1; if ($this->options['enableRangeSupport']) { if (!empty($_SERVER['HTTP_RANGE'])) { - $regex = new Regex('^bytes=(-?\d+)(?:-(\d+))?$'); + $regex = new Regex('^bytes=(?:(\d+)-(\d+)?|-(\d+))$'); if ($regex->match($_SERVER['HTTP_RANGE'])) { $matches = $regex->getMatches(); - $first = intval($matches[1]); - $last = (isset($matches[2]) ? intval($matches[2]) : 0); + $start = (isset($matches[1]) && $matches[1] !== '' ? intval($matches[1]) : null); + $end = (isset($matches[2]) && $matches[2] !== '' ? intval($matches[2]) : null); + $last = (isset($matches[3]) && $matches[3] !== '' ? intval($matches[3]) : null); - if ($first < 0) { - // negative value; subtract from filesize - $this->startByte = $this->options['filesize'] + $first; + if ($start !== null) { + $this->startByte = $start; } - else { - $this->startByte = $first; - if ($last > 0) { - $this->endByte = $last; + if ($end !== null) { + if ($end <= ($this->options['filesize'] - 1)) { + $this->endByte = $end; + } + } + if ($start === null && $end === null && $last !== null) { + if ($last <= $this->options['filesize']) { + // negative value; subtract from filesize + $this->startByte = $this->options['filesize'] - $last; } } } @@ -130,7 +135,7 @@ class FileReader { * Handles the given header items. */ protected function handleHeaders() { - if ($this->startByte < 0 || $this->startByte >= $this->options['filesize'] || $this->endByte >= $this->options['filesize']) { + if ($this->startByte < 0 || $this->startByte >= $this->options['filesize'] || $this->endByte < $this->startByte) { // invalid range given $this->addHeader('', 'HTTP/1.1 416 Requested Range Not Satisfiable'); $this->addHeader('Accept-Ranges', 'bytes'); -- 2.20.1