From d1a971e22156d5eafa4f3e33231b0f21c6b9e8bd Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 5 Apr 2017 10:51:40 -0700 Subject: [PATCH] Support "Range: bytes=123-" requests Summary: Ref T12219. We currently only support Range requests like "bytes=123-456", but "bytes=123-", meaning "until end of file", is valid, and Chrome can send these requests. I suspect this is the issue with T12219. Test Plan: Used `nc local.phacility.com 80` to pipe raw requests, saw both "bytes=123-456" and "bytes=123-" requests satisfied correctly. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12219 Differential Revision: https://secure.phabricator.com/D17626 --- src/aphront/response/AphrontFileResponse.php | 5 +++++ .../controller/PhabricatorFileDataController.php | 13 ++++++++++--- .../PhabricatorFileStorageFormatTestCase.php | 8 ++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/aphront/response/AphrontFileResponse.php b/src/aphront/response/AphrontFileResponse.php index 6337c984b9..25750ddacd 100644 --- a/src/aphront/response/AphrontFileResponse.php +++ b/src/aphront/response/AphrontFileResponse.php @@ -97,7 +97,12 @@ final class AphrontFileResponse extends AphrontResponse { if ($this->rangeMin || $this->rangeMax) { $len = $this->getContentLength(); $min = $this->rangeMin; + $max = $this->rangeMax; + if ($max === null) { + $max = ($len - 1); + } + $headers[] = array('Content-Range', "bytes {$min}-{$max}/{$len}"); $content_len = ($max - $min) + 1; } else { diff --git a/src/applications/files/controller/PhabricatorFileDataController.php b/src/applications/files/controller/PhabricatorFileDataController.php index 43b5aa419f..31761d1244 100644 --- a/src/applications/files/controller/PhabricatorFileDataController.php +++ b/src/applications/files/controller/PhabricatorFileDataController.php @@ -64,14 +64,21 @@ final class PhabricatorFileDataController extends PhabricatorFileController { $range = $request->getHTTPHeader('range'); if ($range) { $matches = null; - if (preg_match('/^bytes=(\d+)-(\d+)$/', $range, $matches)) { + if (preg_match('/^bytes=(\d+)-(\d*)$/', $range, $matches)) { // Note that the "Range" header specifies bytes differently than // we do internally: the range 0-1 has 2 bytes (byte 0 and byte 1). $begin = (int)$matches[1]; - $end = (int)$matches[2] + 1; + + // The "Range" may be "200-299" or "200-", meaning "until end of file". + if (strlen($matches[2])) { + $range_end = (int)$matches[2]; + $end = $range_end + 1; + } else { + $range_end = null; + } $response->setHTTPResponseCode(206); - $response->setRange($begin, ($end - 1)); + $response->setRange($begin, $range_end); } } diff --git a/src/applications/files/format/__tests__/PhabricatorFileStorageFormatTestCase.php b/src/applications/files/format/__tests__/PhabricatorFileStorageFormatTestCase.php index db10b87964..b3425ba313 100644 --- a/src/applications/files/format/__tests__/PhabricatorFileStorageFormatTestCase.php +++ b/src/applications/files/format/__tests__/PhabricatorFileStorageFormatTestCase.php @@ -91,6 +91,14 @@ final class PhabricatorFileStorageFormatTestCase extends PhabricatorTestCase { $raw_data .= $data_chunk; } $this->assertEqual('cow jumped', $raw_data); + + $iterator = $file->getFileDataIterator(4, null); + $raw_data = ''; + foreach ($iterator as $data_chunk) { + $raw_data .= $data_chunk; + } + $this->assertEqual('cow jumped over the full moon.', $raw_data); + } public function testStorageTampering() {