require 'openssl' require 'base64' module Instagram # Defines HTTP request methods module Request # Perform an HTTP GET request def get(path, options={}, signature=false, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper(), signed=sign_requests) ret = nil ntry = 0 max_try = 5 begin ntry += 1 sleep 1 if ntry > 1 ret = request(:get, path, options, signature, raw, unformatted, no_response_wrapper, signed) rescue Zlib::BufError => e retry if ntry < max_try raise e rescue Faraday::ConnectionFailed => e retry if ntry < max_try raise e end ret end # Perform an HTTP POST request def post(path, options={}, signature=false, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper(), signed=sign_requests) request(:post, path, options, signature, raw, unformatted, no_response_wrapper, signed) end # Perform an HTTP PUT request def put(path, options={}, signature=false, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper(), signed=sign_requests) request(:put, path, options, signature, raw, unformatted, no_response_wrapper, signed) end # Perform an HTTP DELETE request def delete(path, options={}, signature=false, raw=false, unformatted=false, no_response_wrapper=no_response_wrapper(), signed=sign_requests) request(:delete, path, options, signature, raw, unformatted, no_response_wrapper, signed) end private # Perform an HTTP request def request(method, path, options, signature=false, raw=false, unformatted=false, no_response_wrapper=false, signed=sign_requests) response = connection(raw).send(method) do |request| path = formatted_path(path) unless unformatted if signed == true if client_id != nil sig_options = options.merge({:client_id => client_id}) end if access_token != nil sig_options = options.merge({:access_token => access_token}) end sig = generate_sig("/"+path, sig_options, client_secret) options[:sig] = sig end case method when :get, :delete request.url(URI.encode(path), options) when :post, :put request.path = URI.encode(path) request.body = options unless options.empty? end if signature && client_ips != nil request.headers["X-Insta-Forwarded-For"] = get_insta_fowarded_for(client_ips, client_secret) end end return response if raw return response.body if no_response_wrapper return Response.create( response.body, {:limit => response.headers['x-ratelimit-limit'].to_i, :remaining => response.headers['x-ratelimit-remaining'].to_i} ) end def formatted_path(path) [path, format].compact.join('.') end def get_insta_fowarded_for(ips, secret) digest = OpenSSL::Digest.new('sha256') signature = OpenSSL::HMAC.hexdigest(digest, secret, ips) return [ips, signature].join('|') end def generate_sig(endpoint, params, secret) sig = endpoint params = params.sort_by{|c|c[0].to_s} params.map do |key, val| sig += '|%s=%s' % [key, val] end digest = OpenSSL::Digest.new('sha256') return OpenSSL::HMAC.hexdigest(digest, secret, sig) end end end