1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
require 'openssl'
module OEmbed
module HttpHelper
private
# Given a URI, make an HTTP request
#
# The options Hash recognizes the following keys:
# :timeout:: specifies the timeout (in seconds) for the http request.
# :max_redirects:: the number of times this request will follow 3XX redirects before throwing an error. Default: 4
def http_get(uri, options = {})
found = false
remaining_redirects = options[:max_redirects] ? options[:max_redirects].to_i : 4
scheme, host, port = uri.scheme, uri.host, uri.port
until found
http = Net::HTTP.new(host, port)
http.use_ssl = scheme == 'https'
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.read_timeout = http.open_timeout = options[:timeout] if options[:timeout]
methods = if RUBY_VERSION < "2.2"
%w{scheme userinfo host port registry}
else
%w{scheme userinfo host port}
end
methods.each { |method| uri.send("#{method}=", nil) }
req = Net::HTTP::Get.new(uri.to_s)
req['User-Agent'] = "Mozilla/5.0 (compatible; ruby-oembed/#{OEmbed::VERSION})"
res = http.request(req)
if remaining_redirects == 0
found = true
elsif res.is_a?(Net::HTTPRedirection) && res.header['location']
uri = URI.parse(res.header['location'])
# If the 'location' is a relative path, keep the last scheme, host, & port.
scheme = uri.scheme || scheme
host = uri.host || host
port = uri.port || port
remaining_redirects -= 1
else
found = true
end
end
case res
when Net::HTTPNotImplemented
raise OEmbed::UnknownFormat
when Net::HTTPNotFound
raise OEmbed::NotFound, uri
when Net::HTTPSuccess
res.body
else
raise OEmbed::UnknownResponse, res && res.respond_to?(:code) ? res.code : 'Error'
end
rescue StandardError
# Convert known errors into OEmbed::UnknownResponse for easy catching
# up the line. This is important if given a URL that doesn't support
# OEmbed. The following are known errors:
# * Net::* errors like Net::HTTPBadResponse
# * JSON::JSONError errors like JSON::ParserError
if defined?(::JSON) && $!.is_a?(::JSON::JSONError) || $!.class.to_s =~ /\ANet::/
raise OEmbed::UnknownResponse, res && res.respond_to?(:code) ? res.code : 'Error'
else
raise $!
end
end
end
end
|