summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/custodian/protocoltest/http.rb156
1 files changed, 152 insertions, 4 deletions
diff --git a/lib/custodian/protocoltest/http.rb b/lib/custodian/protocoltest/http.rb
index 133fdaf..44f76a6 100644
--- a/lib/custodian/protocoltest/http.rb
+++ b/lib/custodian/protocoltest/http.rb
@@ -1,3 +1,9 @@
+require 'openssl'
+require 'socket'
+require 'timeout'
+require 'uri'
+
+
#
# The HTTP-protocol test.
@@ -21,13 +27,25 @@ module Custodian
#
attr_reader :line
-
#
# The URL to poll
#
attr_reader :url
#
+ # The expected status + content
+ #
+ attr_reader :expected_status, :expected_content
+
+
+ #
+ # The actual status & content
+ #
+ attr_reader :status, :content
+
+
+
+ #
# Constructor
#
def initialize( line )
@@ -42,7 +60,6 @@ module Custodian
#
@url = line.split( /\s+/)[0]
-
if ( @url !~ /^https?:/ )
raise ArgumentError, "The target wasn't an URL"
end
@@ -56,6 +73,27 @@ module Custodian
@inverted = false
end
+ #
+ # Expected status
+ #
+ if ( line =~ /with status ([0-9]+)/ )
+ @expected_status = $1.dup
+ else
+ @expected_status = "200"
+ end
+
+ #
+ # The content we expect to find
+ #
+ if ( line =~ /with content '([^']+)'/ )
+ @expected_content = $1.dup
+ else
+ @expected_content = nil
+ end
+
+ @status = nil
+ @content = nil
+
end
@@ -74,12 +112,122 @@ module Custodian
# Run the test.
#
def run_test
- @error = "Not implemented"
- false
+
+ # Reset state, in case we've previously run.
+ @error = nil
+
+ # Parse the URL
+ uri = URI.parse(@url)
+
+ #
+ # Ensure we have a path to request - to cover people who write:
+ #
+ # http://example.com must run http ..
+ #
+ if ( uri.path.empty? )
+ uri.path = "/"
+ end
+
+ #
+ # Connect a socket to the host.
+ #
+ socket = connect( uri.host, uri.port, uri.scheme == "https" )
+
+ path = uri.path
+ if ( uri.query )
+ path = "#{url.path}?#{url.query}"
+ end
+
+ req =<<EOF
+GET #{path} HTTP/1.1
+Host: #{uri.host}
+Connection: close
+
+EOF
+
+ do_check( socket, req )
+
+ if ( @expected_status.to_i != @status.to_i )
+ @error = "Status code was #{@status} not the expected #{@expected_status}"
+ return false
+ end
+
+ if ( !@expected_content.nil? )
+ if (! @content.match(/#{@expected_content}/i) )
+ @error = "<p>The response did not contain our expected text '#{@expected_content}'</p>"
+ end
+ end
+
+ #
+ # Done?
+ #
+ true
end
+ #
+ # Create a socket to the appropriate host - configuring
+ # SSL if appropriate.
+ #
+ def connect( host, port, ssl )
+ sock = TCPSocket.new(host, port)
+ if ( ssl)
+ ssl_sock = OpenSSL::SSL::SSLSocket.new(
+ sock,
+ OpenSSL::SSL::SSLContext.new("SSLv3_client")
+ )
+ ssl_sock.sync_close = true
+ ssl_sock.connect
+ return ssl_sock
+ else
+ return sock
+ end
+ end
+
+
+
+ #
+ # Send the request and get back the response.
+ #
+ def do_check( socket, script )
+ header = true
+
+ begin
+ Timeout.timeout(30, Errno::ETIMEDOUT) do
+ script.each do |line|
+ if line.is_a?(String)
+ socket.print line
+ end
+ end
+
+ loop do
+ trans = socket.gets
+
+ if ( header && trans =~ /HTTP\/[0-9]\.[0-9] ([0-9]+) OK/ )
+ @status = $1.dup
+ end
+ if ( header && trans =~ /^$/ )
+ header = false
+ next
+ end
+
+ if ( !header )
+ @content = "#{@content}#{trans}"
+ end
+ break if trans.nil?
+ end
+ socket.close
+ end
+ rescue => err
+ @error = err
+ ensure
+ socket.close if socket.is_a?(Socket) and not socket.closed?
+ end
+
+ end
+
+
#
# If the test fails then report the error.