HTTP Status: 206 Partial Content and Range Requests
Akki commented on my 100 Continue post, asking:
I was wondering if there was a response status to allow a large file to be “served” in parts and in just one response?
While I’ve never done this myself, I did some research to see how it might be done, and I’ve come up with a solution that I wish I could call clever, innovative, and many other words that make me sound like I came up with a smart solution, but the reality of it is that HTTP was made to support this behavior, so I’ll just tell you how to do it with standard HTTP.
First of all, let’s create a scenario. Say I want to request a very large file from a service, but before I do so, I want to find out exactly how large it is and whether the service supports “range requests.” To do this, I make a HEAD request to the large resource I want to retrieve. The HEAD method is a standard HTTP method that acts as if I’ve made a GET request, but it returns only the headers and not the body. This allows me to find out some information about the resource without actually taking the time or using the bandwidth to download it. For example, I can read the Content-Length header and determine the size of the resource.
Another header of great importance is the Accept-Ranges header. If it’s present, it may contain a value of “bytes.” If so, I know that I can make a GET request and request a byte range to retrieve only those bytes. This is the first important key component:
1. If you are building a service that accepts byte range requests, let clients know by providing the Accept-Ranges header in response to GET and HEAD requests.
So, now, I know I can make a range request to the service, which I do by sending a standard GET request including a Range header that specifies the range of bytes I’m requesting, like so: Range: bytes=0-999. The service should then respond with with a 206 Partial Content status code, a Content-Range header, and the requested range of bytes. This is the second key component:
2. If a client makes a request of your service with a Range header, return a 206 Partial Content response containing a Content-Range header and the requested range of bytes for the resource in the body. The Content-Length value should be the length of what is actually returned and not the full length of the resource.
From then on, it’s a matter of the client continuing to make requests until it has retrieved all of the bytes it wishes to get from the resource. If the client makes a range request that is out of bounds—that is, none of the range values overlap the extent of the resource—the service should respond with a 416 Requested Range Not Satisfiable status.
I should note that the service cannot force the client to make a range request. It is entirely up to the client to make such requests, so the service should honor all standard GET requests that do not contain a Range header by sending back the full representation of the requested resource. If your service allows range requests, it is to your benefit to tell the client with an Accept-Ranges header. If you want to explicitly tell the client that you do not allow range requests, send a value of “none” back with the Accept-Ranges header.
Since I learn best by looking at real-life examples, I’ll provide one for you. Here’s a real example making range requests with Flickr. I’ve removed some of the headers for simplicity and clarity.
HEAD /2390/2253727548_a413c88ab3_s.jpg HTTP/1.1
Host: farm3.static.flickr.com
HTTP/1.0 200 OK
Date: Mon, 05 May 2008 00:33:14 GMT
Server: Apache/2.0.52 (Red Hat)
Accept-Ranges: bytes
Content-Length: 3980
Content-Type: image/jpeg
GET /2390/2253727548_a413c88ab3_s.jpg HTTP/1.1
Host: farm3.static.flickr.com
Range: bytes=0-999
HTTP/1.0 206 Partial Content
Date: Mon, 05 May 2008 00:36:57 GMT
Server: Apache/2.0.52 (Red Hat)
Accept-Ranges: bytes
Content-Length: 1000
Content-Range: bytes 0-999/3980
Content-Type: image/jpeg
{binary data}
GET /2390/2253727548_a413c88ab3_s.jpg HTTP/1.1
Host: farm3.static.flickr.com
Range: bytes=1000-
HTTP/1.0 206 Partial Content
Date: Mon, 05 May 2008 00:37:54 GMT
Server: Apache/2.0.52 (Red Hat)
Accept-Ranges: bytes
Content-Length: 2980
Content-Range: bytes 1000-3979/3980
Content-Type: image/jpeg
{binary data}
9 Comments
Ben, this is awesome! Stuff like this really makes me wonder what other gems are lying "hidden" in RFC 2616....:D
@Adam , not talking about those "lost chunks of rfc2616", like rfc2183, rfc2617 etc...
Keep going Ben, I enjoy :)
how i calling Range: bytes=0-999 on my browser manualy.
give me an example .
thanks
That is a real nice snipper for resume downloads which i was searching in Google. Thanks for your content on the net.
I am trying to do a persistent connection for resume download. can you provide snippet for that too. then the above snippets will give people the idea to resume download.
Hi.
I'm stocked trying to make my website do what you teach here. I understand theorically what you say but i can't put it on code.
Do you have any working implemetation for java to help me with this?
I'm serving a PDF file and need to show it while the download is still in progress.
Hope you can help me.
Sebastian - Did you find a solution to this issue? I am trying to do the exact same thing - show 1st few pages of the pdf while the pdf is loading?
Pls let me know.
Sebastian and others,
This article was written in 2008 and I am reading it in 2010..
just wanted to add that... a Web Service should be capable of serving HTTP 206 but HTTP client should capable of using it also. Now generally just browser is not capable of doing it. But those browsers that have a integrated download/upload manager or a standalone download manager (a special type of HTTP Client) is designed on this principle only. For demonstration on HTTP 206 you can just show realtime HTTP headers...or as just an example you can use Flashget(a free download manager) use for HTTP 206 demonstration and don't forget to go to Log tab.
Ajeet
Someone wrote a program to fully implement this in php - here's a link - it's years old but works perfectly :
http://www.coneural.org/flo...
Ben,
This is Great! I have understood some concepts of partial streaming content from your post. Thanks a lot
I have problem, I use Firefox 4 browser to stream(progressive download) movie in Silverlight using ashx handler. When I seek to a new position, The browser does not initiate a request at all ,instead it downloads the entire movie and then resumes back.
This behavior is applicable in chrome too. But in IE 8 it works great.
What would be the reason for this problem. Would be able to help me out regarding this ?
Thank you
Praveen