Rails byte-range request support


I'm trying to serve the iPhone a video file from my controller using
send_file. However, it appears as thought the iPhone requires byte-
range request support and rails doesn't seem to support this.

If I give the iPhone a url that points to an actual file (i.e. it's
served by my webserver nginx, instead of rails) it downloads and plays
it fine.

Here is the proof (from the iphone docs):

This byte-range request should only return 100 bytes from the video:

curl --range 0-99 http://test.com/7_7.3g2 -o /dev/null
  % Total % Received % Xferd Average Speed Time Time
Time Current
                                 Dload Upload Total Spent
Left Speed
  0 100 0 100 0 0 49 0 --:--:-- 0:00:02
--:--:-- 97

As you can see it does, i.e. byte-range support. Now lets try the same
thing on my controller:

curl --range 0-50 http://test.com/play_video -o /dev/null
  % Total % Received % Xferd Average Speed Time Time
Time Current
                                 Dload Upload Total Spent
Left Speed
100 261k 100 261k 0 0 44310 0 0:00:06 0:00:06
--:--:-- 68172

As you can see it downloaded the entire file, i.e. no byte-range

Any idea how I can get around this issue, because I really need to be
able to server the file via my controller.

Well you need to do 2 things: extract the desired range, for which I imagine you could get from poking around with the environment ActionController sets up for you.
Secondly send_file would have to support sending a range of data, which it currently doesn't. However the source to send_file isn't complicated. It shouldn't be hard to add this.


A quick glance at the api shows this:

  • :filename - suggests a filename for the browser to use. Defaults to File.basename(path).
  • :type - specifies an HTTP content type. Defaults to ‘application/octet-stream’.
  • :disposition - specifies whether the file will be shown inline or downloaded. Valid values are ‘inline’ and ‘attachment’ (default).
  • :stream - whether to send the file to the user agent as it is read (true) or to read the entire file before sending (false). Defaults to true.
  • :buffer_size - specifies size (in bytes) of the buffer used to stream the file. Defaults to 4096.
  • :status - specifies the status code to send with the response. Defaults to ‘200 OK’.

What if you set :buffer_size => 100? Does that work?

The fix is to the X-Sendfile or X-Accel-Redirect for apache/ighthttp
or nginx respectively.

Definitely... You don't want to do this in Rails because a)
apache/lighttpd/nginx are tuned for this, b) mongrel buffers responses
from rails, so this could eat up some memory, and c) longer responses
can lock the mongrel process from responding to other rails requests.

What should I do?