[Rails] send_file problem
Duzenbury, Rich
rduzenbury at BILtd.com
Tue Aug 8 20:53:27 GMT 2006
>
> I'm attempting to use send_file to send an image file from
> public/images. The file is world readable.
>
> I've tried supplying the full path, but it still can't seem to find
the
> file. Here is the code that calls send_file:
I don't think I would do this on purpose, if the image is really in
public. If you want to change the image name at run time, I would
instead generate an <img> tag in the view, which the browser will then
download (per the setting of the user).
Otherwise, if you wish to send content that is *not* inside your web
(e.g. in /public or below) then you might do something like:
Config/routes.rb
# Force all requests for /protected/whatever to the render_static
method.
# Static content control
map.connect '/protected/*path', :controller => 'protected',
:action => 'render_static'
def render_static
# see routes.rb. A map is made so that the URL is
# visible as params[:path]
requested_file = params[:path].to_s
safe, opf = safe_to_send?(requested_file)
if safe
# compute the mime type and send the content here
# This should be made much more concise (a hash lookup)
# and extended to cover more mime types
if requested_file =~ /\.pdf$/ then
apptype = "application/pdf"
elsif requested_file =~ /\.ppt$/ then
apptype = 'application/vnd.ms-powerpoint'
elsif requested_file =~ /\.swf$/ then
apptype = 'application/x-shockwave-flash'
else
apptype = 'octet/stream'
end
send_file opf, :type=> apptype, :disposition=> "inline"
end
end
protected
def safe_to_send?(requested_file)
# Absolute file location. Beware that funny business with RAILS
ROOT
# (e.g. symbolic links) could throw this off
output_base = File.expand_path RAILS_ROOT
output_file = File.expand_path output_base + '/secret/' +
requested_file
# Attempt to foil directory traversal attacks
# make sure that output base is the beginning portion of output_file
# I *think* rails makes this check unnecessary, but hey...
result = false
if output_file.index(output_base) == 0 and File.exists?(output_file)
result = true
end
return result, output_file
end
Note that I'm being paranoid about traversal attacks. I believe rails
already deals with all of the . and .. stuff when the URL is submitted
by the browser, however, I could be wrong.
In this case, the protected content is in a subdirectory called
'secret', which is one level below the main root of the rails app.
Regards,
Rich
More information about the Rails
mailing list