# File lib/restr.rb, line 92
  def self.do(method, url, params = {}, auth = nil)
    uri = URI.parse(url)
    params = {} unless params
      
    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 auth
      raise ArgumentError, 
        "The `auth` parameter must be a Hash with a :username and :password value." unless 
        auth.kind_of? Hash
      req.basic_auth auth[:username] || auth['username'], auth[:password] || auth['password']
    end
    
    if params.kind_of?(Hash) && method_mod != 'Get' && method_mod != 'get'
      req.set_form_data(params, '&')
    end
    
    @@log.debug("Sending #{method.inspect} request to #{url.inspect} with data #{params.inspect}"+
        (auth ? " with authentication" : "")+".") if @@log
 
    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$/
        @@log.debug("Got XML response: \n#{res.body}") if @@log
        return XmlSimple.xml_in_string(res.body,
          'forcearray'   => false,
          'keeproot'     => false
        )
      else
        @@log.debug("Got #{res.content_type.inspect} response: \n#{res.body}") if @@log
        return res.body
      end
    when TimeoutError
      @@log.debug(res) if @@log
      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
      @@log.error("Got error response '#{res.message}(#{res.code})': #{$LAST_ERROR_BODY}") if @@log
      res.error!
    end
  end