def request(request_params, &block)
      current_params = @params.merge(request_params)
      exception = get_param(:exception, current_params) || RuntimeError

      # Re-establish the connection if any of auth params has changed
      same_auth_params_as_before = SECURITY_PARAMS.select do |param|
        request_params[param] != get_param(param)
      end.empty?

      # We save the offset here so that if we need to retry, we can return the file pointer to its initial position
      mypos = get_fileptr_offset(current_params)
      loop do

        current_params[:protocol] ||= (current_params[:port] == 443 ? 'https' : 'http')
        # (re)open connection to server if none exists or params has changed
        same_server_as_before = @server   == current_params[:server]   &&
                                @port     == current_params[:port]     &&
                                @protocol == current_params[:protocol] &&
                                same_auth_params_as_before

        # if we are inside a delay between retries: no requests this time!
        # (skip this step if the endpoint has changed)
        if error_count > current_params[:http_connection_retry_count]            &&
           error_time  + current_params[:http_connection_retry_delay] > Time.now &&
           same_server_as_before

          # store the message (otherwise it will be lost after error_reset and
          # we will raise an exception with an empty text)
          banana_message_text = banana_message
          @logger.warn("#{err_header} re-raising same error: #{banana_message_text} " +
                      "-- error count: #{error_count}, error age: #{Time.now.to_i - error_time.to_i}")
          raise exception.new(banana_message_text)
        end

        # try to connect server(if connection does not exist) and get response data
        begin
          request = current_params[:request]
          request['User-Agent'] = get_param(:user_agent, current_params) || ''
          unless @http          &&
                 @http.started? &&
                 same_server_as_before
            same_auth_params_as_before = true
            start(current_params)
          end

          # Detect if the body is a streamable object like a file or socket.  If so, stream that
          # bad boy.
          setup_streaming(request)
          # update READ_TIMEOUT value (it can be passed with request_params hash)
          @http.read_timeout = get_param(:http_connection_read_timeout, current_params)
          response = @http.request(request, &block)

          error_reset
          eof_reset
          return response

        # We treat EOF errors and the timeout/network errors differently.  Both
        # are tracked in different statistics blocks.  Note below that EOF
        # errors will sleep for a certain (exponentially increasing) period.
        # Other errors don't sleep because there is already an inherent delay
        # in them; connect and read timeouts (for example) have already
        # 'slept'.  It is still not clear which way we should treat errors
        # like RST and resolution failures.  For now, there is no additional
        # delay for these errors although this may change in the future.

        # EOFError means the server closed the connection on us.
        rescue EOFError => e
          finish(e.message)
          
          @logger.debug("#{err_header} server #{@server} closed connection")

            # if we have waited long enough - raise an exception...
          if raise_on_eof_exception?
            @logger.warn("#{err_header} raising #{exception} due to permanent EOF being received from #{@server}, error age: #{Time.now.to_i - eof_time.to_i}")
            raise exception.new("Permanent EOF is being received from #{@server}.")
          else
              # ... else just sleep a bit before new retry
            sleep(add_eof)
            # We will be retrying the request, so reset the file pointer
            reset_fileptr_offset(request, mypos)
          end
        rescue ArgumentError => e
          finish(e.message)
          
          if e.message.include?('wrong number of arguments (5 for 4)')
            # seems our net_fix patch was overriden...
            raise exception.new('incompatible Net::HTTP monkey-patch')
          else
            raise e
          end

        rescue Timeout::Error, SocketError, SystemCallError, Interrupt => e  # See comment at bottom for the list of errors seen...
          finish(e.message)
          if e.is_a?(Errno::ETIMEDOUT) || e.is_a?(Timeout::Error)
            # Omit retries if it was explicitly requested
            # #6481:
            # ... When creating a resource in EC2 (instance, volume, snapshot, etc) it is undetermined what happened if the call times out.
            # The resource may or may not have been created in EC2. Retrying the call may cause multiple resources to be created...
            raise exception.new("#{e.class.name}: #{e.message}") if current_params[:raise_on_timeout]
          elsif e.is_a?(Interrupt)
            # if ctrl+c is pressed - we have to reraise exception to terminate proggy
            @logger.debug( "#{err_header} request to server #{@server} interrupted by ctrl-c")
            raise e
          end
          # oops - we got a banana: log it
          error_add(e)
          @logger.warn("#{err_header} request failure count: #{error_count}, exception: #{e.inspect}")

          # We will be retrying the request, so reset the file pointer
          reset_fileptr_offset(request, mypos)
        end
      end
    end
def request(request_params, &block)
      current_params = @params.merge(request_params)
      exception = get_param(:exception, current_params) || RuntimeError

      # Re-establish the connection if any of auth params has changed
      same_auth_params_as_before = SECURITY_PARAMS.select do |param|
        request_params[param] != get_param(param)
      end.empty?

      # We save the offset here so that if we need to retry, we can return the file pointer to its initial position
      mypos = get_fileptr_offset(current_params)
      loop do

        current_params[:protocol] ||= (current_params[:port] == 443 ? 'https' : 'http')
        # (re)open connection to server if none exists or params has changed
        same_server_as_before = @server   == current_params[:server]   &&
                                @port     == current_params[:port]     &&
                                @protocol == current_params[:protocol] &&
                                same_auth_params_as_before

        # if we are inside a delay between retries: no requests this time!
        # (skip this step if the endpoint has changed)
        if error_count > current_params[:http_connection_retry_count]            &&
           error_time  + current_params[:http_connection_retry_delay] > Time.now &&
           same_server_as_before

          # store the message (otherwise it will be lost after error_reset and
          # we will raise an exception with an empty text)
          banana_message_text = banana_message
          @logger.warn("#{err_header} re-raising same error: #{banana_message_text} " +
                      "-- error count: #{error_count}, error age: #{Time.now.to_i - error_time.to_i}")
          raise exception.new(banana_message_text)
        end

        # try to connect server(if connection does not exist) and get response data
        begin
          request = current_params[:request]
          request['User-Agent'] = get_param(:user_agent, current_params) || ''
          unless @http          &&
                 @http.started? &&
                 same_server_as_before
            same_auth_params_as_before = true
            start(current_params)
          end

          # Detect if the body is a streamable object like a file or socket.  If so, stream that
          # bad boy.
          setup_streaming(request)
          # update READ_TIMEOUT value (it can be passed with request_params hash)
          @http.read_timeout = get_param(:http_connection_read_timeout, current_params)
          response = @http.request(request, &block)

          error_reset
          eof_reset
          return response

        # We treat EOF errors and the timeout/network errors differently.  Both
        # are tracked in different statistics blocks.  Note below that EOF
        # errors will sleep for a certain (exponentially increasing) period.
        # Other errors don't sleep because there is already an inherent delay
        # in them; connect and read timeouts (for example) have already
        # 'slept'.  It is still not clear which way we should treat errors
        # like RST and resolution failures.  For now, there is no additional
        # delay for these errors although this may change in the future.

        # EOFError means the server closed the connection on us.
        rescue EOFError => e
          finish(e.message)
          
          @logger.debug("#{err_header} server #{@server} closed connection")

            # if we have waited long enough - raise an exception...
          if raise_on_eof_exception?
            @logger.warn("#{err_header} raising #{exception} due to permanent EOF being received from #{@server}, error age: #{Time.now.to_i - eof_time.to_i}")
            raise exception.new("Permanent EOF is being received from #{@server}.")
          else
              # ... else just sleep a bit before new retry
            sleep(add_eof)
            # We will be retrying the request, so reset the file pointer
            reset_fileptr_offset(request, mypos)
          end
        rescue ArgumentError => e
          finish(e.message)
          
          if e.message.include?('wrong number of arguments (5 for 4)')
            # seems our net_fix patch was overriden...
            raise exception.new('incompatible Net::HTTP monkey-patch')
          else
            raise e
          end

        rescue Timeout::Error, SocketError, SystemCallError, Interrupt => e  # See comment at bottom for the list of errors seen...
          finish(e.message)
          if e.is_a?(Errno::ETIMEDOUT) || e.is_a?(Timeout::Error)
            # Omit retries if it was explicitly requested
            # #6481:
            # ... When creating a resource in EC2 (instance, volume, snapshot, etc) it is undetermined what happened if the call times out.
            # The resource may or may not have been created in EC2. Retrying the call may cause multiple resources to be created...
            raise exception.new("#{e.class.name}: #{e.message}") if current_params[:raise_on_timeout]
          elsif e.is_a?(Interrupt)
            # if ctrl+c is pressed - we have to reraise exception to terminate proggy
            @logger.debug( "#{err_header} request to server #{@server} interrupted by ctrl-c")
            raise e
          end
          # oops - we got a banana: log it
          error_add(e)
          @logger.warn("#{err_header} request failure count: #{error_count}, exception: #{e.inspect}")

          # We will be retrying the request, so reset the file pointer
          reset_fileptr_offset(request, mypos)
        end
      end
    end
=begin rdoc
    Send HTTP request to server

     request_params hash:
     :server   => 'www.HostName.com'   # Hostname or IP address of HTTP server
     :port     => '80'                 # Port of HTTP server
     :protocol => 'https'              # http and https are supported on any port
     :request  => 'requeststring'      # Fully-formed HTTP request to make
     :proxy_host => 'hostname'         # hostname of HTTP proxy host to use, default none.
     :proxy_port => port               # port of HTTP proxy host to use, default none.
     :proxy_username => 'username'     # username to use for proxy authentication, default none.
     :proxy_password => 'password'     # password to use for proxy authentication, default none.

     :raise_on_timeout                 # do not perform a retry if timeout is received (false by default)
     :http_connection_retry_count
     :http_connection_open_timeout
     :http_connection_read_timeout
     :http_connection_retry_delay
     :user_agent
     :exception

    Raises RuntimeError, Interrupt, and params[:exception] (if specified in new).

=end