Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Chrome not completing request if a Partial Content header is set

I am trying to stream a mp3 file to SoundManager with the HTTP/1.1 Partial Content header to allow some protection to my media files and also allow users to seek to different locations of the track. The code I have works in IE7-10, Firefox, Safari and Opera but refuses to work in Google Chrome. If I was to remove the Partial Content header it would play the file but wouldn't allow the user to seek.

When examining the network tab in Chrome's dev tools there are 2 requests, one is stuck with the status of pending and the other has the status of canceled. both of these requests have a size of 13B. The file I am trying to play is 9.11MB.

Below is the code I am using to set the headers and read the file.

        $name = $_GET['name'];
        $file_size = filesize($file);
        $file = "C:\xampp\htdocs\..\protected\music\testsong.mp3"; // song, user and all other checks are performed before this to get the file path.
        $etag = md5(uniqid(rand(), true));

        $open_file = fopen($file, 'rb');
        if( !$open_file ) throw new Exception('Could not open file');

        $start = 0;
        $end = $file_size - 1;

        if( isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE']) ) {
            $range = explode('-', substr($_SERVER['HTTP_RANGE'], strlen('bytes=')));

            $start = $range[0];
            if( $range[1] > 0 ) $end = $range[1];

            header('HTTP/1.1 206 Partial Content');
            header('Status: 206');
            header('Accept-Ranges: bytes');
            header('Content-Range: ' . $_SERVER['HTTP_RANGE'] . '/' . $file_size);
            header('Content-Length: ' . ($end - $start + 1));
        } else header('Content-Length: ' . $file_size);

        header('Content-Type: ' . $content_type);
        if( $download ) header('Content-Disposition: attachment; filename="' . $name . '"');
        header('Last-Modified: ' . date('D, d M Y H:i:s \G\M\T', filemtime($file)));

        header('ETag: "' . $etag . '"');
        header('Expires: 0');
        header('Pragma: no-cache');
        header('Cache-Control: must-revalidate');

        if( $start > 0 ) fseek($open_file, $start);

        $bytes_position = $start;
        while( !feof($open_file) && $bytes_position <= $end ) {
            if( connection_aborted() || connection_status() != 0 ) throw New Exception('Connection Aborted');

            $chunk = 1048000;
            if( $bytes_position + $chunk > $end + 1 ) $chunk = $end - $bytes_position + 1;

            $chunk = fread($open_file, $chunk);
            if( !$chunk ) throw New Exception('Could not read file');

            print($chunk);
            flush();

            $bytes_position += $chunk;
        }

        fclose($open_file);
like image 384
user2801323 Avatar asked Sep 21 '13 04:09

user2801323


People also ask

Why can't chrome webrequests handle specific request headers?

The Chrome WebRequests API mentions that specific request headers are not available to the onBeforeSendHeaders event, meaning that extensions cannot read and/or modify these headers. Here is an excerpt from the documentation:

Why does the API not provide the final HTTP headers?

Internally, one URL request can be split into several HTTP requests (for example to fetch individual byte ranges from a large file) or can be handled by the network stack without communicating with the network. For this reason, the API does not provide the final HTTP headers that are sent to the network.

What are HTTP headers in Android apps?

HTTP requests contain headers such as User-Agent or Content-Type. Apart from headers attached by browsers, Android apps may add extra headers, like Cookie or Referrer through the EXTRA_HEADERS Intent extra. For security reasons, Chrome filters some of the extra headers depending on how and where an intent is launched.

How do request header modifications affect Cors checks in chrome?

Starting from Chrome 79, request header modifications affect Cross-Origin Resource Sharing (CORS) checks. If modified headers for cross-origin requests do not meet the criteria, it will result in sending a CORS preflight to ask the server if such headers can be accepted.


1 Answers

I'm pretty sure the problem you're having is with the content-range header

try this instead

header('Content-Range: bytes ' . $start . '-' . $end . '/' . $file_size);
like image 141
Swayze Avatar answered Oct 18 '22 14:10

Swayze