Browse Source

Handle malformed Range headers without warnings.

Don't emit warnings on malformed/invalid range headers. Also make
parsing more robust and allow whitespace between significant tokens.
Mark Story 10 years ago
parent
commit
a49361fc7c
2 changed files with 65 additions and 4 deletions
  1. 8 3
      src/Network/Response.php
  2. 57 1
      tests/TestCase/Network/ResponseTest.php

+ 8 - 3
src/Network/Response.php

@@ -1478,11 +1478,16 @@ class Response
      */
     protected function _fileRange($file, $httpRange)
     {
-        list(, $range) = explode('=', $httpRange);
-        list($start, $end) = explode('-', $range);
-
         $fileSize = $file->size();
         $lastByte = $fileSize - 1;
+        $start = 0;
+        $end = $lastByte;
+
+        preg_match('/^bytes\s*=\s*(\d+)?\s*-\s*(\d+)?$/', $httpRange, $matches);
+        if ($matches) {
+            $start = $matches[1];
+            $end = isset($matches[2]) ? $matches[2] : '';
+        }
 
         if ($start === '') {
             $start = $fileSize - $end;

+ 57 - 1
tests/TestCase/Network/ResponseTest.php

@@ -1631,12 +1631,19 @@ class ResponseTest extends TestCase
             [
                 'bytes=0-', 38, 'bytes 0-37/38'
             ],
+
             [
                 'bytes=10-', 28, 'bytes 10-37/38'
             ],
+
             [
                 'bytes=10-20', 11, 'bytes 10-20/38'
             ],
+
+            // Spaced out
+            [
+                'bytes = 10 - 20', 11, 'bytes 10-20/38'
+            ],
         ];
     }
 
@@ -1747,11 +1754,60 @@ class ResponseTest extends TestCase
     }
 
     /**
+     * Provider for invalid range header values.
+     *
+     * @return array
+     */
+    public function invalidFileRangeProvider()
+    {
+        return [
+            // malformed range
+            [
+                'bytes=0,38'
+            ],
+
+            // malformed punctuation
+            [
+                'bytes: 0 - 38'
+            ],
+        ];
+    }
+
+    /**
      * Test invalid file ranges.
      *
+     * @dataProvider invalidFileRangeProvider
+     * @return void
+     */
+    public function testFileRangeInvalid($range)
+    {
+        $_SERVER['HTTP_RANGE'] = $range;
+        $response = $this->getMock('Cake\Network\Response', [
+            '_sendHeader',
+            '_isActive',
+        ]);
+
+        $response->file(
+            TEST_APP . 'vendor' . DS . 'css' . DS . 'test_asset.css',
+            ['download' => true]
+        );
+
+        $expected = [
+            'Content-Disposition' => 'attachment; filename="test_asset.css"',
+            'Content-Transfer-Encoding' => 'binary',
+            'Accept-Ranges' => 'bytes',
+            'Content-Range' => 'bytes 0-37/38',
+            'Content-Length' => 38,
+        ];
+        $this->assertEquals($expected, $response->header());
+    }
+
+    /**
+     * Test reversed file ranges.
+     *
      * @return void
      */
-    public function testFileRangeInvalid()
+    public function testFileRangeReversed()
     {
         $_SERVER['HTTP_RANGE'] = 'bytes=30-2';
         $response = $this->getMock('Cake\Network\Response', [