class Shrine::Plugins::RackResponse::FileResponse

Attributes

file[R]

Public Class Methods

new(file) click to toggle source
# File lib/shrine/plugins/rack_response.rb, line 21
def initialize(file)
  @file = file
end

Public Instance Methods

call(**options) click to toggle source

Returns a Rack response triple for the uploaded file.

# File lib/shrine/plugins/rack_response.rb, line 26
def call(**options)
  file.open unless file.opened?

  options[:range] = parse_content_range(options[:range]) if options[:range]

  status  = rack_status(**options)
  headers = rack_headers(**options)
  body    = rack_body(**options)

  headers = Rack::Headers[headers] if Rack.release >= "3"

  [status, headers, body]
end

Private Instance Methods

accept_ranges(range) click to toggle source

Value for the “Accept-Ranges” header.

# File lib/shrine/plugins/rack_response.rb, line 87
def accept_ranges(range)
  "bytes" unless range == false
end
content_disposition(disposition, filename) click to toggle source

Value for the “Content-Disposition” header.

# File lib/shrine/plugins/rack_response.rb, line 75
def content_disposition(disposition, filename)
  filename ||= file.original_filename || file.id.split("/").last

  ContentDisposition.format(disposition: disposition, filename: filename)
end
content_length(range) click to toggle source

Value for the “Content-Length” header.

# File lib/shrine/plugins/rack_response.rb, line 64
def content_length(range)
  length = range ? range.size : file.size
  length.to_s if length
end
content_range(range) click to toggle source

Value for the “Content-Range” header.

# File lib/shrine/plugins/rack_response.rb, line 82
def content_range(range)
  "bytes #{range.begin}-#{range.end}/#{file.size}" if range
end
content_type(type) click to toggle source

Value for the “Content-Type” header.

# File lib/shrine/plugins/rack_response.rb, line 70
def content_type(type)
  type || file.mime_type || Rack::Mime.mime_type(".#{file.extension}", nil)
end
etag() click to toggle source

Value for the “ETag” header.

# File lib/shrine/plugins/rack_response.rb, line 92
def etag
  digest = Digest::SHA256.hexdigest("#{file.shrine_class}-#{file.storage_key}-#{file.id}")

  %(W/"#{digest.byteslice(0, 32)}")
end
get_byte_ranges(range_header) click to toggle source
# File lib/shrine/plugins/rack_response.rb, line 111
def get_byte_ranges(range_header)
  Rack::Utils.get_byte_ranges(range_header, file.size)
end
parse_content_range(range_header) click to toggle source

Retrieves a range value parsed from HTTP “Range” header.

# File lib/shrine/plugins/rack_response.rb, line 105
def parse_content_range(range_header)
  ranges = get_byte_ranges(range_header)
  ranges.first if ranges && ranges.one?
end
rack_body(range: nil, **) click to toggle source

Returns an object that responds to each and close, which yields contents of the file.

# File lib/shrine/plugins/rack_response.rb, line 100
def rack_body(range: nil, **)
  FileBody.new(file, range: range)
end
rack_headers(filename: nil, type: nil, disposition: "inline", range: false) click to toggle source

Returns a hash of “Content-Length”, “Content-Type” and “Content-Disposition” headers, whose values are extracted from metadata. Also returns the correct “Content-Range” header on ranged requests.

# File lib/shrine/plugins/rack_response.rb, line 52
def rack_headers(filename: nil, type: nil, disposition: "inline", range: false)
  {
    "Content-Length"      => content_length(range),
    "Content-Type"        => content_type(type),
    "Content-Disposition" => content_disposition(disposition, filename),
    "Content-Range"       => content_range(range),
    "Accept-Ranges"       => accept_ranges(range),
    "ETag"                => etag,
  }.compact
end
rack_status(range: nil, **) click to toggle source

Returns “200 OK” on full request, and “206 Partial Content” on ranged request.

# File lib/shrine/plugins/rack_response.rb, line 44
def rack_status(range: nil, **)
  range ? 206 : 200
end