no way to compare when less than two revisions
Differences
This shows you the differences between two versions of the page.
— | monitors:urlplus [2009/11/23 06:11] (current) – created - external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== urlplus.pl ====== | ||
+ | |||
+ | ^ Compatibility | Xymon 4.2+ | | ||
+ | ^ Requirements | Perl, unix, curl | | ||
+ | ^ Download | None | | ||
+ | ^ Last Update | 2008-04-30 | | ||
+ | |||
+ | ===== Description ===== | ||
+ | Provides a more robust form of URL content checking than Xymon does out of the box. | ||
+ | Per-host user-configuration is provided. | ||
+ | |||
+ | |||
+ | ===== Installation ===== | ||
+ | === Client side === | ||
+ | N/A | ||
+ | |||
+ | === Server side === | ||
+ | - Copy urlplus.pl to $BBHOME/ext | ||
+ | - Create a new configuration file: $BBHOME/ | ||
+ | * Add the " | ||
+ | * Create an entry in cont-check.cfg for each of the hosts to be monitored | ||
+ | - Edit hobbitlaunch.cfg to run urlplus.pl | ||
+ | * [urlplus]\\ | ||
+ | |||
+ | ===== Source ===== | ||
+ | ==== urlplus.pl ==== | ||
+ | |||
+ | <hidden onHidden=" | ||
+ | <code perl> | ||
+ | # | ||
+ | ################################################################################ | ||
+ | # Author: | ||
+ | # Created On: | ||
+ | # Description: | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # USAGE AND NOTES: | ||
+ | # ================ | ||
+ | # *) The host must be defined in bb-hosts before any | ||
+ | # | ||
+ | # | ||
+ | # *) Hosts defined in bb-hosts with the " | ||
+ | # | ||
+ | # | ||
+ | # *) Lines starting with "#" | ||
+ | # | ||
+ | # *) Adding a URL test | ||
+ | # | ||
+ | # 1) Add the following keyword to the the appropriate host in | ||
+ | # the bb-hosts file: urlplus | ||
+ | # 2) Use the following format in cont-check.cfg | ||
+ | # <TEST NAME>;< | ||
+ | # | ||
+ | # < | ||
+ | # the bb-hosts file | ||
+ | # < | ||
+ | # | ||
+ | # | ||
+ | # not found | ||
+ | # | ||
+ | # < | ||
+ | # < | ||
+ | # < | ||
+ | # The PCRE content to check for | ||
+ | # < | ||
+ | # The "good if NOT matched" | ||
+ | # < | ||
+ | # This is a 3-part field: | ||
+ | # < | ||
+ | # Where < | ||
+ | # < | ||
+ | # | ||
+ | # *) tNN <- URL timeout, in seconds | ||
+ | # *) p <- Use the default (http) proxy | ||
+ | # *) P <- Use the default secure (https) proxy | ||
+ | # *) g <- Default < | ||
+ | # This changes it to GET. | ||
+ | # *) r <- Follow page redirects (internal to curl) | ||
+ | # *) R <- Follow page redirects (new curl session) | ||
+ | # (Currently assumes to use the http proxy) | ||
+ | # *) u <- Use an alternate User-Agent string | ||
+ | # (Currently hard-coded for Mozilla/ | ||
+ | # | ||
+ | # EXAMPLES: | ||
+ | # ========= | ||
+ | # () Simple HTTP valid-response check: | ||
+ | # | ||
+ | # () HTTP valid-response with https proxy: | ||
+ | # | ||
+ | # | ||
+ | # () Basic content check: | ||
+ | # | ||
+ | # () Content check with custom timeout and http proxy: | ||
+ | # | ||
+ | # () Reverse content check: | ||
+ | # | ||
+ | # () Combined " | ||
+ | # | ||
+ | # | ||
+ | # () Simple one-page form submission content check: | ||
+ | # | ||
+ | # () Multi-page form submission content check: | ||
+ | # | ||
+ | # | ||
+ | # REVISION HISTORY: | ||
+ | # ================= | ||
+ | # Ver. Date Author | ||
+ | # ---- ---- ------ | ||
+ | # v1.0 1-2-2008 | ||
+ | # v1.1 1-3-2008 | ||
+ | # v1.3 1-3-2008 | ||
+ | # v1.4 1-7-2008 | ||
+ | # Added logic to deal with URLs containing ". | ||
+ | # v1.5 1-8-2008 | ||
+ | # Minor change to the debugging flags. | ||
+ | # v1.6 1-10-2008 | ||
+ | # | ||
+ | # v1.7 1-16-2008 | ||
+ | # v1.8 1-18-2008 | ||
+ | # | ||
+ | # good portion of the code to allow it cleanly | ||
+ | # work with the new feature. | ||
+ | # Also added a proxy option. | ||
+ | # v1.9 1-23-2008 | ||
+ | # v1.10 1-28-2008 | ||
+ | # | ||
+ | # v1.11 1-30-2008 | ||
+ | # the above comment section for readability, | ||
+ | # added additional comments to be more friendly | ||
+ | # to others using/ | ||
+ | # an " | ||
+ | # v1.12 3-24-2008 | ||
+ | # One method has curl follow the redirect itself, | ||
+ | # the other opens a new curl session to the | ||
+ | # | ||
+ | # v1.21 4-29-2008 | ||
+ | # | ||
+ | # v1.22 4-30-2008 | ||
+ | # bits of code that I thought ugly ways of doing | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # TODO: | ||
+ | # ===== | ||
+ | # 1 - | ||
+ | # (i.e. content check initial page, submit data, content check resulting | ||
+ | # page) | ||
+ | # 2 - With the addition of the < | ||
+ | # be good to make this script threadable to improve performance. | ||
+ | # 3 - The User-Agent option should be configuratable via the config | ||
+ | # file. | ||
+ | ################################################################################ | ||
+ | use strict; | ||
+ | |||
+ | # USER-MODIFIABLE CONSTANTS: | ||
+ | # ========================== | ||
+ | # Default Values | ||
+ | use constant DEFAULT_TO => 15; # Default http timeout in seconds | ||
+ | use constant HTTP_PROXY => " | ||
+ | use constant HTTPS_PROXY => " | ||
+ | use constant COOKIE_DIR => "/ | ||
+ | use constant ALT_USER_AGENT => " | ||
+ | |||
+ | # Hobbit Paths And Options | ||
+ | my $BBDISP | ||
+ | my $BBPROG | ||
+ | my $BBHOSTGREP = $ENV{' | ||
+ | my $CFGPATH | ||
+ | my $CFGFILE | ||
+ | #} location... | ||
+ | use constant COLUMN => " | ||
+ | use constant BBTAG => " | ||
+ | |||
+ | ################################################################################ | ||
+ | # No User-Servicable Parts Below! | ||
+ | # Removal of seal voids warranty! | ||
+ | # Qualified service personel only! | ||
+ | ################################################################################ | ||
+ | # CONSTANTS: | ||
+ | # ========== | ||
+ | # Function Return Codes | ||
+ | use constant BAD_ARGS => -2; # Bad arguments, or not enough (< | ||
+ | use constant PASS => -1; # The primary matching objective succeeded | ||
+ | use constant UNKNOWN => 0; # An unknown error occurred | ||
+ | use constant FAIL => 1; # The primary matching objective failed | ||
+ | use constant PROXY_ERR => 5; # Error with the proxy | ||
+ | use constant DNS_ERR => 6; # Err, we couldn' | ||
+ | use constant CONN_ERR => 7; # Failed to connect to the host | ||
+ | use constant TIMEDOUT => 28; # Http timeout while retrieving URL | ||
+ | use constant POST_ERR => 34; # Problem sending a POST to the server | ||
+ | # Bitwise Encoding Kung-Fu | ||
+ | use constant MAX_ERR => 512; # Max error number (largest 9-bit number) | ||
+ | use constant SHIFT => 10; # Shift by 10 bits | ||
+ | use constant MASK => 1023; # 2^10-1 = 10-bit number | ||
+ | use constant BASE => -1; # The no. encoded in the lower 9 bits | ||
+ | use constant HIDDEN => 1; # The no. encoded from the 10th bit | ||
+ | # Urlplus Options | ||
+ | use constant NONE => " | ||
+ | use constant FIND => " | ||
+ | use constant NOFIND => " | ||
+ | use constant BOTH => " | ||
+ | use constant POST => " | ||
+ | # | ||
+ | use constant PROXY => -1; | ||
+ | use constant NO_PROXY => 0; | ||
+ | use constant SECURE_PROXY => 1; | ||
+ | # | ||
+ | use constant POST_FORM => 0; # Submit form data using " | ||
+ | use constant GET_FORM => 1; # Submit form data using " | ||
+ | # | ||
+ | use constant SEPREDIR => -1; # Follow redirects (new session) | ||
+ | use constant NOREDIR => 0; # Don't follow redirects (default) | ||
+ | use constant REDIRECT => 1; # Follow redirects (within curl) | ||
+ | # Miscellaneous | ||
+ | use constant TOK_SEP => ";"; | ||
+ | use constant TRUE => 0; | ||
+ | use constant FALSE => -1; | ||
+ | |||
+ | # GLOBAL VARIABLES: | ||
+ | # ================= | ||
+ | # "use constant" | ||
+ | my $TOK_SEP=TOK_SEP; | ||
+ | my $HTTP_PROXY=HTTP_PROXY; | ||
+ | my $HTTPS_PROXY=HTTPS_PROXY; | ||
+ | my $BBTAG=BBTAG; | ||
+ | my $COLUMN=COLUMN; | ||
+ | my $COOKIE_DIR=COOKIE_DIR; | ||
+ | |||
+ | my $user_agent=undef; | ||
+ | |||
+ | my $hostline = undef; | ||
+ | my $opts = undef; | ||
+ | my $url = undef; | ||
+ | my @post = undef; | ||
+ | my $cont = undef; | ||
+ | my $nocont = undef; | ||
+ | my $errStep = undef; | ||
+ | # | ||
+ | my $option = undef; | ||
+ | my $timeout = undef; | ||
+ | my $proxy = undef; | ||
+ | my $gp_method = undef; | ||
+ | my $redirect = undef; | ||
+ | # | ||
+ | my $urlhosts; | ||
+ | my $color; | ||
+ | my $msg = undef; | ||
+ | my $debug1 = undef; | ||
+ | my $debug2 = undef; | ||
+ | my $debug3 = undef; | ||
+ | |||
+ | |||
+ | # ========== | ||
+ | # MAIN LOOP: | ||
+ | # ========== | ||
+ | # " | ||
+ | # These are only useful when modifying this script. | ||
+ | my $arg1 = $ARGV[0]; | ||
+ | if ($arg1) { | ||
+ | if ( $arg1 eq " | ||
+ | elsif ( $arg1 eq " | ||
+ | elsif ( $arg1 eq " | ||
+ | else { print " | ||
+ | } | ||
+ | |||
+ | |||
+ | # High-level outline: | ||
+ | # ------------------- | ||
+ | # 1) Get a list of the hosts using this script | ||
+ | # 2) Process the hosts using this script | ||
+ | # 2A) Get all the urlplus arguments | ||
+ | # 2B) Make sure the host was defined in bb-hosts | ||
+ | # 2Bb) Parse any optional flags | ||
+ | # 2C) Perform the content/ | ||
+ | # 2D) Report back to the Hobbit server | ||
+ | |||
+ | # 1) Get a list of the hosts using this script | ||
+ | my @hostgrepin = qx($BBHOSTGREP $BBTAG); | ||
+ | foreach $hostline (@hostgrepin) | ||
+ | { | ||
+ | # Get all the applicable hosts | ||
+ | my( undef, $machine, undef, $tag ) = split / /, $hostline; | ||
+ | $urlhosts-> | ||
+ | } | ||
+ | |||
+ | # 2) Process the hosts using this script | ||
+ | my @hostgrepin = qx(cat $CFGPATH/ | ||
+ | foreach $hostline (@hostgrepin) | ||
+ | { | ||
+ | # 2A) Get all the urlplus arguments | ||
+ | # --------------------------------- | ||
+ | chomp($hostline); | ||
+ | my( $machine, $type ) = split /$TOK_SEP/, $hostline; | ||
+ | if ( length($machine) <= 1 ) { next; } # ignore blank lines | ||
+ | if ( $machine =~ /\s*#.*/ ) { next; } # ignore comment lines | ||
+ | |||
+ | # Ignore unknown content check types | ||
+ | if ($type ne FIND && $type ne NOFIND && $type ne BOTH && | ||
+ | $type ne POST && $type ne NONE) | ||
+ | { | ||
+ | # ignore unknown content check types | ||
+ | print " | ||
+ | next; | ||
+ | } | ||
+ | |||
+ | # Get all the tokens, depending on the content check type | ||
+ | if ( $type eq NONE ) { | ||
+ | ( undef, | ||
+ | } elsif ( $type eq BOTH ) { | ||
+ | ( undef, | ||
+ | chomp($cont); | ||
+ | } elsif ( $type eq POST ) { | ||
+ | ( undef, | ||
+ | chomp($cont); | ||
+ | } else { | ||
+ | ( undef, | ||
+ | chomp($cont); | ||
+ | } | ||
+ | chomp($opts); | ||
+ | |||
+ | # 2B) Make sure the host was defined in bb-hosts | ||
+ | # ---------------------------------------------- | ||
+ | if (!$urlhosts-> | ||
+ | print " | ||
+ | next; | ||
+ | } | ||
+ | |||
+ | # Debugging | ||
+ | if ( $debug2 ) { | ||
+ | print " | ||
+ | if ( $debug3 ) { print " | ||
+ | if ( $type eq FIND ) { | ||
+ | print " | ||
+ | } elsif ( $type eq NOFIND ) { | ||
+ | print " | ||
+ | } else { | ||
+ | print " | ||
+ | } | ||
+ | print " | ||
+ | } | ||
+ | |||
+ | # 2Bb) Parse any optional flags | ||
+ | # ----------------------------- | ||
+ | # Reset the options to default | ||
+ | $timeout = DEFAULT_TO; | ||
+ | $proxy = NO_PROXY; | ||
+ | $gp_method = POST_FORM; | ||
+ | $redirect = NOREDIR; | ||
+ | $user_agent = undef; | ||
+ | |||
+ | # Update the options (if any) | ||
+ | if ( $opts ) { | ||
+ | # Get the defined options | ||
+ | $option = undef; | ||
+ | my @opts = split /,/, $opts; | ||
+ | foreach $option (@opts) { | ||
+ | # Option tNN <- Timeout in seconds | ||
+ | if ( $option =~ / | ||
+ | $timeout = substr $option, 1; | ||
+ | } | ||
+ | |||
+ | # Option p/P <- Use the http/https proxy | ||
+ | if ( $option =~ /p/ ) { | ||
+ | $proxy = PROXY; | ||
+ | } elsif ( $option =~ /P/ ) { | ||
+ | $proxy = SECURE_PROXY; | ||
+ | } | ||
+ | |||
+ | # Option g <- Form get/post method | ||
+ | if ( $option =~ /g/ ) { | ||
+ | if ($type ne POST) { | ||
+ | # Only < | ||
+ | print " | ||
+ | next; | ||
+ | } | ||
+ | $gp_method = GET_FORM; | ||
+ | } | ||
+ | |||
+ | # Option R <- Follow redirects | ||
+ | if ( $option =~ /R/ ) { | ||
+ | $redirect = SEPREDIR; | ||
+ | } elsif ( $option =~ /r/ ) { | ||
+ | $redirect = REDIRECT; | ||
+ | } | ||
+ | |||
+ | # Option u <- Use alternate User-Agent string | ||
+ | if ( $option =~ /u/ ) { | ||
+ | $user_agent = ALT_USER_AGENT; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | # 2C) Perform the content check | ||
+ | # ----------------------------- | ||
+ | $color = " | ||
+ | $msg = "<a href=' | ||
+ | |||
+ | |||
+ | # Get the URL output | ||
+ | my $output = showUrl($url, | ||
+ | $output = escapeString($output); | ||
+ | $cont = escapeString($cont); | ||
+ | my $contRet = undef; | ||
+ | my $postRet = undef; | ||
+ | |||
+ | # Check for non-green situations | ||
+ | if ( $type eq FIND ) { | ||
+ | # --- < | ||
+ | $contRet = contFind($output, | ||
+ | if ( $contRet == FAIL ) { | ||
+ | $color=" | ||
+ | $msg.=" | ||
+ | } elsif ( $contRet != PASS ) { | ||
+ | $color=" | ||
+ | $msg.=decodeErr($contRet, | ||
+ | } | ||
+ | } elsif ( $type eq NOFIND ) { | ||
+ | # --- < | ||
+ | $contRet = contNofind($output, | ||
+ | if ( $contRet == FAIL ) { | ||
+ | $color=" | ||
+ | $msg.=" | ||
+ | } elsif ( $contRet != PASS ) { | ||
+ | $color=" | ||
+ | $msg.=decodeErr($contRet, | ||
+ | } | ||
+ | } elsif ( $type eq BOTH ) { | ||
+ | # --- < | ||
+ | $contRet = contFind($output, | ||
+ | if ( $contRet == PASS ) { | ||
+ | $contRet = contNofind($output, | ||
+ | if ( $contRet == FAIL ) { | ||
+ | $color=" | ||
+ | $msg.=" | ||
+ | } elsif ( $contRet != PASS ) { | ||
+ | $color=" | ||
+ | $msg.=decodeErr($contRet, | ||
+ | } | ||
+ | } elsif ( $contRet == FAIL ) { | ||
+ | $color=" | ||
+ | $msg.=" | ||
+ | } else { | ||
+ | $color=" | ||
+ | $msg.=decodeErr($contRet, | ||
+ | } | ||
+ | } elsif ( $type eq POST ) { | ||
+ | # --- < | ||
+ | $postRet = contPost($url, | ||
+ | if ( $postRet > MAX_ERR ) { | ||
+ | # IF we're here, the error code & the test | ||
+ | # step the error occurred on are encoded. | ||
+ | $contRet = bitwiseDecode($postRet, | ||
+ | $errStep = bitwiseDecode($postRet, | ||
+ | } else { $contRet = $postRet; $errStep = 1; } | ||
+ | if ( $contRet == BAD_ARGS ) { | ||
+ | # Yellow, because there wasn't enough | ||
+ | # info to actually do the content check. | ||
+ | $color=" | ||
+ | $msg.=" | ||
+ | } elsif ( $contRet == FAIL ) { | ||
+ | $color=" | ||
+ | $msg.=" | ||
+ | } elsif ( $contRet != PASS ) { | ||
+ | $color=" | ||
+ | $msg.=" | ||
+ | } | ||
+ | } else { | ||
+ | # --- < | ||
+ | $contRet = curlError($output); | ||
+ | if ( $contRet != PASS ) { | ||
+ | $color=" | ||
+ | $msg.=decodeErr($contRet, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | # If we enter this block, everything' | ||
+ | if ( $color eq " | ||
+ | if ($type eq FIND) { | ||
+ | $msg.=" | ||
+ | } elsif ($type eq NOFIND) { | ||
+ | $msg.=" | ||
+ | } elsif ($type eq BOTH) { | ||
+ | $msg.=" | ||
+ | } elsif ($type eq POST) { | ||
+ | $msg.=" | ||
+ | } else { # $type eq NONE | ||
+ | $msg.=" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | # 2D) Report back to the Hobbit server | ||
+ | # ------------------------------------ | ||
+ | qx($BBPROG $BBDISP " | ||
+ | if ( !$opts ) { $opts = " | ||
+ | print " | ||
+ | if ( $debug1 ) { print " | ||
+ | } | ||
+ | |||
+ | |||
+ | # ============= | ||
+ | # SUB-ROUTINES: | ||
+ | # ============= | ||
+ | # High-level outline: | ||
+ | # ------------------- | ||
+ | # GET url, searchString, | ||
+ | # output= curlError(escapeString(showUrl(url))) | ||
+ | # SWITCH (< | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # END | ||
+ | # IF result OKAY THEN | ||
+ | # | ||
+ | # ELSE | ||
+ | # | ||
+ | # | ||
+ | # ENDIF | ||
+ | |||
+ | # | ||
+ | # The below are helper/ | ||
+ | # | ||
+ | sub escapeString | ||
+ | # Purpose: | ||
+ | # Inputs: | ||
+ | # Outputs: | ||
+ | { | ||
+ | my($str) = @_; | ||
+ | |||
+ | # URL Encoding: | ||
+ | # " | ||
+ | $str =~ s/"/ | ||
+ | |||
+ | return $str; | ||
+ | } | ||
+ | |||
+ | |||
+ | sub curlError | ||
+ | # Purpose: | ||
+ | # is a valid response code | ||
+ | # Inputs: | ||
+ | # Outputs: | ||
+ | # | ||
+ | { | ||
+ | my($urlout) = @_; | ||
+ | my $ret = PASS; | ||
+ | |||
+ | # CURLcode errors that we check for | ||
+ | # (http:// | ||
+ | # | ||
+ | # 0 <= CURLE_OK | ||
+ | # No problems here, carry on | ||
+ | # 5 <= CURLE_COULDNT_RESOLVE_PROXY | ||
+ | # | ||
+ | # 6 <= CURLE_COULDNT_RESOLVE_HOST | ||
+ | # Yep, couldn' | ||
+ | # 7 <= CURLE_COULDNT_CONNECT | ||
+ | # Curl couldn' | ||
+ | # 28 <= CURLE_OPERATION_TIMEDOUT | ||
+ | # Curl timed out while trying to get the URL. This | ||
+ | # | ||
+ | # 34 <= CURLE_HTTP_POST_ERROR | ||
+ | # | ||
+ | # to the http server | ||
+ | # 52 <= CURLE_GOT_NOTHING | ||
+ | # The web server didn't return any content | ||
+ | # 56 <= CURLE_RECV_ERROR | ||
+ | # | ||
+ | # an issue with the proxy). | ||
+ | |||
+ | if ( !$urlout || $urlout =~ /curl: \(0\).*/ || | ||
+ | $urlout =~ /curl: \(52\).*/ ) { | ||
+ | return PASS; | ||
+ | } else { | ||
+ | if ( $urlout =~ /curl: \(5\).*/ || | ||
+ | $urlout =~ /curl: \(56\).*/ ) { $ret=PROXY_ERR; | ||
+ | elsif ( $urlout =~ /curl: \(6\).*/ ) { $ret=DNS_ERR; | ||
+ | elsif ( $urlout =~ /curl: \(7\).*/ ) { $ret=CONN_ERR; | ||
+ | elsif ( $urlout =~ /curl: \(28\).*/ ) { $ret=TIMEDOUT; | ||
+ | elsif ( $urlout =~ /curl: \(34\).*/ ) { $ret=POST_ERR; | ||
+ | elsif ( $urlout =~ /curl: no URL specified!/ ) { $ret=UNKNOWN; | ||
+ | } | ||
+ | |||
+ | return $ret; | ||
+ | } | ||
+ | |||
+ | |||
+ | sub decodeErr | ||
+ | # Purpose: | ||
+ | # | ||
+ | # Inputs: | ||
+ | # | ||
+ | # Outputs: | ||
+ | { | ||
+ | my($err, $urlout) = @_; | ||
+ | |||
+ | if ( $err == PROXY_ERR ) { return "Proxy error: $urlout"; | ||
+ | elsif ( $err == DNS_ERR ) { return "DNS error"; | ||
+ | elsif ( $err == CONN_ERR ) { return " | ||
+ | elsif ( $err == TIMEDOUT ) { return "Http request timed out"; } | ||
+ | elsif ( $err == POST_ERR ) { return "Error during http POST"; } | ||
+ | |||
+ | return " | ||
+ | } | ||
+ | |||
+ | |||
+ | sub bitwiseEncode | ||
+ | # Purpose: | ||
+ | # that the base (lower bit-boundary) number must be less | ||
+ | # than MAX_ERR (9-bit number). | ||
+ | # works with unsigned integers. | ||
+ | # Inputs: | ||
+ | # | ||
+ | # Outputs: | ||
+ | { | ||
+ | my($base, $hidden) = @_; | ||
+ | return ($base | ($hidden << SHIFT)); | ||
+ | } | ||
+ | |||
+ | |||
+ | sub bitwiseDecode | ||
+ | # Purpose: | ||
+ | # Inputs: | ||
+ | # | ||
+ | # HIDDEN to decode out the " | ||
+ | # Outputs: | ||
+ | { | ||
+ | my($encoded, | ||
+ | my $base = $encoded & MASK; | ||
+ | |||
+ | if ( $decPos eq HIDDEN ) { return (($encoded - $base) >> SHIFT); } | ||
+ | # else | ||
+ | return $base; | ||
+ | } | ||
+ | |||
+ | |||
+ | # | ||
+ | # All of the above code is essentially a wrapper | ||
+ | # for the below functions. | ||
+ | # | ||
+ | sub showUrl | ||
+ | # Purpose: | ||
+ | # Inputs: | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # Outputs: | ||
+ | { | ||
+ | my($url, $tout, $proxy, $redir, $submit, $method) = @_; | ||
+ | my $ret = undef; | ||
+ | my $pstr = ""; | ||
+ | my $form = ""; | ||
+ | my $other = ""; | ||
+ | |||
+ | # This technically isn't needed, but | ||
+ | # it's useful fault-tolerance | ||
+ | if ( !$tout ) { $tout = DEFAULT_TO; } | ||
+ | |||
+ | # Get the proxy | ||
+ | # (curl option: -x < | ||
+ | if ( $proxy == PROXY ) | ||
+ | { $pstr=" | ||
+ | elsif ( $proxy == SECURE_PROXY ) | ||
+ | { $pstr=" | ||
+ | |||
+ | # Are we following redirects? | ||
+ | if ( $redir == REDIRECT ) { | ||
+ | $other.=" | ||
+ | } | ||
+ | |||
+ | # Use an alternate User-Agent string? | ||
+ | if ( $user_agent ) { | ||
+ | $other.=" | ||
+ | } | ||
+ | |||
+ | # Get the form submission (if any) | ||
+ | if ( $submit && $method == GET_FORM ) { | ||
+ | $form = "-d \" | ||
+ | } elsif ( $submit ) { | ||
+ | # This does graceful error handling | ||
+ | # if $method is an invalid value | ||
+ | $form = "-d \" | ||
+ | } | ||
+ | |||
+ | #Curl options: | ||
+ | # | ||
+ | #These are for all tests: | ||
+ | # -s <- Don't output a progress bar | ||
+ | # -k <- Trust all SSL certificates | ||
+ | # -S <- Shows an error message if curl fails | ||
+ | # ( 2>&1 : redirect stderr to stdout so we can | ||
+ | # actually get whatever error curl returns) | ||
+ | #These are user-configurable: | ||
+ | # -m NN <- Don't take longer than $tout seconds to run | ||
+ | # $pstr <- The proxy option (or blank if no proxy used) | ||
+ | |||
+ | if ( $redir == SEPREDIR ) { | ||
+ | # -I <- Only display the headers (to get the " | ||
+ | $url=qx(curl -S -s -k -m $tout -b $COOKIE_DIR $other -I $pstr $form " | ||
+ | $ret=qx(curl -S -s -k -m $tout -b $COOKIE_DIR $other -L -x $HTTP_PROXY $form " | ||
+ | #print "*** $url\n$ret"; | ||
+ | } else { | ||
+ | $ret=qx(curl -S -s -k -m $tout -b $COOKIE_DIR $other $pstr $form " | ||
+ | } | ||
+ | |||
+ | return $ret; | ||
+ | } | ||
+ | |||
+ | |||
+ | sub contFind | ||
+ | # Purpose: | ||
+ | # must exist for the status to be green). | ||
+ | # Inputs: | ||
+ | # | ||
+ | # Outputs: | ||
+ | # FAIL if $cont isn't found, | ||
+ | # | ||
+ | { | ||
+ | my($urlout, $cont) = @_; | ||
+ | my $ceRet = curlError($urlout); | ||
+ | |||
+ | if ( $ceRet == PASS ) { | ||
+ | # If we're here, we at least didn't have any | ||
+ | # problems retrieving the URL | ||
+ | if ( $urlout =~ m/$cont/ ) { return PASS; } | ||
+ | else { return FAIL; } | ||
+ | } | ||
+ | |||
+ | return $ceRet; | ||
+ | } | ||
+ | |||
+ | |||
+ | sub contNofind | ||
+ | # Purpose: | ||
+ | # must not exist for the status to be green). | ||
+ | # Inputs: | ||
+ | # | ||
+ | # Outputs: | ||
+ | # FAIL if $cont IS found, | ||
+ | # | ||
+ | { | ||
+ | my($urlout, $cont) = @_; | ||
+ | my $ceRet = curlError($urlout); | ||
+ | |||
+ | if ( $ceRet == PASS ) { | ||
+ | # If we're here, we at least didn't have any | ||
+ | # problems retrieving the URL | ||
+ | if ( $urlout =~ m/$cont/ ) { return FAIL; } | ||
+ | else { return PASS; } | ||
+ | } | ||
+ | |||
+ | return $ceRet; | ||
+ | } | ||
+ | |||
+ | |||
+ | sub contPost | ||
+ | # Purpose: | ||
+ | # | ||
+ | # Inputs: | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # | ||
+ | # Outputs: | ||
+ | { | ||
+ | my($url, $tout, $proxy, $redirect, $method, @cont) = @_; | ||
+ | my $len = $#cont + 1; # Size of @cont | ||
+ | my $output = undef; | ||
+ | my $contRet = undef; | ||
+ | my $submission = undef; | ||
+ | my $shiftCont; | ||
+ | my $cont = undef; | ||
+ | |||
+ | # --START-- DEBUG | ||
+ | if ( $debug2 ) { | ||
+ | my $temp; | ||
+ | if ($method eq GET_FORM) { $temp=" | ||
+ | print " | ||
+ | my $cnt = 0; | ||
+ | foreach $cont (@cont) { | ||
+ | print " | ||
+ | $cnt = $cnt + 1; | ||
+ | } | ||
+ | } | ||
+ | # --END-- DEBUG | ||
+ | |||
+ | # Make sure we have enough arguments: | ||
+ | # Minimum 3 arguments (< | ||
+ | # or any even number after that (;< | ||
+ | if ( $len < 3 || ($len-3)%2 != 0 ) { return BAD_ARGS; } | ||
+ | |||
+ | # Do the first-page content check: | ||
+ | #print " | ||
+ | #print " | ||
+ | $output = showUrl($url, | ||
+ | $output = escapeString($output); | ||
+ | $shiftCont = shift @cont; | ||
+ | $cont = escapeString($shiftCont); | ||
+ | #print " | ||
+ | $contRet = contFind($output, | ||
+ | if ( $contRet != PASS ) { return $contRet; }; | ||
+ | |||
+ | # Now hit submit on the first page, and check | ||
+ | # the content of the resulting page: | ||
+ | my $level = 2; | ||
+ | #print " | ||
+ | $submission = shift @cont; | ||
+ | #print " | ||
+ | $output = showUrl($url, | ||
+ | $output = escapeString($output); | ||
+ | $shiftCont = shift @cont; | ||
+ | #print " | ||
+ | $cont = escapeString($shiftCont); | ||
+ | $contRet = contFind($output, | ||
+ | if ( $contRet != PASS ) { return bitwiseEncode($contRet, | ||
+ | |||
+ | # Finally, loop through each additional (optional) page to check: | ||
+ | for ( $level++, $submission=shift @cont ; $submission ; | ||
+ | $submission=shift @cont, $level++ ) { | ||
+ | #print " | ||
+ | #print " | ||
+ | $output = showUrl($url, | ||
+ | $output = escapeString($output); | ||
+ | $shiftCont = shift @cont; | ||
+ | #print " | ||
+ | $cont = escapeString($shiftCont); | ||
+ | $contRet = contFind($output, | ||
+ | |||
+ | if ( $contRet != PASS ) { | ||
+ | # No need to keep checking if we've failed | ||
+ | return bitwiseEncode($contRet, | ||
+ | } | ||
+ | } | ||
+ | |||
+ | return $contRet; | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ===== Known Bugs and Issues ===== | ||
+ | None at this time | ||
+ | |||
+ | ===== To Do ===== | ||
+ | * Need more testing on a larger variety of hosts, mostly for inclusion of new features. | ||
+ | * Integrate user-provided changes. | ||
+ | * This was supposed to be just a simple script that quickly grew to be fairly feature-rich. | ||
+ | * WWW::Mech isn't as efficient as ' | ||
+ | |||
+ | |||
+ | |||
+ | ===== Credits ===== | ||
+ | |||
+ | Thanks to everyone who has made use of URLPlus and provided feedback on the Xymon mailing list. There are too many of you to name here, but suffice to say, you are providing inspiration for me to continue the development of this add-on. | ||
+ | |||
+ | ===== Changelog ===== | ||
+ | |||
+ | * **2008-01-02** | ||
+ | * Initial creation | ||
+ | * **2008-01-28** | ||
+ | * Initial release to Xymonton | ||
+ | * **2009-09-01** | ||
+ | * v1.22 uploaded | ||