module Spectre::Curl
Public Class Methods
curl(name, secure: false, &block)
click to toggle source
# File lib/spectre/curl.rb, line 157 def curl name, secure: false, &block req = { 'use_ssl' => secure, } if @@http_cfg.key? name req.merge! @@http_cfg[name] raise "No `base_url' set for HTTP client '#{name}'. Check your HTTP config in your environment." if !req['base_url'] else req['base_url'] = name end SpectreHttpRequest.new(req).instance_eval(&block) if block_given? invoke(req) end
curl_request()
click to toggle source
# File lib/spectre/curl.rb, line 174 def curl_request raise 'No request has been invoked yet' unless @@request @@request end
curl_response()
click to toggle source
# File lib/spectre/curl.rb, line 179 def curl_response raise 'There is no response. No request has been invoked yet.' unless @@response @@response end
register(mod)
click to toggle source
# File lib/spectre/curl.rb, line 184 def register mod raise 'Module must not be nil' unless mod @@modules << mod end
Private Class Methods
header_to_s(headers)
click to toggle source
# File lib/spectre/curl.rb, line 214 def header_to_s headers s = '' return s unless headers headers.each do |header| key = header[0].to_s value = header[1].to_s value = '*****' if is_secure?(key) and not @@debug s += "#{key.ljust(30, '.')}: #{value}\n" end s end
invoke(req)
click to toggle source
# File lib/spectre/curl.rb, line 229 def invoke req cmd = [@@curl_path] if req['cert'] or req['use_ssl'] scheme = 'https' else scheme = 'http' end uri = req['base_url'] if not uri.match /http(?:s)?:\/\// uri = scheme + '://' + uri end if req['path'] uri += '/' if !uri.end_with? '/' uri += req['path'] end if req['query'] uri += '?' uri += req['query'] .map { |x| x.join '='} .join('&') end cmd.append('"' + uri + '"') cmd.append('-X', req['method']) unless req['method'] == 'GET' or (req['body'] and req['method'] == 'POST') # Call all registered modules @@modules.each do |mod| mod.on_req(req, cmd) if mod.respond_to? :on_req end # Add headers to curl command req['headers'].each do |header| cmd.append('-H', '"' + header.join(':') + '"') end if req['headers'] # Add request body if req['body'] != nil and not req['body'].empty? req_body = try_format_json(req['body']).gsub(/"/, '\\"') cmd.append('-d', '"' + req_body + '"') elsif ['POST', 'PUT', 'PATCH'].include? req['method'].upcase cmd.append('-d', '"\n"') end # Add certificate path if one if given if req['cert'] raise "Certificate '#{req['cert']}' does not exist" unless File.exists? req['cert'] cmd.append('--cacert', req['cert']) elsif req['use_ssl'] or uri.start_with? 'https' cmd.append('-k') end cmd.append('-i') cmd.append('-v') @@request = OpenStruct.new(req) sys_cmd = cmd.join(' ') @@logger.debug(sys_cmd) req_id = SecureRandom.uuid()[0..5] req_log = "[>] #{req_id} #{req['method']} #{uri}\n" req_log += header_to_s(req['headers']) req_log += try_format_json(req['body'], pretty: true) @@logger.info(req_log) start_time = Time.now stdin, stdout, stderr, wait_thr = Open3.popen3(sys_cmd) end_time = Time.now output = stdout.gets(nil) stdout.close debug_log = stderr.gets(nil) stderr.close # debug_log.lines.each { |x| @@logger.debug x unless x.empty? } raise "Unable to request #{uri}. Please check if this service is reachable." unless output @@logger.debug("[<] #{req_id} stdout:\n#{output}") header, body = output.split /\r?\n\r?\n/ result = header.lines.first exit_code = wait_thr.value.exitstatus raise Exception.new "An error occured while executing curl:\n#{debug_log.lines.map { |x| not x.empty? }}" unless exit_code == 0 # Parse protocol, version, status code and status message from response match = /^(?<protocol>[A-Za-z0-9]+)\/(?<version>\d+\.?\d*) (?<code>\d+) (?<message>.*)/.match result raise "Unexpected result from curl request:\n#{result}" unless match res_headers = header.lines[1..-1] .map { |x| /^(?<key>[A-Za-z0-9-]+):\s*(?<value>.*)$/.match x } .select { |x| x != nil } .map { |x| [x[:key].downcase, x[:value]] } res = { protocol: match[:protocol], version: match[:version], code: match[:code].to_i, message: match[:message], headers: Hash[res_headers], body: body } # Call all registered modules @@modules.each do |mod| mod.on_res(res, output) if mod.respond_to? :on_res end res_log = "[<] #{req_id} #{res[:code]} #{res[:message]} (#{end_time - start_time}s)\n" res_headers.each do |header| res_log += "#{header[0].to_s.ljust(30, '.')}: #{header[1].to_s}\n" end if res[:body] != nil and not res[:body].empty? res_log += try_format_json(res[:body], pretty: true) end @@logger.info res_log @@response = SpectreHttpResponse.new(res) raise "Response did not indicate success: #{@@response.code} #{@@response.message}" if req['ensure_success'] and not @@response.success? @@response end
is_secure?(key)
click to toggle source
# File lib/spectre/curl.rb, line 210 def is_secure? key @@secure_keys.any? { |x| key.to_s.downcase.include? x.downcase } end
try_format_json(str, pretty: false)
click to toggle source
# File lib/spectre/curl.rb, line 191 def try_format_json str, pretty: false return str unless str or str.empty? begin json = JSON.parse(str) json.obfuscate!(@@secure_keys) if not @@debug if pretty str = JSON.pretty_generate(json) else str = JSON.dump(json) end rescue # do nothing end str end