knutin/elli — pull request #38 by zambal (2012-11-08 08:47:05+00:00)
Title: Added single byte-range support for elli_hhtp:send_file

This PR adds support for byte-range requests and responses with send_file, as defined in rfc2616-14.35 and rfc2616-14.16. This makes it for example possible to let Elli serve files to html5 audio and video elements with proper file seek support.

Some notes about the current implementation:

* Adds around 100 LOC, including comments, whitespace and specs to elli_http.erl. Most of the code deals with parsing and generating correct HTTP range headers.
* Performance impact on non send_file requests should be almost none. (added a few extra cases to elli_http:execute_callback/2)
* Performance impact for send_file requests without a range (ie. the previous send_file implementation) should be insignificant, since it still uses the native sendfile implementation, although via file:sendfile/5 instead of file:sendfile/2.
* Code should be backwards compatible with the previous send_file implementation, although the semantics have been changed slightly, see below.
* Since a correct Content-Length value now depends on a possible byte-range request, it doesn't make sense to let a user specify the Content-Length header in the callback module anymore.
* So setting the Content-Length of the file in a callback handler, as was mandatory in the previous implementation has no effect anymore, as its value will be overwritten by send_file.
* It's still possible to set the size of the file iin the callback handler for efficiency or flexibility reasons, but now as an optional option: `{file, "path/to/file", [{size, 1000}]}`. send_file will add a correct Content-Length header considering both range and size information. If the size option is omitted, send_file checks the file size itself by calling file:read_file_info/1
* Ranges can also be explicitly set in the callback handler via: `{file, "path/to/file", [{range, {0, 500}}]}`
* Explicitly set ranges have precedence over ranges set in the request header.
* If a range is present, the HTTP status code will be rewritten to 206 - Partial Content if the range is valid and 416 Requested Range Not Satisfiable if the range is invalid.