lib/skylight/util/http.rb in skylight-5.1.0.beta vs lib/skylight/util/http.rb in skylight-5.1.0.beta2

- old
+ new

@@ -8,18 +8,18 @@ module Skylight module Util class HTTP CONTENT_ENCODING = "content-encoding".freeze - CONTENT_LENGTH = "content-length".freeze - CONTENT_TYPE = "content-type".freeze - ACCEPT = "Accept".freeze - X_VERSION_HDR = "x-skylight-agent-version".freeze + CONTENT_LENGTH = "content-length".freeze + CONTENT_TYPE = "content-type".freeze + ACCEPT = "Accept".freeze + X_VERSION_HDR = "x-skylight-agent-version".freeze APPLICATION_JSON = "application/json".freeze - AUTHORIZATION = "authorization".freeze - DEFLATE = "deflate".freeze - GZIP = "gzip".freeze + AUTHORIZATION = "authorization".freeze + DEFLATE = "deflate".freeze + GZIP = "gzip".freeze include Logging attr_accessor :authentication attr_reader :host, :port, :config @@ -33,22 +33,23 @@ @original = error super error.inspect end end - class ReadResponseError < StandardError; end + class ReadResponseError < StandardError + end def initialize(config, service = :auth, opts = {}) @config = config unless (url = config["#{service}_url"]) raise ArgumentError, "no URL specified for #{service}" end url = URI.parse(url) - @ssl = url.scheme == "https" + @ssl = url.scheme == "https" @host = url.host @port = url.port if (proxy_url = config[:proxy_url]) proxy_url = URI.parse(proxy_url) @@ -79,134 +80,132 @@ execute(request, body) end private - def get_timeout(type, config, service, opts) - config.duration_ms("#{service}_http_#{type}_timeout") || - opts[:timeout] || 15 - end + def get_timeout(type, config, service, opts) + config.duration_ms("#{service}_http_#{type}_timeout") || opts[:timeout] || 15 + end - def build_request(type, endpoint, hdrs, length = nil) - headers = {} + def build_request(type, endpoint, hdrs, length = nil) + headers = {} - headers[CONTENT_LENGTH] = length.to_s if length - headers[AUTHORIZATION] = authentication if authentication - headers[ACCEPT] = APPLICATION_JSON - headers[X_VERSION_HDR] = VERSION - headers[CONTENT_ENCODING] = GZIP if length && @deflate + headers[CONTENT_LENGTH] = length.to_s if length + headers[AUTHORIZATION] = authentication if authentication + headers[ACCEPT] = APPLICATION_JSON + headers[X_VERSION_HDR] = VERSION + headers[CONTENT_ENCODING] = GZIP if length && @deflate - hdrs.each do |k, v| - headers[k] = v - end + hdrs.each { |k, v| headers[k] = v } - type.new(endpoint, headers) + type.new(endpoint, headers) + end + + def do_request(http, req) + begin + client = http.start + rescue StandardError => e + # TODO: Retry here + raise StartError, e end - def do_request(http, req) - begin - client = http.start - rescue => e - # TODO: Retry here - raise StartError, e - end + begin + res = client.request(req) + rescue *READ_EXCEPTIONS => e + raise ReadResponseError, e.inspect + end - begin - res = client.request(req) - rescue *READ_EXCEPTIONS => e - raise ReadResponseError, e.inspect - end + yield res + ensure + client&.finish + end - yield res - ensure - client&.finish + def execute(req, body = nil) + t do + fmt "executing HTTP request; host=%s; port=%s; path=%s, body=%s", + @host, + @port, + req.path, + body && body.bytesize end - def execute(req, body = nil) - t do - fmt "executing HTTP request; host=%s; port=%s; path=%s, body=%s", - @host, @port, req.path, body && body.bytesize - end + if body + body = Gzip.compress(body) if @deflate + req.body = body + end - if body - body = Gzip.compress(body) if @deflate - req.body = body - end + http = Net::HTTP.new(@host, @port, @proxy_addr, @proxy_port, @proxy_user, @proxy_pass) - http = Net::HTTP.new(@host, @port, - @proxy_addr, @proxy_port, @proxy_user, @proxy_pass) + http.open_timeout = @open_timeout + http.read_timeout = @read_timeout - http.open_timeout = @open_timeout - http.read_timeout = @read_timeout + if @ssl + http.use_ssl = true - if @ssl - http.use_ssl = true + http.ca_file = SSL.ca_cert_file_or_default unless SSL.ca_cert_file? - unless SSL.ca_cert_file? - http.ca_file = SSL.ca_cert_file_or_default - end + http.verify_mode = OpenSSL::SSL::VERIFY_PEER + end - http.verify_mode = OpenSSL::SSL::VERIFY_PEER + do_request(http, req) do |res| + unless res.code =~ /2\d\d/ + debug "server responded with #{res.code}" + t { fmt "body=%s", res.body } end - do_request(http, req) do |res| - unless res.code =~ /2\d\d/ - debug "server responded with #{res.code}" - t { fmt "body=%s", res.body } - end - - Response.new(res.code.to_i, res, res.body) - end - rescue Exception => e - error "http %s %s failed; error=%s; msg=%s", req.method, req.path, e.class, e.message - t { e.backtrace.join("\n") } - ErrorResponse.new(req, e) + Response.new(res.code.to_i, res, res.body) end + rescue Exception => e + error "http %s %s failed; error=%s; msg=%s", req.method, req.path, e.class, e.message + t { e.backtrace.join("\n") } + ErrorResponse.new(req, e) + end - class Response - attr_reader :status, :headers, :body, :exception + class Response + attr_reader :status, :headers, :body, :exception - def initialize(status, headers, body) - @status = status - @headers = headers + def initialize(status, headers, body) + @status = status + @headers = headers - if (headers[CONTENT_TYPE] || "").include?(APPLICATION_JSON) - begin - @body = JSON.parse(body) - rescue JSON::ParserError - @body = body # not really JSON I guess - end - else - @body = body + if (headers[CONTENT_TYPE] || "").include?(APPLICATION_JSON) + begin + @body = JSON.parse(body) + rescue JSON::ParserError + @body = body # not really JSON I guess end + else + @body = body end + end - def success? - status >= 200 && status < 300 - end + def success? + status >= 200 && status < 300 + end - def to_s - body.to_s - end + def to_s + body.to_s + end - def get(key) - body.dig(*key.split(".")) if body.is_a?(Hash) - end + def get(key) + body.dig(*key.split(".")) if body.is_a?(Hash) + end - def respond_to_missing?(name, include_all = false) - super || body.respond_to?(name, include_all) - end + def respond_to_missing?(name, include_all = false) + super || body.respond_to?(name, include_all) + end - def method_missing(name, *args, &blk) - if respond_to_missing?(name) - body.send(name, *args, &blk) - else - super - end + def method_missing(name, *args, &blk) + if respond_to_missing?(name) + body.send(name, *args, &blk) + else + super end end + end - ErrorResponse = Struct.new(:request, :exception) do + ErrorResponse = + Struct.new(:request, :exception) do def status nil end def success?