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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
require 'cgi'
require 'oembed/http_helper'
module OEmbed
# An OEmbed::Provider has information about an individual oEmbed enpoint.
class Provider
include OEmbed::HttpHelper
# The String that is the http URI of the Provider's oEmbed endpoint.
# This URL may also contain a {{format}} portion. In actual requests to
# this Provider, this string will be replaced with a string representing
# the request format (e.g. "json").
attr_accessor :endpoint
# The name of the default format for all request to this Provider (e.g. 'json').
attr_accessor :format
# An Array of all URL schemes supported by this Provider.
attr_accessor :urls
# The human-readable name of the Provider.
#
# @deprecated *Note*: This accessor currently isn't used anywhere in the codebase.
attr_accessor :name
# @deprecated *Note*: Added in a fork of the gem, a while back. I really would like
# to get rid of it, though. --Marcos
attr_accessor :url
# Construct a new OEmbed::Provider instance, pointing at a specific oEmbed
# endpoint.
#
# The endpoint should be a String representing the http URI of the Provider's
# oEmbed endpoint. The endpoint String may also contain a {format} portion.
# In actual requests to this Provider, this string will be replaced with a String
# representing the request format (e.g. "json").
#
# If give, the format should be the name of the default format for all request
# to this Provider (e.g. 'json'). Defaults to OEmbed::Formatter.default
#
# For example:
# # If requests should be sent to:
# # "http://my.service.com/oembed?format=#{OEmbed::Formatter.default}"
# @provider = OEmbed::Provider.new("http://my.service.com/oembed")
#
# # If requests should be sent to:
# # "http://my.service.com/oembed.xml"
# @xml_provider = OEmbed::Provider.new("http://my.service.com/oembed.{format}", :xml)
def initialize(endpoint, format = OEmbed::Formatter.default)
endpoint_uri = URI.parse(endpoint.gsub(/[\{\}]/,'')) rescue nil
raise ArgumentError, "The given endpoint isn't a valid http(s) URI: #{endpoint.to_s}" unless endpoint_uri.is_a?(URI::HTTP)
@endpoint = endpoint
@urls = []
@format = format
end
# Adds the given url scheme to this Provider instance.
# The url scheme can be either a String, containing wildcards specified
# with an asterisk, (see http://oembed.com/#section2.1 for details),
# or a Regexp.
#
# For example:
# @provider << "http://my.service.com/video/*"
# @provider << "http://*.service.com/photo/*/slideshow"
# @provider << %r{^http://my.service.com/((help)|(faq))/\d+[#\?].*}
def <<(url)
if !url.is_a?(Regexp)
full, scheme, domain, path = *url.match(%r{([^:]*)://?([^/?]*)(.*)})
domain = Regexp.escape(domain).gsub("\\*", "(.*?)").gsub("(.*?)\\.", "([^\\.]+\\.)?")
path = Regexp.escape(path).gsub("\\*", "(.*?)")
url = Regexp.new("^#{Regexp.escape(scheme)}://#{domain}#{path}")
end
@urls << url
end
# Send a request to the Provider endpoint to get information about the
# given url and return the appropriate OEmbed::Response.
#
# The query parameter should be a Hash of values which will be
# sent as query parameters in this request to the Provider endpoint. The
# following special cases apply to the query Hash:
# :timeout:: specifies the timeout (in seconds) for the http request.
# :format:: overrides this Provider's default request format.
# :url:: will be ignored, replaced by the url param.
# :max_redirects:: the number of times this request will follow 3XX redirects before throwing an error. Default: 4
def get(url, query = {})
query[:format] ||= @format
OEmbed::Response.create_for(raw(url, query), self, url, query[:format].to_s)
end
# Determine whether the given url is supported by this Provider by matching
# against the Provider's URL schemes.
def include?(url)
@urls.empty? || !!@urls.detect{ |u| u =~ url }
end
# @deprecated *Note*: This method will be made private in the future.
def build(url, query = {})
raise OEmbed::NotFound, url unless include?(url)
query = query.merge({:url => ::CGI.escape(url)})
query.delete(:timeout)
query.delete(:max_redirects)
# TODO: move this code exclusively into the get method, once build is private.
this_format = (query[:format] ||= @format.to_s).to_s
endpoint = @endpoint.clone
if endpoint.include?("{format}")
endpoint["{format}"] = this_format
query.delete(:format)
end
base = endpoint.include?('?') ? '&' : '?'
query = base + query.inject("") do |memo, (key, value)|
"#{key}=#{value}&#{memo}"
end.chop
URI.parse(endpoint + query).instance_eval do
@format = this_format
def format
@format
end
self
end
end
# @deprecated *Note*: This method will be made private in the future.
def raw(url, query = {})
uri = build(url, query)
http_get(uri, query)
rescue OEmbed::UnknownFormat
# raise with format to be backward compatible
raise OEmbed::UnknownFormat, format
end
end
end
|