lib/amazon/ecs.rb in amazon-ecs-0.5.4 vs lib/amazon/ecs.rb in amazon-ecs-0.5.5

- old
+ new

@@ -1,7 +1,7 @@ #-- -# Copyright (c) 2006 Herryanto Siatono, Pluit Solutions +# Copyright (c) 2009 Herryanto Siatono, Pluit Solutions # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, @@ -22,24 +22,30 @@ #++ require 'net/http' require 'hpricot' require 'cgi' +require 'hmac-sha2' +require 'base64' module Amazon class RequestError < StandardError; end class Ecs - SERVICE_URLS = {:us => 'http://webservices.amazon.com/onca/xml?Service=AWSECommerceService', - :uk => 'http://webservices.amazon.co.uk/onca/xml?Service=AWSECommerceService', - :ca => 'http://webservices.amazon.ca/onca/xml?Service=AWSECommerceService', - :de => 'http://webservices.amazon.de/onca/xml?Service=AWSECommerceService', - :jp => 'http://webservices.amazon.co.jp/onca/xml?Service=AWSECommerceService', - :fr => 'http://webservices.amazon.fr/onca/xml?Service=AWSECommerceService' + SERVICE_URLS = {:us => 'http://webservices.amazon.com/onca/xml?', + :uk => 'http://webservices.amazon.co.uk/onca/xml?', + :ca => 'http://webservices.amazon.ca/onca/xml?', + :de => 'http://webservices.amazon.de/onca/xml?', + :jp => 'http://webservices.amazon.co.jp/onca/xml?', + :fr => 'http://webservices.amazon.fr/onca/xml?' } - @@options = {} + @@options = { + :version => "2009-01-06", + :service => "AWSECommerceService" + } + @@debug = false # Default search options def self.options @@options @@ -90,10 +96,14 @@ end # Generic send request to ECS REST service. You have to specify the :operation parameter. def self.send_request(opts) opts = self.options.merge(opts) if self.options + + # Include other required options + opts[:timestamp] = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ") + request_url = prepare_url(opts) log "Request URL: #{request_url}" res = Net::HTTP.get_response(URI::parse(request_url)) unless res.kind_of? Net::HTTPSuccess @@ -188,22 +198,42 @@ def self.prepare_url(opts) country = opts.delete(:country) country = (country.nil?) ? 'us' : country request_url = SERVICE_URLS[country.to_sym] raise Amazon::RequestError, "Invalid country '#{country}'" unless request_url + + secret_key = opts.delete(:aWS_secret_key) + request_host = URI.parse(request_url).host qs = '' - opts.each {|k,v| - next unless v - v = v.join(',') if v.is_a? Array - qs << "&#{camelize(k.to_s)}=#{URI.encode(v.to_s)}" + opts.collect {|a,b| [camelize(a.to_s), b.to_s] }.sort {|c,d| c[0].to_s <=> d[0].to_s}.each {|e| + log "Adding #{e[0]}=#{e[1]}" + next unless e[1] + e[1] = e[1].join(',') if e[1].is_a? Array + v=URI.encode(e[1].to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")) + qs << "&" unless qs.length == 0 + qs << "#{e[0]}=#{v}" } - "#{request_url}#{qs}" + + signature = '' + unless secret_key.nil? + request_to_sign="GET\n#{request_host}\n/onca/xml\n#{qs}" + signature = "&Signature=#{sign_request(request_to_sign, secret_key)}" + end + + "#{request_url}#{qs}#{signature}" end def self.camelize(s) s.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase } end + + def self.sign_request(url, key) + return nil if key.nil? + signature = URI.escape( Base64.encode64( HMAC::SHA256.digest(key, url) ).strip, Regexp.new("[+=]") ) + return signature + end + end # Internal wrapper class to provide convenient method to access Hpricot element value. class Element # Pass Hpricot::Elements object \ No newline at end of file