class ActiveStorage::Download
Constants
- BINARY_CONTENT_TYPE
- CONTENT_TYPES_TO_RENDER_AS_BINARY
Sending .ai files as application/postscript to Safari opens them in a blank, grey screen. Downloading .ai as application/postscript files in Safari appends .ps to the extension. Sending HTML, SVG, XML and SWF files as binary closes XSS vulnerabilities. Sending JS files as binary avoids InvalidCrossOriginRequest without compromising security.
- RFC5987_PARAMETER_ESCAPED_CHAR
- TRADITIONAL_PARAMETER_ESCAPED_CHAR
Public Class Methods
new(stored_file)
click to toggle source
# File lib/active_storage/download.rb, line 19 def initialize(stored_file) @stored_file = stored_file end
Public Instance Methods
headers(force_attachment: false)
click to toggle source
# File lib/active_storage/download.rb, line 23 def headers(force_attachment: false) { x_accel_redirect: '/reproxy', x_reproxy_url: reproxy_url, content_type: content_type, content_disposition: content_disposition(force_attachment), x_frame_options: 'SAMEORIGIN' } end
Private Instance Methods
content_disposition(force_attachment = false)
click to toggle source
# File lib/active_storage/download.rb, line 46 def content_disposition(force_attachment = false) if force_attachment || content_type == BINARY_CONTENT_TYPE "attachment; #{escaped_filename}" else "inline; #{escaped_filename}" end end
content_type()
click to toggle source
# File lib/active_storage/download.rb, line 38 def content_type if @stored_file.content_type.in? CONTENT_TYPES_TO_RENDER_AS_BINARY BINARY_CONTENT_TYPE else @stored_file.content_type end end
encode_ascii_filename(filename)
click to toggle source
# File lib/active_storage/download.rb, line 66 def encode_ascii_filename(filename) # There is no reliable way to escape special or non-Latin characters # in a traditionally quoted Content-Disposition filename parameter. # Settle for transliterating to ASCII, then percent-escaping special # characters, excluding spaces. filename = I18n.transliterate(filename) filename = percent_escape(filename, TRADITIONAL_PARAMETER_ESCAPED_CHAR) %(filename="#{filename}") end
encode_utf8_filename(filename)
click to toggle source
# File lib/active_storage/download.rb, line 78 def encode_utf8_filename(filename) # RFC2231 filename parameters can simply be percent-escaped according # to RFC5987. filename = percent_escape(filename, RFC5987_PARAMETER_ESCAPED_CHAR) %(filename*=UTF-8''#{filename}) end
escaped_filename()
click to toggle source
RFC2231 encoding for UTF-8 filenames, with an ASCII fallback first for unsupported browsers (IE < 9, perhaps others?). greenbytes.de/tech/tc2231/#encoding-2231-fb
# File lib/active_storage/download.rb, line 57 def escaped_filename filename = @stored_file.filename.sanitized ascii_filename = encode_ascii_filename(filename) utf8_filename = encode_utf8_filename(filename) "#{ascii_filename}; #{utf8_filename}" end
percent_escape(string, pattern)
click to toggle source
# File lib/active_storage/download.rb, line 85 def percent_escape(string, pattern) string.gsub(pattern) do |char| char.bytes.map { |byte| "%%%02X" % byte }.join("") end end
reproxy_url()
click to toggle source
# File lib/active_storage/download.rb, line 34 def reproxy_url @stored_file.depot_location.paths.first end