#!/usr/bin/perl
use strict;
use warnings;
use Readonly;
use CGI;

###
### CONSTANTS ###
###

# settings
Readonly my $DEFMIN          => 1024;
Readonly my $DEFMAX          => 20480;
Readonly my $FNAME_LENGTH    => 16;
Readonly my $FNAME_EXTENSION => '.txt';
Readonly my $DEBUG           => 0;
# facts
Readonly my $EICAR_BODY      => 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*';
Readonly my $HARDMIN         => 1024;
Readonly my $HARDMAX         => 20480;
my @RANDOM_CHARS    =  ( 'a' .. 'z', 'A' .. 'Z', '0' .. '9', '_' );

( $DEFMIN < $DEFMAX )   or die("Invalid lower and upper limits!");
( $HARDMIN < $HARDMAX ) or die("Invalid lower and upper limits!");


my $q = CGI -> new();

###
### SUBBIES ###
###
sub dprint {                ## @message ## print all $message-s with dbg fancy
    my $mes;
    return if ( $DEBUG == 0 );
    while (1) {
        $mes = shift or return;
        print "randomfile: DEBUG: $mes\n";
    }
    return;
}

sub minmax_valid {          ## low, high, min, max ## Validate boundaries
    my ($low, $hgh, $min, $max ) = @_;
    # dprint "## $low # $high ## $min # $max ##";
    # If array is wanted, try to crop
    if ( wantarray() ) {
        $low = $min if ( $low <= $min );     # crop low to min
        $low = $max if ( $low >= $max );     # crop low to max
        $hgh = $min if ( $hgh <= $min );     # crop hgh to min
        $hgh = $max if ( $hgh >= $max );     # crop hgh to max
        return ( $low, $hgh, $min, $max );   # return valid low high min max
    }
    # Else just answer if it's OK
    else {
        return 0 if ( $low < $min || $low > $max );
        return 0 if ( $hgh < $min || $hgh > $max );
        return 0 if ( $hgh < $low );
        return 0 if ( $max < $max );
        return 1;
    }
}

sub http_die {              ## $status ## Http-die with $status
  my $status = shift || 400;
  print $q->header ( -type => 'text/plain' , -status => $status );
  exit 1;
}

sub generate_random_string {    # -------
    my $length = shift;
    my $flush = shift;
    my $random_string;
    foreach ( 1 .. $length ) {
        $random_string .= $RANDOM_CHARS[ rand @RANDOM_CHARS ];
    }
    return $random_string;
}

sub print_random_string {       # -------
    my $length = shift;
    foreach ( 1 .. $length ) {
        print $RANDOM_CHARS[ rand @RANDOM_CHARS ];
    }
    return 1;
}

###
### PAREMETER RETRIEVAL & VALIDATION ###
###

# Get parameters from CGI query
$q->import_names;
my $min             = defined ($Q::min)     ? $Q::min   : $DEFMIN;
my $max             = defined ($Q::max)     ? $Q::max   : $DEFMAX;
my $eicar_chance    = defined ($Q::eicar)   ? $Q::eicar : 0;


# Validate min/max against hard min/max
minmax_valid ( $min , $max, $HARDMIN, $HARDMAX  ) or http_die( 400 );

###
### MAIN ###
###

# Generate random output length
my $length = int( $min + rand( $max - $min ) );

# Generate the random filename
my $random_fname  = &generate_random_string($FNAME_LENGTH) . $FNAME_EXTENSION;

# Random throw of EICAR ( 0 to 99 inclusive )
my $eicar_throw = int ( rand ( 100 ) );

#final printing
if ($eicar_throw <= $eicar_chance ) {
    # serve EICAR
    print $q->header();
    print $EICAR_BODY;
} else {
    # serve random content
    print $q->header();
    print_random_string($length);
}

dprint (
    "\$min = $min",
    "\$max = $max",
    "\$eicar_chance = $eicar_chance",
    "\$eicar_throw = $eicar_throw",
    );