class CFoundry::RestClient

Constants

DEFAULT_OPTIONS
HTTP_METHODS
LOG_LENGTH

Attributes

backtrace[RW]
log[RW]
request_id[RW]
target[R]
token[RW]
trace[RW]

Public Class Methods

new(target, token = nil) click to toggle source
# File lib/cfoundry/rest_client.rb, line 43
def initialize(target, token = nil)
  @target = target
  @token = token
  @trace = false
  @backtrace = false
  @log = false
end

Public Instance Methods

generate_headers(payload, options) click to toggle source
# File lib/cfoundry/rest_client.rb, line 62
def generate_headers(payload, options)
  headers = {}

  if payload.is_a?(String)
    headers["Content-Length"] = payload.size
  elsif !payload
    headers["Content-Length"] = 0
  end

  headers["X-Request-Id"] = @request_id if @request_id
  headers["Authorization"] = @token.auth_header if @token

  if accept_type = mimetype(options[:accept])
    headers["Accept"] = accept_type
  end

  if content_type = mimetype(options[:content])
    headers["Content-Type"] = content_type
  end

  headers.merge!(options[:headers]) if options[:headers]
  headers
end
request(method, path, options = {}) click to toggle source
# File lib/cfoundry/rest_client.rb, line 58
def request(method, path, options = {})
  request_uri(method, construct_url(path), DEFAULT_OPTIONS.merge(options))
end
target=(target) click to toggle source
# File lib/cfoundry/rest_client.rb, line 51
def target=(target)
  return if target == @target

  @target = target
  @token = nil
end

Private Instance Methods

add_headers(request, headers) click to toggle source
# File lib/cfoundry/rest_client.rb, line 188
def add_headers(request, headers)
  headers.each { |key, value| request[key] = value }
end
construct_url(path) click to toggle source
# File lib/cfoundry/rest_client.rb, line 176
def construct_url(path)
  uri = URI.parse(path)
  return path if uri.scheme

  path = "/#{path}" unless path[0] == ?\/
  target + path
end
encode_params(hash, escape = true) click to toggle source
# File lib/cfoundry/rest_client.rb, line 208
def encode_params(hash, escape = true)
  hash.keys.map do |k|
    v = hash[k]
    v = MultiJson.dump(v) if v.is_a?(Hash)
    v = URI.escape(v.to_s, /[^#{URI::PATTERN::UNRESERVED}]/) if escape
    "#{k}=#{v}"
  end.join("&")
end
get_method_class(method_string) click to toggle source
# File lib/cfoundry/rest_client.rb, line 184
def get_method_class(method_string)
  HTTP_METHODS[method_string.upcase]
end
log_data(time, request, response) click to toggle source
# File lib/cfoundry/rest_client.rb, line 217
def log_data(time, request, response)
  { :time => time,
    :request => {
      :method => request.method,
      :url => request.path,
      :headers => sane_headers(request)
    },
    :response => {
      :code => response.code,
      :headers => sane_headers(response)
    }
  }
end
log_line(io, data) click to toggle source
# File lib/cfoundry/rest_client.rb, line 231
def log_line(io, data)
  io.printf(
    "[%s]  %0.3fs  %6s -> %d  %s\n",
    Time.now.strftime("%F %T"),
    data[:time],
    data[:request][:method].to_s.upcase,
    data[:response][:code],
    data[:request][:url])
end
log_request(time, request, response) click to toggle source
# File lib/cfoundry/rest_client.rb, line 241
def log_request(time, request, response)
  return unless @log

  data = log_data(time, request, response)

  case @log
  when IO
    log_line(@log, data)
    return
  when String
    if File.exists?(@log)
      log = File.readlines(@log).last(LOG_LENGTH - 1)
    elsif !File.exists?(File.dirname(@log))
      FileUtils.mkdir_p(File.dirname(@log))
    end

    File.open(@log, "w") do |io|
      log.each { |l| io.print l } if log
      log_line(io, data)
    end

    return
  end

  if @log.respond_to?(:call)
    @log.call(data)
    return
  end

  if @log.respond_to?(:<<)
    @log << data
    return
  end
end
mimetype(content) click to toggle source
# File lib/cfoundry/rest_client.rb, line 192
def mimetype(content)
  case content
  when String
    content
  when :json
    "application/json"
  when :form
    "application/x-www-form-urlencoded"
  when nil
    nil
  # return request headers (not really Accept)
  else
    raise CFoundry::Error, "Unknown mimetype '#{content.inspect}'"
  end
end
print_backtrace(locs) click to toggle source
print_request(request) click to toggle source
print_response(response) click to toggle source
request_uri(method, uri, options = {}) click to toggle source
# File lib/cfoundry/rest_client.rb, line 88
def request_uri(method, uri, options = {})
  uri = URI.parse(uri)

  unless uri.is_a?(URI::HTTP)
    raise InvalidTarget.new(@target)
  end

  # keep original options in case there's a redirect to follow
  original_options = options.dup
  payload = options[:payload]

  if options[:params]
    encoded_params = encode_params(options[:params])
    if encoded_params.respond_to?(:empty?) ? !encoded_params.empty? : encoded_params
      if uri.query
        uri.query += "&" + encoded_params
      else
        uri.query = encoded_params
      end
    end
  end

  unless payload.is_a?(String)
    case options[:content]
      when :json
        payload = MultiJson.dump(payload)
      when :form
        payload = encode_params(payload)
    end
  end

  method_class = get_method_class(method)
  if payload.is_a?(Hash)
    multipart = method_class.const_get(:Multipart)
    request = multipart.new(uri.request_uri, payload)
  else
    request = method_class.new(uri.request_uri)
    request.body = payload if payload
  end

  headers = generate_headers(payload, options)

  request_hash = {
    :url => uri.to_s,
    :method => method,
    :headers => headers,
    :body => payload
  }

  print_request(request_hash) if @trace

  add_headers(request, headers)

  http = HTTPFactory.create(uri, proxy_options_for(uri))

  # TODO remove this when staging returns streaming responses
  http.read_timeout = 300

  before = Time.now
  http.start do
    response = http.request(request)
    time = Time.now - before

    response_hash = {
      :headers => sane_headers(response),
      :status => response.code,
      :body => response.body
    }

    print_response(response_hash) if @trace
    print_backtrace(caller) if @trace

    log_request(time, request, response)

    if response.is_a?(Net::HTTPRedirection) && options[:follow_redirects]
      request_uri("GET", response["location"], original_options)
    else
      return request_hash, response_hash
    end
  end
rescue ::Timeout::Error => e
  raise Timeout.new(method, uri, e)
rescue SocketError, Errno::ECONNREFUSED => e
  raise TargetRefused, e.message
rescue URI::InvalidURIError
  raise InvalidTarget.new(@target)
end
sane_headers(obj) click to toggle source
# File lib/cfoundry/rest_client.rb, line 306
def sane_headers(obj)
  hds = {}

  obj.each_header do |k, v|
    hds[k] = v
  end

  hds
end