require "net/http" require "net/https" require "cgi" require "openssl" # This module contains a set of utility methods related to the HTTP protocol. module OmniContacts module HTTPUtils SSL_PORT = 443 module_function def query_string_to_map query_string query_string.split('&').reduce({}) do |memo, key_value| (key, value) = key_value.split('=') memo[key]= value memo end end def to_query_string map map.collect do |key, value| key.to_s + "=" + value.to_s end.join("&") end # Encodes the given input according to RFC 3986 def encode to_encode CGI.escape(to_encode) end # Calculates the url of the host from a Rack environment. # The result is in the form scheme://host:port # If port is 80 the result is scheme://host # According to Rack specification the HTTP_HOST variable is preferred over SERVER_NAME. def host_url_from_rack_env env port = ((env["SERVER_PORT"] == 80) && "") || ":#{env['SERVER_PORT']}" host = (env["HTTP_HOST"]) || (env["SERVER_NAME"] + port) "#{scheme(env)}://#{host}" end def scheme env if env['HTTPS'] == 'on' 'https' elsif env['HTTP_X_FORWARDED_SSL'] == 'on' 'https' elsif env['HTTP_X_FORWARDED_PROTO'] env['HTTP_X_FORWARDED_PROTO'].split(',').first else env["rack.url_scheme"] end end # Classes including the module must respond to the ssl_ca_file message in order to use the following methods. # The response will be the path to the CA file to use when making https requests. # If the result of ssl_ca_file is nil no file is used. In this case a warn message is logged. private # Executes an HTTP GET request. # It raises a RuntimeError if the response code is not equal to 200 def http_get host, path, params connection = Net::HTTP.new(host) process_http_response connection.request_get(path + "?" + to_query_string(params)) end # Executes an HTTP POST request over SSL # It raises a RuntimeError if the response code is not equal to 200 def https_post host, path, params https_connection host do |connection| connection.request_post(path, to_query_string(params)) end end # Executes an HTTP GET request over SSL # It raises a RuntimeError if the response code is not equal to 200 def https_get host, path, params, headers = nil https_connection host do |connection| connection.request_get(path + "?" + to_query_string(params), headers) end end def https_connection (host) connection = Net::HTTP.new(host, SSL_PORT) connection.use_ssl = true if ssl_ca_file connection.ca_file = ssl_ca_file else logger << "No SSL ca file provided. It is highly reccomended to use one in production envinronments" if respond_to?(:logger) && logger connection.verify_mode = OpenSSL::SSL::VERIFY_NONE end process_http_response(yield(connection)) end def process_http_response response raise response.body if response.code != "200" response.body end end end