# File lib/restr.rb, line 102
  def self.do(method, url, params = {}, options = {})
    puts "METHOD:  #{method.inspect}"
    puts "URL:     #{url.inspect}"
    puts "PARAMS:  #{params.inspect}"
    puts "OPTIONS: #{options.inspect}"
    
    uri = URI.parse(url)
    
    params = {} unless params
    options = {} unless options
    
    logger = options[:logger] || self.logger
      
    method_mod = method.to_s.downcase.capitalize
    unless Net::HTTP.const_defined?(method_mod)
      raise InvalidRequestMethod, 
        "Callback method #{method.inspect} is not a valid HTTP request method."
    end
    
    if method_mod == 'Get'
      q = params.collect{|k,v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"}.join("&")
      if uri.query
        uri.query += "&#{q}"
      else
        uri.query = q
      end
    end
    
    req = Net::HTTP.const_get(method_mod).new(uri.request_uri)
    
    
    if options[:username] || options['username']
      req.basic_auth options[:username] || options['username'], options[:password] || options['password']
    end
    
    if params.kind_of?(Hash) && method_mod != 'Get' && method_mod != 'get'
      req.set_form_data(params, '&')
    end
    
    logger.debug("Sending #{method.inspect} request to #{url.inspect} with data #{params.inspect}"+
        (options ? " with options" : "")+".") if logger
 
    client = Net::HTTP.new(uri.host, uri.port)
    client.use_ssl = (uri.scheme == 'https')
    
    timeout = Restr.request_timeout
    client.read_timeout = timeout
    
    begin
      res = client.start do |http|
        http.request(req)
      end
    rescue Timeout::Error
      res = TimeoutError, "Request timed out after #{timeout} seconds."
    end
    
    case res
    when Net::HTTPSuccess
      if res.content_type =~ /[\/+]xml$/
        logger.debug("Got XML response: \n#{res.body}") if logger
        return XmlSimple.xml_in_string(res.body,
          'forcearray'   => false,
          'keeproot'     => false
        )
      else
        logger.debug("Got #{res.content_type.inspect} response: \n#{res.body}") if logger
        return res.body
      end
    when TimeoutError
      logger.debug(res) if logger
      return XmlSimple.xml_in_string(res,
          'forcearray'   => false,
          'keeproot'     => false
        )
    else
      $LAST_ERROR_BODY = res.body # FIXME: this is dumb... need a better way of reporting errors
      $LAST_ERROR_RESPONSE = res # this is currently unused within Restr, but may be useful for debugging 
      logger.error("Got error response '#{res.message}(#{res.code})': #{res.body.blank? ? '(blank response body)' : res.body}") if logger
      res.error!
    end
  end