class Shrine::DownloadEndpoint

Routes incoming requests. It first asserts that the storage is existent and allowed. Afterwards it proceeds with the file download using streaming.

Public Class Methods

new(options) click to toggle source

Writes given options to instance variables.

# File lib/shrine/plugins/download_endpoint.rb, line 101
def initialize(options)
  options.each do |name, value|
    instance_variable_set("@#{name}", value)
  end
end

Public Instance Methods

call(env) click to toggle source
# File lib/shrine/plugins/download_endpoint.rb, line 107
def call(env)
  request = Rack::Request.new(env)

  status, headers, body = catch(:halt) do
    error!(405, "Method Not Allowed") unless request.get?

    handle_request(request)
  end

  headers = Rack::Headers[headers] if Rack.release >= "3"
  headers["Content-Length"] ||= body.respond_to?(:bytesize) ? body.bytesize.to_s :
                                                              body.map(&:bytesize).inject(0, :+).to_s

  [status, headers, body]
end
inspect() click to toggle source
# File lib/shrine/plugins/download_endpoint.rb, line 123
def inspect
  "#<#{@shrine_class}::DownloadEndpoint>"
end
Also aliased as: to_s
to_s()
Alias for: inspect

Private Instance Methods

bad_request!(message) click to toggle source
# File lib/shrine/plugins/download_endpoint.rb, line 196
def bad_request!(message)
  error!(400, message)
end
error!(status, message) click to toggle source

Halts the request with the error message.

# File lib/shrine/plugins/download_endpoint.rb, line 201
def error!(status, message)
  throw :halt, [status, { "Content-Type" => "text/plain" }, [message]]
end
get_uploaded_file(serialized) click to toggle source

Deserializes a Shrine::UploadedFile from a URL component. Returns 404 if storage is not found.

# File lib/shrine/plugins/download_endpoint.rb, line 183
def get_uploaded_file(serialized)
  @shrine_class::UploadedFile.urlsafe_load(serialized)
rescue Shrine::Error # storage not found
  not_found!
rescue JSON::ParserError, ArgumentError => error # invalid serialized component
  raise if error.is_a?(ArgumentError) && error.message != "invalid base64"
  bad_request!("Invalid serialized file")
end
handle_request(request) click to toggle source
# File lib/shrine/plugins/download_endpoint.rb, line 130
def handle_request(request)
  _, serialized, * = request.path_info.split("/")

  uploaded_file = get_uploaded_file(serialized)

  serve_file(uploaded_file, request)
end
not_found!() click to toggle source
# File lib/shrine/plugins/download_endpoint.rb, line 192
def not_found!
  error!(404, "File Not Found")
end
open_file(uploaded_file, request) click to toggle source
# File lib/shrine/plugins/download_endpoint.rb, line 172
def open_file(uploaded_file, request)
  download_options = @download_options
  download_options = download_options.call(uploaded_file, request) if download_options.respond_to?(:call)

  uploaded_file.open(**download_options)
rescue Shrine::FileNotFound
  not_found!
end
redirect_to_file(uploaded_file, request) click to toggle source

Redirects to the uploaded file’s direct URL or the specified URL proc.

# File lib/shrine/plugins/download_endpoint.rb, line 162
def redirect_to_file(uploaded_file, request)
  if @redirect == true
    redirect_url = uploaded_file.url
  else
    redirect_url = @redirect.call(uploaded_file, request)
  end

  [302, { "Location" => redirect_url }, []]
end
serve_file(uploaded_file, request) click to toggle source

Streams or redirects to the uploaded file.

# File lib/shrine/plugins/download_endpoint.rb, line 139
def serve_file(uploaded_file, request)
  if @redirect
    redirect_to_file(uploaded_file, request)
  else
    stream_file(uploaded_file, request)
  end
end
stream_file(uploaded_file, request) click to toggle source

Streams the uploaded file content.

# File lib/shrine/plugins/download_endpoint.rb, line 148
def stream_file(uploaded_file, request)
  open_file(uploaded_file, request)

  response = uploaded_file.to_rack_response(
    disposition: @disposition,
    range:       request.env["HTTP_RANGE"],
  )

  response[1]["Cache-Control"] = "max-age=#{365*24*60*60}" # cache for a year

  response
end