File: C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/roadie-4.0.0/lib/roadie/net_http_provider.rb
# frozen_string_literal: true
require 'set'
require 'uri'
require 'net/http'
module Roadie
# @api public
# External asset provider that downloads stylesheets from some other server
# using Ruby's built-in {Net::HTTP} library.
#
# You can pass a whitelist of hosts that downloads are allowed on.
#
# @example Allowing all downloads
# provider = Roadie::NetHttpProvider.new
#
# @example Only allowing your own app domains
# provider = Roadie::NetHttpProvider.new(
# whitelist: ["myapp.com", "assets.myapp.com", "www.myapp.com"]
# )
class NetHttpProvider
attr_reader :whitelist
# @option options [Array<String>] :whitelist ([]) A list of host names that downloads are allowed from. Empty set means everything is allowed.
def initialize(options = {})
@whitelist = host_set(Array(options.fetch(:whitelist, [])))
end
def find_stylesheet(url)
find_stylesheet!(url)
rescue CssNotFound
nil
end
def find_stylesheet!(url)
response = download(url)
if response.kind_of? Net::HTTPSuccess
Stylesheet.new(url, response_body(response))
else
raise CssNotFound.new(url, "Server returned #{response.code}: #{truncate response.body}", self)
end
rescue Timeout::Error
raise CssNotFound.new(url, "Timeout", self)
end
def to_s() inspect end
def inspect() "#<#{self.class} whitelist: #{whitelist.inspect}>" end
private
def host_set(hosts)
hosts.each { |host| validate_host(host) }.to_set
end
def validate_host(host)
if host.nil? || host.empty? || host == "." || host.include?("/")
raise ArgumentError, "#{host.inspect} is not a valid hostname"
end
end
def download(url)
url = "https:#{url}" if url.start_with?("//")
uri = URI.parse(url)
if access_granted_to?(uri.host)
get_response(uri)
else
raise CssNotFound.new(url, "#{uri.host} is not part of whitelist!", self)
end
end
def get_response(uri)
if RUBY_VERSION >= "2.0.0"
Net::HTTP.get_response(uri)
else
Net::HTTP.start(uri.host, uri.port, use_ssl: (uri.scheme == 'https')) do |http|
http.request(Net::HTTP::Get.new(uri.request_uri))
end
end
end
def access_granted_to?(host)
whitelist.empty? || whitelist.include?(host)
end
def truncate(string)
if string.length > 50
string[0, 49] + "…"
else
string
end
end
def response_body(response)
# Make sure we respect encoding because Net:HTTP will encode body as ASCII by default
# which will break if the response is not compatible.
supplied_charset = response.type_params['charset']
body = response.body
if supplied_charset
body.force_encoding(supplied_charset).encode!("UTF-8")
else
# Default to UTF-8 when server does not specify encoding as that is the
# most common charset.
body.force_encoding("UTF-8")
end
end
end
end