Information Technology Grimoire

Version .0.0.1

IT Notes from various projects because I forget, and hopefully they help you too.

Perl Script to Test URI Status

This Perl script was a little test to see the URI status for multiple URIs, related services, status codes, and response times. The purpose of this Perl script is for base-lining multiple websites and generating a before and after reports, automating your URI status testing.

For example, if we do a firewall change we want to know if all ports and sites are still accessible. This script can tell us quickly the status of all URIs in the list.

Please give credit for it’s creation. It tests a few things, mostly as a demonstration of what can easily be scripted in a few hours of Perl. If you would like a custom script created for you, please contact us for custom Perl programming.

Here are a few of the things this URI Testing script demonstrates:

  • HTTP Status codes

  • Windows ANSI Terminal Colors

  • Response load time (doesn’t include all images, only HTTP)

  • HTTP Response size (for baselining)

  • Specific Text on the HTTP/S page

  • Open Ports

  • Additional HTTP Status Messages

As written, it could be used for both server checks and website status checks, but a good improvement would be to add a mail feature or other similar log so you can run your URI tests on a cron schedule.

Please let use know if you use it. If you want help with your Perl scripting or have an idea for something you want written in Perl, please contact us Perl Development.

#!/usr/bin/perl

# please give credit to somesite.com

use strict;
use warnings;

use URI;                    # to strip domain from uri
use HTTP::Tiny;             # get html, check status, headers
use Data::Validate::URI;    # verify it's a URI
use Time::HiRes qw (time);  # for timing response, and net ping response
use Win32::Console::ANSI;   # colors on prompt
use Term::ANSIColor;        # colors on prompt
use IO::Socket::PortState qw(check_ports);

# don't spit it out all at once, but as we get the info update screen
$|++;

# what exact string are we looking for on the page?
my $textcheck = 'contact-form-7';

# list of uris to check
# note, it converts to hosts for most checks
my @uris = qw(
    http://somesite.com:80
    http://somesite.com/404erroh
    http://aquaponics-system.com
    http://jse.co.za/
    https://mybroadband.co.za
    http://www.junkmail.co.za
    http://1.0.0.1:565
);

# when is something considered "dead"?
my $timeout = 4;

# what ports do we care about?
my %check = (
   tcp => {
      '22'  => { name => 'SSH', },
      '80'  => { name => 'HTTP', },
      '443' => { name => 'HTTPS', },
   },
);

# loop over each URI to see if they are even valid
foreach my $uri (@uris) {
    # only allow valid urls in test, exit early
    my $uriValidator = new Data::Validate::URI();
    unless ($uriValidator->is_web_uri($uri) ) {
        print color("bright_red"),"FAIL: '$uri' is not a valid URI\n", color("reset");
        exit;
    }
}

# loop over each URI, again now that we know they are valid
foreach my $uri (@uris) {

    # extract domain from uri
    my $url = URI->new( $uri );
    my $domain = $url->host;

    # start timer
    my $t0 = time;

    # new instance of HTTP::Tiny from $ARGV
    my $http = HTTP::Tiny->new(timeout => $timeout);
    my $response = $http->get($uri);

    # end timer
    my $t1 = time - $t0;
    my $time = sprintf("%.3f", $t1);  # 3 decimal places

    # HTTP response test
    if ($response->{success}) {
        # wordpress DB error?
        my $html = $response->{content};
        if ($html =~ m/Error establishing a database connection/) {
            print color("bright_green"),"HTTP: DBERR, \t";   # basically a '200 check' (passed)
        } else {
            print color("bright_green"),"HTTP: GOOD, \t";   # basically a '200 check' (passed)
        }
    } else {
        print color("bright_red"),"HTTP: FAIL, \t";
    }

    # time
    if ($time < .5) { print color("bright_green"),"TIME: $time, ", color("reset"); } else { print color("bright_red"),"TIME: $time, ", color("reset"); } # http status code if ($response->{status} =~ m/^2/) {
        print color("bright_green"),"CODE: " . $response->{status} . ",  ", color("reset");
    } elsif ($response->{status} =~ m/^3/) {
        print color("bright_yellow"),"CODE: " . $response->{status} . ",  ", color("reset");
    } else {
        print color("bright_red"),"CODE: " . $response->{status} . ",  ", color("reset");
    }

    #tell us the length
    if (length $response->{content}) {
        print "SIZE: " . length $response->{content};
        print", \t";
    } else {
        print "SIZE: 00000, \t";
    }

    # check for specific text on the page
    my $html = $response->{content};
    if ($html =~/$textcheck/) {
        print color("bright_green"),"TEXT: PASS, ", color("reset");
    } else {
        print color("bright_red"),"TEXT: FAIL, ", color("reset");
    }

   # check open ports from %check
    check_ports($domain,$timeout,\%check);
    my $portcheck =  "PORTS: ";
    foreach my $proto (keys %check){
        foreach my $key (keys %{ $check{$proto} }) {
            if ($check{$proto}{$key}->{open}) {
                $portcheck .=  $check{$proto}{$key}->{name} . ",";
            }
        }
    }

    printf "%-20s\t", $portcheck;

    # which URI we tested, and give it a 35 space block to land in
    printf "%-35s\t", $uri . ",";

    # any other messages that might be helpful
    my $msg = "";
       $msg .= $response->{reason};
    print "MESG: '" . $msg . "'\n";
    print color("reset");
}
Last updated on 20 Jul 2018
Published on 20 Jul 2018