class ImagePlaceholder::Middleware

Public Class Methods

new(app, image_extensions: %w(jpg png), size_pattern: {/.*/ => 100}, host: 'via.placeholder.com') click to toggle source
# File lib/image_placeholder/middleware.rb, line 5
def initialize(app, image_extensions: %w(jpg png), size_pattern: {/.*/ => 100}, host: 'via.placeholder.com')
  @app = app
  @image_extensions = image_extensions
  @size_pattern = size_pattern
  @host = host
end

Public Instance Methods

call(env) click to toggle source
# File lib/image_placeholder/middleware.rb, line 12
def call(env)
  status, headers, response = @app.call(env)
  request_path = URI.decode(Rack::Request.new(env).fullpath)

  if not_found?(status) && image?(request_path)
    serve_placeholder_image(matched_size(request_path))
  else
    [status, headers, response]
  end
end

Private Instance Methods

hop_by_hop_header_fields() click to toggle source
# File lib/image_placeholder/middleware.rb, line 40
def hop_by_hop_header_fields
  # https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.3.1
  %w(connection keep-alive proxy-authenticate proxy-authorization te trailer transfer-encoding upgrade)
end
image?(path) click to toggle source
# File lib/image_placeholder/middleware.rb, line 49
def image?(path)
  @image_extensions.include? File.extname(path)[1, 3]
end
matched_size(path) click to toggle source
# File lib/image_placeholder/middleware.rb, line 53
def matched_size(path)
  @size_pattern.find { |pattern, _| pattern.match(path) }[1]
end
not_found?(status) click to toggle source
# File lib/image_placeholder/middleware.rb, line 45
def not_found?(status)
  status == 404
end
serve_placeholder_image(size = 100) click to toggle source
# File lib/image_placeholder/middleware.rb, line 25
def serve_placeholder_image(size = 100)
  net_response  = Net::HTTP.get_response(URI("https://#{@host}/#{size}"))
  rack_response = Rack::Response.new(net_response.body, net_response.code.to_i)
  safe_headers  = net_response.to_hash
                    .reject { |key, _| hop_by_hop_header_fields.include?(key.downcase) }
                    .reject { |key, _| key.downcase == 'content-length' }

  safe_headers.each do |key, values|
    values.each do |value|
      rack_response.add_header(key, value)
    end
  end
  rack_response.finish
end