Permalink
Browse files

Use to_path instead of to_file in X-Sendfile middleware

  • Loading branch information...
1 parent d42fac0 commit 1e2134aaec864afa39de912ff32c02563b18574e @rtomayko rtomayko committed Dec 9, 2008
Showing with 46 additions and 19 deletions.
  1. +42 −15 lib/rack/sendfile.rb
  2. +4 −4 test/spec_rack_sendfile.rb
View
@@ -2,21 +2,34 @@
module Rack
class File #:nodoc:
- alias :to_file :path
+ alias :to_path :path
end
# = Sendfile
#
# The Sendfile middleware intercepts responses whose body is being
# served from a file and replaces it with a server specific X-Sendfile
- # header.
- #
- # When the response body responds to +to_file+ and the request includes
- # an X-Sendfile-Type header.
+ # header. The web server is then responsible for writing the file contents
+ # to the client. This can dramatically reduce the amount of work required
+ # by the Ruby backend and takes advantage of the web servers optimized file
+ # delivery code.
+ #
+ # In order to take advantage of this middleware, the response body must
+ # respond to +to_path+ and the request must include an X-Sendfile-Type
+ # header. Rack::File and other components implement +to_path+ so there's
+ # rarely anything you need to do in your application. The X-Sendfile-Type
+ # header is typically set in your web servers configuration. The following
+ # sections attempt to document
#
# === Nginx
#
- # Nginx supports the X-Accel-Redirect header.
+ # Nginx supports the X-Accel-Redirect header. This is similar to X-Sendfile
+ # but requires parts of the filesystem to be mapped into a private URL
+ # hierarachy.
+ #
+ # The following example shows the Nginx configuration required to create
+ # a private "/files/" area, enable X-Accel-Redirect, and pass the special
+ # X-Sendfile-Type and X-Accel-Mapping headers to the backend:
#
# location /files/ {
# internal;
@@ -36,12 +49,19 @@ class File #:nodoc:
# proxy_pass http://127.0.0.1:8080/;
# }
#
- # http://wiki.codemongers.com/NginxXSendfile
+ # Note that the X-Sendfile-Type header must be set exactly as shown above. The
+ # X-Accel-Mapping header should specify the name of the private URL pattern,
+ # followed by an equals sign (=), followed by the location on the file system
+ # that it maps to. The middleware performs a simple substitution on the
+ # resulting path.
+ #
+ # See Also: http://wiki.codemongers.com/NginxXSendfile
#
# === lighttpd
#
# Lighttpd has supported some variation of the X-Sendfile header for some
- # time. The following example
+ # time, although only recent version support X-Sendfile in a reverse proxy
+ # configuration.
#
# $HTTP["host"] == "example.com" {
# proxy-core.protocol = "http"
@@ -58,13 +78,20 @@ class File #:nodoc:
# )
# }
#
- # http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModProxyCore
+ # See Also: http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModProxyCore
#
# === Apache
#
- # XSendFile on
+ # X-Sendfile is supported under Apache 2.x using a separate module:
#
# http://tn123.ath.cx/mod_xsendfile/
+ #
+ # Once the module is compiled and installed, you can enable it using
+ # XSendFile config directive:
+ #
+ # RequestHeader Set X-Sendfile-Type X-Sendfile
+ # ProxyPassReverse / http://localhost:8001/
+ # XSendFile on
class Sendfile
F = ::File
@@ -76,19 +103,19 @@ def initialize(app, variation=nil)
def call(env)
status, headers, body = @app.call(env)
- if body.respond_to?(:to_file)
+ if body.respond_to?(:to_path)
case type = variation(env)
when 'X-Accel-Redirect'
- file = F.expand_path(body.to_file)
- if url = map_accel_path(env, file)
+ path = F.expand_path(body.to_path)
+ if url = map_accel_path(env, path)
headers[type] = url
body = []
else
env['rack.errors'] << "X-Accel-Mapping header missing"
end
when 'X-Sendfile', 'X-Lighttpd-Send-File'
- file = F.expand_path(body.to_file)
- headers[type] = file
+ path = F.expand_path(body.to_path)
+ headers[type] = path
body = []
when '', nil
else
@@ -2,15 +2,15 @@
require 'rack/sendfile'
context "Rack::File" do
- specify "should respond to #to_file" do
- Rack::File.new(Dir.pwd).should.respond_to :to_file
+ specify "should respond to #to_path" do
+ Rack::File.new(Dir.pwd).should.respond_to :to_path
end
end
context "Rack::Sendfile" do
def sendfile_body
res = ['Hello World']
- def res.to_file ; "/tmp/hello.txt" ; end
+ def res.to_path ; "/tmp/hello.txt" ; end
res
end
@@ -75,7 +75,7 @@ def request(headers={})
end
end
- specify 'does nothing when body does not respond to #to_file' do
+ specify 'does nothing when body does not respond to #to_path' do
@request = Rack::MockRequest.new(sendfile_app(['Not a file...']))
request 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' do |response|
response.body.should.equal 'Not a file...'

0 comments on commit 1e2134a

Please sign in to comment.