Skip to content

Instantly share code, notes, and snippets.

@jacquescrocker
Created April 30, 2010 08:46
Show Gist options
  • Save jacquescrocker/384951 to your computer and use it in GitHub Desktop.
Save jacquescrocker/384951 to your computer and use it in GitHub Desktop.
def run_request(method, url, headers={}, data=false, limit=10, raw=false)
@cookies ||= {}
@default_headers ||= {}
http_retry_delay = 5
http_retry_count = 5
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
http = Net::HTTP.new(url.host, url.port)
if url.scheme == "https"
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
http.read_timeout = 300
headers = @default_headers.merge(headers)
unless raw
headers = headers.merge({
'Accept' => "application/json",
})
end
headers['X-Chef-Version'] = "0.10"
json_body = data ? data.to_json : nil
req = nil
case method
when :GET
req_path = "#{url.path}"
req_path << "?#{url.query}" if url.query
req = Net::HTTP::Get.new(req_path, headers)
when :POST
headers["Content-Type"] = 'application/json' if data
req_path = "#{url.path}"
req_path << "?#{url.query}" if url.query
req = Net::HTTP::Post.new(req_path, headers)
req.body = json_body if json_body
when :PUT
headers["Content-Type"] = 'application/json' if data
req_path = "#{url.path}"
req_path << "?#{url.query}" if url.query
req = Net::HTTP::Put.new(req_path, headers)
req.body = json_body if json_body
when :DELETE
req_path = "#{url.path}"
req_path << "?#{url.query}" if url.query
req = Net::HTTP::Delete.new(req_path, headers)
else
raise ArgumentError, "You must provide :GET, :PUT, :POST or :DELETE as the method"
end
puts("Sending HTTP Request via #{req.method} to #{url.host}:#{url.port}#{req.path}")
# Optionally handle HTTP Basic Authentication
req.basic_auth(url.user, url.password) if url.user
res = nil
tf = nil
http_attempts = 0
begin
http_attempts += 1
begin
res = http.request(req) do |response|
if raw
tf = Tempfile.new("chef-rest")
# Stolen from http://www.ruby-forum.com/topic/166423
# Kudos to _why!
size, total = 0, response.header['Content-Length'].to_i
response.read_body do |chunk|
tf.write(chunk)
size += chunk.size
if size == 0
puts("#{req.path} done (0 length file)")
elsif total == 0
puts("#{req.path} (zero content length)")
else
puts("#{req.path}" + " %d%% done (%d of %d)" % [(size * 100) / total, size, total])
end
end
tf.close
tf
else
response.read_body
end
response
end
rescue Exception => e
puts "!!!FAILED ON:!!!"
puts "run_request(#{method.inspect}, #{url.inspect}, #{headers.inspect}, #{data.inspect}, #{limit.inspect}, #{raw.inspect})"
puts "WTF"
raise e
end
if res.kind_of?(Net::HTTPSuccess)
if res['set-cookie']
@cookies["#{url.host}:#{url.port}"] = res['set-cookie']
end
if res['content-type'] =~ /json/
response_body = res.body.chomp
JSON.parse(response_body)
else
if raw
tf
else
res.body
end
end
elsif res.kind_of?(Net::HTTPFound) or res.kind_of?(Net::HTTPMovedPermanently)
if res['set-cookie']
@cookies["#{url.host}:#{url.port}"] = res['set-cookie']
end
@sign_request = false if @sign_on_redirect == false
run_request(:GET, create_url(res['location']), {}, false, limit - 1, raw)
else
if res['content-type'] =~ /json/
exception = JSON.parse(res.body)
puts("HTTP Request Returned #{res.code} #{res.message}: #{exception["error"].respond_to?(:join) ? exception["error"].join(", ") : exception["error"]}")
end
res.error!
end
rescue Errno::ECONNREFUSED
if http_retry_count - http_attempts + 1 > 0
puts("Connection refused connecting to #{url.host}:#{url.port} for #{req.path}, retry #{http_attempts}/#{http_retry_count}")
sleep(http_retry_delay)
retry
end
raise Errno::ECONNREFUSED, "Connection refused connecting to #{url.host}:#{url.port} for #{req.path}, giving up"
rescue Timeout::Error
if http_retry_count - http_attempts + 1 > 0
puts("Timeout connecting to #{url.host}:#{url.port} for #{req.path}, retry #{http_attempts}/#{http_retry_count}")
sleep(http_retry_delay)
retry
end
raise Timeout::Error, "Timeout connecting to #{url.host}:#{url.port} for #{req.path}, giving up"
rescue Net::HTTPServerException
if res.kind_of?(Net::HTTPForbidden)
if http_retry_count - http_attempts + 1 > 0
puts("Received 403 Forbidden against #{url.host}:#{url.port} for #{req.path}, retry #{http_attempts}/#{http_retry_count}")
sleep(http_retry_delay)
retry
end
end
raise
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment