Class: Videojuicer::OAuth::RequestProxy
- Includes:
- Configurable, Exceptions
- Defined in:
- lib/videojuicer/oauth/request_proxy.rb
Constant Summary collapse
- EXCLUDED_BASE_STRING_PORTS =
Requests to the following ports will not include the port in the signature base string. See OAuth spec 1.0a section 9.1.2 for details.
[80, 443].freeze
- TIMEOUT =
allow Net::HTTP requests to take up to 5 minutes
60 * 5
Instance Attribute Summary
Attributes included from Configurable
Instance Method Summary collapse
-
#authified_query_string(method, path, params = {}) ⇒ Object
Authifies the given parameters and converts them into a query string.
-
#authify_params(method, path, params) ⇒ Object
Takes a set of business parameters you want sent to the provider, and merges them with the proxy configuration to produce a set of parameters that will be accepted by the OAuth provider.
-
#delete(path, params = {}) ⇒ Object
Makes a DELETE request given path and params.
- #flatten_params(params, *hash_path) ⇒ Object
-
#get(path, params = {}) ⇒ Object
Makes a GET request given path and params.
-
#handle_response(response, request) ⇒ Object
Handles an HTTPResponse object appropriately.
- #host_stub(_protocol = protocol, _host = host, _port = port) ⇒ Object
-
#initialize(options = {}) ⇒ RequestProxy
constructor
Initializes a new RequestProxy object which can be used to make requests.
-
#make_request(method, host, port, path, params = {}) ⇒ Object
Does the actual work of making a request.
-
#normalize_params(params, *hash_path) ⇒ Object
Returns a string representing a normalised parameter hash.
-
#post(path, params = {}) ⇒ Object
Makes a POST request given path and params.
-
#put(path, params = {}) ⇒ Object
Makes a PUT request given path and params.
-
#request_class_for_method(m, in_module = Net::HTTP) ⇒ Object
Returns the Net::HTTPRequest subclass needed to make a request for the given method.
-
#response_error(exception_klass, request, response) ⇒ Object
Handles the response as an error of the desired type.
-
#signature(method, path, params) ⇒ Object
Calculates and returns the encrypted signature for this proxy object and the given request properties.
-
#signature_base_string(method, path, params) ⇒ Object
Returns the unencrypted signature base string for this proxy object and the given request properties.
- #signature_base_string_host ⇒ Object
-
#signature_secret ⇒ Object
Calculates and returns the signature secret to be used for this proxy object.
- #signed_url(method, path, params = {}) ⇒ Object
-
#split_by_signature_eligibility(params, *hash_path) ⇒ Object
Splits a given parameter hash into two hashes - one containing all string and non-binary parameters, and one containing all file/binary parameters.
Methods included from Configurable
#api_version, #config, #configure!, #consumer_key, #consumer_secret, #host, #port, #protocol, #scope, #seed_name, #token, #token_secret, #user_id
Constructor Details
#initialize(options = {}) ⇒ RequestProxy
Initializes a new RequestProxy object which can be used to make requests. Accepts all the same options as Videojuicer::configure! as well as: token
- The OAuth token to use in requests made through this proxy. token_secret
- The OAuth token secret to use when encrypting the request signature.
35 36 37 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 35 def initialize(={}) configure!() end |
Instance Method Details
#authified_query_string(method, path, params = {}) ⇒ Object
Authifies the given parameters and converts them into a query string.
201 202 203 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 201 def authified_query_string(method, path, params={}) normalize_params(authify_params(method, path, params)) end |
#authify_params(method, path, params) ⇒ Object
Takes a set of business parameters you want sent to the provider, and merges them with the proxy configuration to produce a set of parameters that will be accepted by the OAuth provider.
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 208 def authify_params(method, path, params) defaults = { :oauth_consumer_key=>consumer_key, :oauth_token=>token, :api_version=>api_version, :oauth_timestamp=>Time.now.to_i, :oauth_nonce=>rand(9999), :oauth_signature_method=>"HMAC-SHA1", :seed_name=>seed_name, :user_id=>user_id } defaults.delete_if {|k,v| (!v) or (v.to_s.empty?) } params = defaults.merge(params) params[:oauth_signature] = signature(method, path, params) return params end |
#delete(path, params = {}) ⇒ Object
Makes a DELETE request given path and params. The host will be ascertained from the configuration options.
53 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 53 def delete(path, params={}); make_request(:delete, host, port, path, params); end |
#flatten_params(params, *hash_path) ⇒ Object
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 262 def flatten_params(params, *hash_path) op = {} params.sort {|a,b| a.to_s<=>b.to_s}.each do |key, value| path = hash_path.dup path << key.to_s if value.is_a?(Hash) op.merge! flatten_params(value, *path) elsif value key_path = path.first + path[1..(path.length-1)].collect {|h| "[#{h}]"}.join("") op[key_path] = value end end return op end |
#get(path, params = {}) ⇒ Object
Makes a GET request given path and params. The host will be ascertained from the configuration options.
41 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 41 def get(path, params={}); make_request(:get, host, port, path, params); end |
#handle_response(response, request) ⇒ Object
Handles an HTTPResponse object appropriately. Redirects are followed, error states raise errors and success responses are returned directly.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 119 def handle_response(response, request) c = response.code.to_i case c when 200..399 # Successful or redirected response response when 409 # Not ready but still successful response when 415 # Validation error response when 401 # Authentication problem response_error Unauthenticated, request, response when 403 # Attempted to perform a forbidden action response_error Forbidden, request, response when 404 # Resource URL not valid response_error NoResource, request, response when 406 # Excuse me WTF r u doin response_error NotAcceptable, request, response when 411 # App-side server error where request is not properly constructed. response_error ContentLengthRequired, request, response when 500..600 # Remote application failure response_error RemoteApplicationError, request, response else response_error UnhandledHTTPStatus, request, response end end |
#host_stub(_protocol = protocol, _host = host, _port = port) ⇒ Object
113 114 115 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 113 def host_stub(_protocol=protocol, _host=host, _port=port) "#{_protocol}://#{_host}:#{_port}" end |
#make_request(method, host, port, path, params = {}) ⇒ Object
Does the actual work of making a request. Returns a Net::HTTPResponse object.
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 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 56 def make_request(method, host, port, path, params={}) # Strip the files from the parameters to determine what, from the whole bundle, needs signing signature_params, multipart_params = split_by_signature_eligibility(params) query_string = nil if multipart_params.any? # Sign the params and include the as multipart multipart_params = flatten_params( authify_params(method, path, signature_params).deep_merge(multipart_params) ) else # Use the query string query_string = authified_query_string(method, path, signature_params) end uri = Addressable::URI.new( :scheme => protocol, :host => host, :port => port, :path => path, :query => query_string ) klass = request_class_for_method(method) if multipart_params.any? request = klass::Multipart.new( uri.request_uri, Videojuicer::OAuth::Multipart.new(multipart_params) ) else request = klass.new(uri.request_uri) case method when :post, :put # Send a content-length on POST and PUT to avoid an HTTP 411 response query_string = uri.query.to_s request = klass.new(uri.path) request.content_type = 'application/x-www-form-urlencoded' request.content_length = query_string.length request.body = query_string end end response = Net::HTTP.start(uri.host, uri.port) do |http| http.read_timeout = TIMEOUT http.request(request) end handle_response(response, request) rescue EOFError => e raise "EOF error when accessing #{uri.inspect}" rescue Errno::ECONNREFUSED => e raise "Could not connect to #{uri.inspect}" end |
#normalize_params(params, *hash_path) ⇒ Object
258 259 260 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 258 def normalize_params(params, *hash_path) flatten_params(params).sort {|a,b| a.to_s <=> b.to_s}.collect {|k, v| "#{CGI.rfc3986_escape(k)}=#{CGI.rfc3986_escape(v.to_s)}" }.join("&") end |
#post(path, params = {}) ⇒ Object
Makes a POST request given path and params. The host will be ascertained from the configuration options.
45 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 45 def post(path, params={}); make_request(:post, host, port, path, params); end |
#put(path, params = {}) ⇒ Object
Makes a PUT request given path and params. The host will be ascertained from the configuration options.
49 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 49 def put(path, params={}); make_request(:put, host, port, path, params); end |
#request_class_for_method(m, in_module = Net::HTTP) ⇒ Object
Returns the Net::HTTPRequest subclass needed to make a request for the given method.
279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 279 def request_class_for_method(m, in_module=Net::HTTP) case (m.is_a?(Symbol) ? m : m.downcase.to_sym rescue :get) when :post in_module::Post when :put in_module::Put when :head in_module::Head when :delete in_module::Delete else in_module::Get end end |
#response_error(exception_klass, request, response) ⇒ Object
Handles the response as an error of the desired type.
155 156 157 158 159 160 161 162 163 164 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 155 def response_error(exception_klass, request, response) begin e = JSON.parse(response.body) e = e["error"] raise exception_klass, "#{e["message"]} || 'an error has occurred, vj-core did not provide sufficient data to handle it properly' \n #{(e["backtrace"] || []).join("\n")}" rescue JSON::ParserError raise exception_klass, "#{exception_klass.to_s} : Response code was #{response.code} for request: #{request.path}" end end |
#signature(method, path, params) ⇒ Object
Calculates and returns the encrypted signature for this proxy object and the given request properties.
227 228 229 230 231 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 227 def signature(method, path, params) base = signature_base_string(method, path, params) signature_octet = HMAC::SHA1.digest(signature_secret, base) signature_base64 = [signature_octet].pack('m').chomp.gsub(/\n/, '') end |
#signature_base_string(method, path, params) ⇒ Object
Returns the unencrypted signature base string for this proxy object and the given request properties.
240 241 242 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 240 def signature_base_string(method, path, params) s = [method.to_s.upcase, "#{protocol}://#{signature_base_string_host}#{path}", normalize_params(params)].collect {|e| CGI.rfc3986_escape(e)}.join("&") end |
#signature_base_string_host ⇒ Object
244 245 246 247 248 249 250 251 252 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 244 def signature_base_string_host if EXCLUDED_BASE_STRING_PORTS.include?(port.to_i) # Natural port. Ignore the port host else # Weird port. Expect a signature. "#{host}:#{port}" end end |
#signature_secret ⇒ Object
Calculates and returns the signature secret to be used for this proxy object.
234 235 236 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 234 def signature_secret [consumer_secret, token_secret].collect {|e| CGI.rfc3986_escape(e.to_s)}.join("&") end |
#signed_url(method, path, params = {}) ⇒ Object
196 197 198 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 196 def signed_url(method, path, params={}) "#{protocol}://#{host}:#{port}#{path}?#{authified_query_string(method, path, params)}" end |
#split_by_signature_eligibility(params, *hash_path) ⇒ Object
Splits a given parameter hash into two hashes - one containing all string and non-binary parameters, and one containing all file/binary parameters. This action is performed recursively so that:
params = {:user=>{:attributes=>{:file=>some_file, :name=>"user name"}}, :foo=>"bar"}
normal, multipart = split_multipart_params(params)
normal.inspect # => {:user=>{:attributes=>{:name=>"user name"}}, :foo=>"bar"}
multipart.inspect # => {:user=>{:attributes=>{:file=>some_file}}}
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/videojuicer/oauth/request_proxy.rb', line 173 def split_by_signature_eligibility(params, *hash_path) strings = {} files = {} params.each do |key, value| if value.is_a?(Hash) # Call recursively s, f = split_by_signature_eligibility(value, *(hash_path+[key])) strings = strings.deep_merge(s) files = files.deep_merge(f) else # Insert it into files at the current key path if it is a binary, # and into strings if it is not. pwd = (value.respond_to?(:read))? files : strings hash_path.each do |component| pwd[component] ||= {} pwd = pwd[component] end pwd[key] = value end end return strings, files end |