require 'net/https' require 'uri' require 'cgi' # Extend the Integer class to facilitate retries of code blocks if specified exception(s) occur # see: http://blog.josh-nesbitt.net/2010/02/08/writing-contingent-ruby-code-with-retryable/ RETRYABLE_SLEEP_VALUE = 300 class Integer def tries(options={}, &block) attempts = self exception_classes = [*options[:on] || StandardError] begin # First attempt return yield rescue *exception_classes sleep RETRYABLE_SLEEP_VALUE # 2nd to n-1 attempts retry if (attempts -= 1) > 1 end # final (nth) attempt yield end end module LyberCore class Connection def Connection.get_https_connection(url) LyberCore::Log.debug("Establishing connection to #{url.host} on port #{url.port}") https = Net::HTTP.new(url.host, url.port) if(url.scheme == 'https') https.use_ssl = true LyberCore::Log.debug("Using SSL") https.cert = OpenSSL::X509::Certificate.new( File.read(LyberCore::CERT_FILE) ) LyberCore::Log.debug("Using cert file #{LyberCore::CERT_FILE}") https.key = OpenSSL::PKey::RSA.new( File.read(LyberCore::KEY_FILE), LyberCore::KEY_PASS ) LyberCore::Log.debug("Using key file #{LyberCore::KEY_FILE} with pass #{LyberCore::KEY_PASS}") https.verify_mode = OpenSSL::SSL::VERIFY_NONE LyberCore::Log.debug("https.verify_mode = #{https.verify_mode} (should eql #{OpenSSL::SSL::VERIFY_NONE})") end https end # Returns body of the HTTP response, or passes the response to the block if it's passed in # # == Required Parameters # - full_url - A string containing the full url to the resource you're trying to connect to # - method - Recognizes the following symbols which correspond to an HTTP verb. The convenience methods take care of this # :get for HTTP GET # :post for HTTP POST # :put for HTTP PUT # - body The body of your request. Can be nil if you don't have one. # # == Options # - :auth_user for basic HTTP authentication. :auth_user and :auth_password must both be set if using authentication # - :auth_password for basic HTTP authentication. :auth_user and :auth_password must both be set if using authentication # - :content_type if not passed in as an option, then it is set to 'application/xml' # # == Block # By default, this method returns the body of the response, Net::HTTPResponse.body . If you want to work with the Net::HTTPResponse # object, you can pass in a block, and the response will be passed to it. # # == Exceptions # Any exceptions thrown while trying to connect should be handled by the caller def Connection.connect(full_url, method, body, options = {}, &block) url = URI.parse(full_url) case method when :get req = Net::HTTP::Get.new(url.request_uri) when :post req = Net::HTTP::Post.new(url.request_uri) when :put req = Net::HTTP::Put.new(url.request_uri) end req.body = body unless(body.nil?) if(options.include?(:content_type)) req.content_type = options[:content_type] else req.content_type = 'application/xml' end if(options.include?(:auth_user)) req.basic_auth options[:auth_user], options[:auth_password] end res = Connection.send_request(url, req) case res when Net::HTTPSuccess if(block_given?) block.call(res) else return res.body end else raise res.error! # ??? raise LyberCore::Exceptions::ServiceError.new('HTTP Request failed',res.error!) end end # Send the request to the server, with multiple retries if specified exceptions occur def Connection.send_request(url, req) 3.tries :on => [Timeout::Error, EOFError, Errno::ECONNRESET] do Connection.get_https_connection(url).start {|http| http.request(req) } end rescue Exception => e raise LyberCore::Exceptions::ServiceError.new('HTTP Request failed',e) end end # Convenience method for performing an HTTP GET using Connection.connect def Connection.get(full_url, options = {}, &b) Connection.connect(full_url, :get, nil, options, &b) end # Convenience method for performing an HTTP POST using Connection.connect def Connection.post(full_url, body, options = {}, &b) Connection.connect(full_url, :post, body, options, &b) end # Convenience method for performing an HTTP PUT using Connection.connect def Connection.put(full_url, body, options = {}, &b) Connection.connect(full_url, :put, body, options, &b) end end