#!/usr/bin/ruby

require 'net/http'
require 'net/https'
require 'uri'



class HTTPSTest

  #
  # Data passed from the JSON hash.
  #
  attr_reader :test_data

  #
  # The HTTP status, the HTTP response body, and the error text
  # we return on failure.
  #
  attr_reader :status, :body, :error



  #
  # Save the data away.
  #
  def initialize( data )
    @test_data = data
    @error     = nil

    #
    # Ensure we have an URL
    #
    if ( @test_data["target_host"].nil? )
      @error = "Missing URL for the test."
      raise ArgumentError, @error
    end

    #
    # Ensure we have a port
    #
    if ( @test_data["test_port"].nil? )
      @error = "Missing port for the test."
      raise ArgumentError, @error

    end

  end


  #
  # Run the test.
  #
  #  Return "true" on success
  #
  #  Return "false" on failure.
  #
  # If the test fails the details should be retrieved from "error()".
  #
  def run_test

    #
    #  Do the fetch, if this success then we'll have the
    # @status + @text setup
    #
    if ( getURL (@test_data["target_host"] ) )

      #
      #  Do we need to test for a HTTP status code?
      #
      if ( @test_data["http_status"] )
        puts "Testing for HTTP status code: #{@test_data['http_status']}" if ( @test_data['verbose'] )

        if ( @status != @test_data['http_status'].to_i)
          @error = "#{@error} status code was #{@status} not #{@test_data['http_status']}"
        end
      end

      #
      #  Do we need to search for text in the body of the reply?
      #
      if ( @test_data['http_text'] )
        puts "Testing for text in the response: #{@test_data['http_text']}" if ( @test_data['verbose'] )

        if (! @body.match(/#{@test_data['http_text']}/i) )
          @error = "#{@error} The respond did not contain #{test_data['http_text']}"
        end
      end

      return true if ( @error.nil? )

      return false
    end

    return false
  end


  #
  #  Return the error text for why this test failed.
  #
  def error
    return @error
  end


  #
  # Retrieve a HTTP page from the web.
  #
  # NOTE:  This came from sentinel.
  def getURL (uri_str)
    begin
      uri_str = 'http://' + uri_str unless uri_str.match(/^http/)
      url = URI.parse(uri_str)
      http = Net::HTTP.new(url.host, url.port)
      http.open_timeout = 3
      http.read_timeout = 3

      if (url.scheme == "https")
        http.use_ssl = true
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
      end

      response = nil

      if nil == url.query
        response = http.start { http.get(url.path) }
      else
        response = http.start { http.get("#{url.path}?#{url.query}") }
      end

      @status = response.code.to_i
      @body   =  response.body

      return true
    rescue Errno::EHOSTUNREACH => ex
      @error = "no route to host"
      return false
    rescue Timeout::Error => ex
      @error = "time out reached"
      return false
    rescue => ex
      raise ex
      return false
    end
    return false
  end



end



#
# Sample test, for testing.
#
if __FILE__ == $0 then

  #
  #  Sample data.
  #
  test = {
    "target_host" => "http://www.steve.org.uk/",
    "test_type"   => "http",
    "verbose"     => 1,
    "test_port"   => 80,
    "test_alert"  => "Steve's website is unavailable",
    "http_text"   => "Steve Kemp",
    "http_status" => "200"
  }


  #
  #  Run the test.
  #
  http = HTTPSTest.new( test )
  if ( http.run_test )
    puts "TEST OK"
  else
    puts "TEST FAILED"
    puts http.error()
  end

end