When developing a website which deals with digital media such as E-Books, MP3s, Videos etc. you often need to be able to restrict access to these files only to users who have authenticated somehow. There are a few different approaches to solving this problem, but I've recently come across what I consider to be the simplest and most efficient way, and since it took me a while to actually find it, I thought I would document it here in hopes that I can save someone some googling time in the future.
The key to this solution is the X-SendFile header, which was originally developed for lighttpd, however an apache2 module is available as well. Installation of the module is beyond the scope of this blog post, but its a very straight forward process, and there is even a nice .deb package to make the process even easier on a debian or ubuntu host.
Once the module is installed, configuration is a snap. The module has 2 config options:
- XSendFile on|off - Enable or disable processing of the X-SendFile header.
- XSendFileAllowAbove on|off - Enable or disable serving files above the requested URI
The way the X-sendfile header works is so simple its brilliant, the application returns an HttpResponse which has the X-SendFile header pointing to a file on the local filesystem. When apache is returning this response to the user, it notices this header, and will serve the specified file instead of the body of the original response, so the trick is to make the file otherwise inaccessible to the user, but as long as the apache process has read access to the file, it will be able to serve it up via this directive.
a simple django view which serves up a pdf file only to authenticated users:
@login_required def get_pdf(request, id): pdf = get_object_or_404(Pdf, pk=id) response = HttpResponse() response['X-SendFile'] = pdf.file.path #The full path to the attached file. response['Content-Type'] = 'application/pdf' return response
in this example the file is only available if the user has logged in, but we can do any logic we want before deciding whether or not to grant access to the file.
There are other ways to accomplish this, such as having your application read the file from the filesystem and return it to the user, but that ties up the python threads and uses a lot of extra memory. Apache, lighty, and other web servers are much more efficient at serving static files, so we really want to let them handle it and free up the resources for more dynamic page requests.
RSS
2009 March 29, 9:58 AM