Advanced Rails - Building Industrial-Strength Web Apps in Record Time

(Tuis.) #1
Large/Binary Objects | 105

Sending Data with X-Sendfile


Often you will need to send a file to the client for download after doing some pro-
cessing in Rails. The most common example is an access-controlled file—you need
to verify that the logged-in user has the appropriate level of access before sending the
file, for example. The easy way to do this is with thesend_fileorsend_dataAPI
calls, which stream data from the server to the client:


class DataController < ApplicationController
before_filter :check_authenticated

def private_document
file = File.find params[:id]
send_file file.path if file
end

end

This method is easy, but it is slow if you are sending static files. Rails reads the file
and streams it byte-by-byte to the client. The X-Sendfile protocol makes this easy
and fast, by allowing Rails to do its processing but then offloading the “heavy lift-
ing” to the web server (which may offload that processing to the operating system
kernel, as described previously).


The X-Sendfile protocol is a very simple standard, first introduced in the Lighttpd
web server, which directs the web server to send a file from the filesystem to the cli-
ent rather than a response generated by the application server. Because the web
server is optimized for throwing files at the client, this usually yields a decent speed
improvement over reading the file into memory and sending it from Rails with the
send_file orsend_data API calls.


Because the web server requires access to the file in order to send it to the client, you
must use filesystem large object storage. In addition, the files to be sent must have
permissions set so as to be accessible to the web server. However, the files should be
outside of the web root, lest someone guess a filename and have free access to your
private files.


X-Sendfile uses theX-SendfileHTT Pheader pointing to the server’s path to the file
to send, in conjunction with the other standard HTT Pheaders. A typical response
using X-Sendfile would look something like this:


X-Sendfile: /home/rails/sample_application/private/secret_codes_69843.zip
Content-Type: application/octet-stream
Content-Disposition: attachment; file="secret_codes.zip"
Content-Length: 654685

Assuming the web server is properly configured, it will ignore any response body and
stream the file from disk to the client.

Free download pdf