Module: ElbPing::HttpPinger

Defined in:
lib/elbping/pinger.rb

Overview

Responsible for all HTTP ping-like functionality

Class Method Summary collapse

Class Method Details

.cert_matches?(cert, host) ⇒ Boolean

Check if a given host matches a cert’s pattern

Arguments:

  • cert: (object) of X.509 certificate

  • host: (string) of a hostname to compare

Returns:

  • (Boolean)


31
32
33
# File 'lib/elbping/pinger.rb', line 31

def self.cert_matches?(cert, host)
  File.fnmatch(cert_name(cert.subject).first, host)
end

.cert_name(x509_subject) ⇒ Object

Extract CNs from a X509 subject string

Arguments:

  • x509_subject: (string) of cert subject



15
16
17
18
19
20
21
22
23
# File 'lib/elbping/pinger.rb', line 15

def self.cert_name(x509_subject)
  cn_bucket = Array.new
  x509_subject.to_a.each do |entry|
    if entry.first == 'CN' and entry[1]
      cn_bucket << entry[1]
    end
  end
  cn_bucket
end

.ping_node(node, host, port, path, use_ssl, verb_len, timeout) ⇒ Object

Make HTTP request to given node using custom request method and measure response time

Arguments:

  • node: (string) of node IP

  • host: (string) of hostname, used for checking SSL cert match

  • port: (string || Fixnum) of positive integer [1, 65535]

  • path: (string) of path to request, e.g. “/”

  • use_ssl: (boolean) Whether or not this is HTTPS

  • verb_len: (Fixnum) of positive integer, how long the custom HTTP verb should be

  • timeout: (Fixnum) of positive integer, how many seconds for connect and read timeouts



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/elbping/pinger.rb', line 46

def self.ping_node(node, host, port, path, use_ssl, verb_len, timeout)
  ##
  # Build request class
  ping_request = Class.new(Net::HTTPRequest) do
    const_set :METHOD, "A" * verb_len
    const_set :REQUEST_HAS_BODY, false
    const_set :RESPONSE_HAS_BODY, false
  end

  ##
  # Configure http object
  start = Time.now.getutc
  http = Net::HTTP.new(node, port.to_s)
  http.open_timeout     = timeout
  http.read_timeout     = timeout
  http.continue_timeout = timeout

  # Enable SSL if it's to be used
  if use_ssl
    http.use_ssl          = true
    http.verify_mode      = OpenSSL::SSL::VERIFY_NONE
    http.ssl_timeout      = timeout
  end

  ##
  # Make the HTTP request and handle any errors along the way
  error, exc = nil, nil
  req, response, cert = nil, nil, nil

  begin
    http.start do
      req = ping_request.new(path)
      cert = http.peer_cert
      response = http.request(req)
    end
  rescue OpenSSL::SSL::SSLError => e
    # This probably? won't happen with VERIFY_NONE
    error = :sslerror
  rescue Errno::ECONNREFUSED
    error = :econnrefused
  rescue Timeout::Error
    error = :timeout
  rescue Interrupt
    raise
  rescue SystemExit
    raise
  rescue StandardError => e
    exc = e # because I don't understand scope in ruby yet
    error = :exception
  end

  ssl_status = {}
  if use_ssl
    raise "No cert when SSL enabled?!" unless cert
    ssl_status = {
      :sslSubject => cert_name(cert.subject),
      :sslExpires => cert.not_after,
      :sslHostMatch => cert_matches?(cert, host)
    }
  end

  {:code => error || response.code,
    :exception => exc,
    :node => node,
    :duration => ((Time.now.getutc - start) * 1000).to_i, # returns in ms
  }.merge(ssl_status)
end