require "jfoundry/trace_helpers" require "net/https" require "net/http/post/multipart" require "multi_json" require "fileutils" require "forwardable" module JFoundry class BaseClient # :nodoc: include JFoundry::ProxyOptions extend Forwardable attr_reader :rest_client def_delegators :rest_client, :target, :target=, :access_key, :secret_key, :version, #:token, :trace, :backtrace, :backtrace=, :log, :log=, :http_proxy, :http_proxy=, :https_proxy, :https_proxy= def initialize(target, access_key, secret_key, version) @rest_client = JFoundry::RestClient.new(target, access_key, secret_key, version) self.trace = false self.backtrace = false self.log = false end def trace=(trace) @rest_client.trace = trace #@uaa.trace = trace if @uaa end # Cloud metadata def info get("/v2/info", :accept => :json) end def get(*args) request("GET", *args) end def delete(*args) request("DELETE", *args) end def post(*args) request("POST", *args) end def put(*args) request("PUT", *args) end def request(method, *args) #puts "args: ", args path, options = normalize_arguments(args) #puts "path: ", path #puts "options: ", options request, response = request_raw(method, path, options) handle_response(response, options, request) end def request_raw(method, path, options) @rest_client.request(method, path, options) end def stream_url(url, &blk) uri = URI.parse(url) opts = {} if uri.scheme == "https" opts[:use_ssl] = true opts[:verify_mode] = OpenSSL::SSL::VERIFY_NONE end Net::HTTP.start(uri.host, uri.port, *proxy_options_for(uri), opts) do |http| http.read_timeout = 5 req = Net::HTTP::Get.new(uri.request_uri) #req["Authorization"] = token.auth_header if token http.request(req) do |response| case response when Net::HTTPOK response.read_body(&blk) when Net::HTTPNotFound raise JFoundry::NotFound.new(response.body, 404) when Net::HTTPForbidden raise JFoundry::Denied.new(response.body, 403) when Net::HTTPUnauthorized raise JFoundry::Unauthorized.new(response.body, 401) else raise JFoundry::BadResponse.new(response.body, response.code) end end end end private def status_is_successful?(code) (code >= 200) && (code < 400) end def handle_response(response, options, request) if status_is_successful?(response[:status].to_i) handle_successful_response(response, options) else handle_error_response(response, request) end end def handle_successful_response(response, options) if options[:return_response] response elsif options[:accept] == :json parse_json(response[:body]) else response[:body] end end def handle_error_response(response, request) body_json = parse_json(response[:body]) body_code = body_json && body_json[:code] code = body_code || response[:status].to_i if body_code error_class = JFoundry::APIError.error_classes[body_code] || JFoundry::APIError raise error_class.new(body_json[:description], body_code, request, response) end case code when 404 raise JFoundry::NotFound.new(nil, code, request, response) when 403 raise JFoundry::Denied.new(nil, code, request, response) when 401 raise JFoundry::Unauthorized.new(nil, code, request, response) else raise JFoundry::BadResponse.new(nil, code, request, response) end end def normalize_arguments(args) if args.last.is_a?(Hash) options = args.pop else options = {} end [normalize_path(args), options] end URI_ENCODING_PATTERN = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]") def normalize_path(segments) if segments.size == 1 && segments.first =~ /^\// segments.first else segments.flatten.collect { |x| URI.encode(x.to_s, URI_ENCODING_PATTERN) }.join("/") end end def parse_json(x) if x.empty? raise MultiJson::DecodeError.new("Empty JSON string", [], "") else MultiJson.load(x, :symbolize_keys => true) end rescue MultiJson::DecodeError nil end end end