lib/riemann/tools/http_check.rb in riemann-tools-1.8.2 vs lib/riemann/tools/http_check.rb in riemann-tools-1.9.0

- old
+ new

@@ -23,10 +23,12 @@ ] opt :connection_latency_warning, 'Lattency warning threshold', short: :none, default: 0.1 opt :connection_latency_critical, 'Lattency critical threshold', short: :none, default: 0.25 opt :response_latency_warning, 'Lattency warning threshold', short: :none, default: 0.5 opt :response_latency_critical, 'Lattency critical threshold', short: :none, default: 1.0 + opt :follow_redirects, 'Follow redirects (301, 302)', short: :none, default: true + opt :max_redirects, 'Stop following redirects after this number of hops', short: :none, default: 5 opt :http_timeout, 'Timeout (in seconds) for HTTP requests', short: :none, default: 5.0 opt :checks, 'A list of checks to run.', short: :none, type: :strings, default: %w[consistency connection-latency response-code response-latency] opt :resolvers, 'Run this number of resolver threads', short: :none, type: :integer, default: 5 opt :workers, 'Run this number of worker threads', short: :none, type: :integer, default: 20 opt :user_agent, 'User-Agent header for HTTP requests', short: :none, default: "#{File.basename($PROGRAM_NAME)}/#{Riemann::Tools::VERSION} (+https://github.com/riemann/riemann-tools)" @@ -98,12 +100,11 @@ @resolve_queue.push(URI(uri)) end end def test_uri_addresses(uri, addresses) - request = ::Net::HTTP::Get.new(uri, { 'user-agent' => opts[:user_agent] }) - request.basic_auth(uri.user, uri.password) + request = get_request(uri) responses = [] addresses.each do |address| responses << test_uri_address(uri, address.to_s, request) @@ -145,11 +146,19 @@ hostname: uri.host, port: uri.port, ) end - def test_uri_address(uri, address, request) + def get_request(uri) + request = ::Net::HTTP::Get.new(uri, { 'user-agent' => opts[:user_agent] }) + + request.basic_auth(uri.user, uri.password) + + request + end + + def test_uri_address(uri, address, request, redirect_count: 0) response = nil start = Time.now connected = nil done = nil @@ -171,16 +180,47 @@ report_http_endpoint_response_code(http, uri, response) if opts[:checks].include?('response-code') report_http_endpoint_latency(http, uri, 'connection', start, connected) if opts[:checks].include?('connection-latency') report_http_endpoint_latency(http, uri, 'response', start, done) if opts[:checks].include?('response-latency') + if opts[:follow_redirects] && %w[301 302].include?(response.code) + next_uri = redirect_uri(uri, response['Location']) + + if same_origin?(uri, next_uri) + if redirect_count == opts[:max_redirects] + report_http_endpoint_max_redirects(http, uri) + return nil + else + response = test_uri_address(next_uri, address, get_request(next_uri), redirect_count: redirect_count + 1) + end + end + end + response rescue StandardError # Ignore this address nil end + def redirect_uri(uri, location) + res = URI.parse(location) + + res.scheme ||= uri.scheme + res.host ||= uri.host + res.port ||= uri.port + res.user ||= res.user + res.password ||= res.password + + res + end + + def same_origin?(left, right) + left.scheme == right.scheme && + left.host == right.host && + left.port == right.port + end + def report_http_endpoint_response_code(http, uri, response) return unless response report( { @@ -211,9 +251,18 @@ state: latency_state(latency, nil), description: 'timeout', }.merge(endpoint_report(http, uri, "#{latency} latency")), ) end + end + + def report_http_endpoint_max_redirects(http, uri) + report( + { + state: 'critical', + description: "Reached the limit of #{opts[:max_redirects]} redirects", + }.merge(endpoint_report(http, uri, 'redirects')), + ) end def latency_state(name, latency) critical_threshold = opts["#{name}_latency_critical".to_sym] warning_threshold = opts["#{name}_latency_warning".to_sym]