diff options
| -rw-r--r-- | phpBB/includes/functions_download.php | 98 | ||||
| -rw-r--r-- | tests/download/http_byte_range_test.php | 62 | 
2 files changed, 110 insertions, 50 deletions
diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php index 8f6526dd71..d61ce3d098 100644 --- a/phpBB/includes/functions_download.php +++ b/phpBB/includes/functions_download.php @@ -254,11 +254,21 @@ function send_file_to_browser($attachment, $upload_dir, $category)  				send_status_line(206, 'Partial Content');  				header('Content-Range: bytes ' . $range['byte_pos_start'] . '-' . $range['byte_pos_end'] . '/' . $range['bytes_total']);  				header('Content-Length: ' . $range['bytes_requested']); -			} -			while (!feof($fp)) +				// First read chunks +				while (!feof($fp) && ftell($fp) < $range['byte_pos_end'] - 8192) +				{ +					echo fread($fp, 8192); +				} +				// Then, read the remainder +				echo fread($fp, $range['bytes_requested'] % 8192); +			} +			else  			{ -				echo fread($fp, 8192); +				while (!feof($fp)) +				{ +					echo fread($fp, 8192); +				}  			}  			fclose($fp);  		} @@ -529,6 +539,9 @@ function phpbb_find_range_request()  */  function phpbb_parse_range_request($request_array, $filesize)  { +	$first_byte_pos	= -1; +	$last_byte_pos	= -1; +  	// Go through all ranges  	foreach ($request_array as $range_string)  	{ @@ -540,62 +553,61 @@ function phpbb_parse_range_request($request_array, $filesize)  			continue;  		} +		// Substitute defaults  		if ($range[0] === '')  		{ -			// Return last $range[1] bytes. - -			if (!$range[1]) -			{ -				continue; -			} +			$range[0] = 0; +		} -			if ($range[1] >= $filesize) -			{ -				return false; -			} +		if ($range[1] === '') +		{ +			$range[1] = $filesize - 1; +		} -			$first_byte_pos	= $filesize - (int) $range[1]; -			$last_byte_pos	= $filesize - 1; +		if ($last_byte_pos >= 0 && $last_byte_pos + 1 != $range[0]) +		{ +			// We only support contiguous ranges, no multipart stuff :( +			return false;  		} -		else + +		if ($range[1] && $range[1] < $range[0])  		{ -			// Return bytes from $range[0] to $range[1] +			// The requested range contains 0 bytes. +			continue; +		} +		// Return bytes from $range[0] to $range[1] +		if ($first_byte_pos < 0) +		{  			$first_byte_pos	= (int) $range[0]; -			$last_byte_pos	= (int) $range[1]; - -			if ($last_byte_pos && $last_byte_pos < $first_byte_pos) -			{ -				// The requested range contains 0 bytes. -				continue; -			} +		} -			if ($first_byte_pos >= $filesize) -			{ -				// Requested range not satisfiable -				return false; -			} +		$last_byte_pos	= (int) $range[1]; -			// Adjust last-byte-pos if it is absent or greater than the content. -			if ($range[1] === '' || $last_byte_pos >= $filesize) -			{ -				$last_byte_pos = $filesize - 1; -			} +		if ($first_byte_pos >= $filesize) +		{ +			// Requested range not satisfiable +			return false;  		} -		// We currently do not support range requests that end before the end of the file -		if ($last_byte_pos != $filesize - 1) +		// Adjust last-byte-pos if it is absent or greater than the content. +		if ($range[1] === '' || $last_byte_pos >= $filesize)  		{ -			continue; +			$last_byte_pos = $filesize - 1;  		} +	} -		return array( -			'byte_pos_start'	=> $first_byte_pos, -			'byte_pos_end'		=> $last_byte_pos, -			'bytes_requested'	=> $last_byte_pos - $first_byte_pos + 1, -			'bytes_total'		=> $filesize, -		); +	if ($first_byte_pos < 0 || $last_byte_pos < 0) +	{ +		return false;  	} + +	return array( +		'byte_pos_start'	=> $first_byte_pos, +		'byte_pos_end'		=> $last_byte_pos, +		'bytes_requested'	=> $last_byte_pos - $first_byte_pos + 1, +		'bytes_total'		=> $filesize, +	);  }  /** diff --git a/tests/download/http_byte_range_test.php b/tests/download/http_byte_range_test.php index f920299048..8975ec1799 100644 --- a/tests/download/http_byte_range_test.php +++ b/tests/download/http_byte_range_test.php @@ -45,24 +45,72 @@ class phpbb_download_http_byte_range_test extends phpbb_test_case  	public function parse_range_request_data()  	{  		return array( -			// Does not read until the end of file. +            // Valid request  			array(  				array('3-4'),  				10, -				false, +				array( +					'byte_pos_start'	=> 3, +					'byte_pos_end'		=> 4, +					'bytes_requested'	=> 2, +					'bytes_total'		=> 10, +				),  			), -			// Valid request, handle second range. +            // Get the beginning  			array( -				array('0-0', '120-125'), -				125, +				array('-5'), +				10,  				array( -					'byte_pos_start'	=> 120, -					'byte_pos_end'		=> 124, +					'byte_pos_start'	=> 0, +					'byte_pos_end'		=> 5, +					'bytes_requested'	=> 6, +					'bytes_total'		=> 10, +				), +			), + +            // Get the end +			array( +				array('5-'), +				10, +				array( +					'byte_pos_start'	=> 5, +					'byte_pos_end'		=> 9,  					'bytes_requested'	=> 5, +					'bytes_total'		=> 10, +				), +			), + +            // Overlong request +			array( +				array('3-20'), +				10, +				array( +					'byte_pos_start'	=> 3, +					'byte_pos_end'		=> 9, +					'bytes_requested'	=> 7, +					'bytes_total'		=> 10, +				), +			), + +			// Multiple, contiguous range +			array( +				array('10-20', '21-30'), +				125, +				array( +					'byte_pos_start'	=> 10, +					'byte_pos_end'		=> 30, +					'bytes_requested'	=> 21,  					'bytes_total'		=> 125,  				)  			), + +			// We don't do multiple, non-contiguous range +			array( +				array('0-0', '120-125'), +				125, +				false, +			),  		);  	}  }  | 
