Created
April 30, 2010 08:46
-
-
Save jacquescrocker/384951 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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