#!/usr/bin/perl

use strict;
use vars qw($opt_p $opt_n $opt_bench $opt_debug $opt_version 
	    $opt_v $opt_help
	    $opt_cert $opt_key $opt_cafile $opt_cadir
	    );
use lib qw(lib);
use Net::SSL;
use File::Basename;
use Benchmark;

use Getopt::Long;
&GetOptions ('p:s' => \$opt_p, 
	     'proxy:s' => \$opt_p, 
	     'bench:n' => $opt_bench,
	     'd' => \$opt_debug,
	     'version:i' => \$opt_version,
	     'v:i' => \$opt_version,
	     'h' => \$opt_help,
	     'help' => \$opt_help,
	     'cert:s' => \$opt_cert,
	     'key:s' => \$opt_key,
	     'CAfile:s' => \$opt_cafile,
	     'CAdir:s' => \$opt_cadir,
	     );

my $basename = &File::Basename::basename($0);

# define sub first, in case you are reading the source :)
sub help {
    
    print <<HELP;
Usage: $basename [-d] [-b=NNN] [-h] [-p proxy_name:port] [-CAfile=FILE] [GET|HEAD] [ssl_server_name] [port]

  -d  Debug mode
  -b  Benchmark NNN times, good test for memory leaks
  -h  This help message
  -p  Proxy server, via CONNECT method, localhost:80 format

  -cert  client certificate file
  -key   private key file

  -CAfile CA certificates file, use certs/ca-bundle.crt for primary root certs 
  
 method          defaults to HEAD
 ssl_server_name defaults to www.nodeworks.com
 port            defaults to 443

These are equivalent:
 
  ./net_ssl_test
  ./net_ssl_test HEAD www.nodeworks.com 443

This might be how you debug your proxy:

  ./net_ssl_test -d -p http://proxy_name:80 www.nodeworks.com

Note http:// on proxy hostname is stripped off, and is 
meaningless to Crypt::SSLeay.

HELP
;
    exit;
}

if($opt_help) {
    &help;
};

if($opt_debug) {
    eval "use LWP::Debug qw(+)";
}

my $method = (@ARGV && $ARGV[0] =~ /^[A-Z]+$/) ? shift : "HEAD";
my($host, $port, $path);
if($opt_bench) {
    $host = shift || die("need host, run like ./$basename HEAD yourhost.com.foo");
} else {
    $host = shift || "www.nodeworks.com";
}
if($host =~ m|^(https://)?([^/:]+)(:(\d+))?(/.*)?$|) {
    ($host, $port, $path) = ($2, $4, $5);	
}

$port ||= shift || 443;
$path ||= '/';

if($opt_n) {
    $ENV{NO_PROXY} = $opt_n;
}

$ENV{HTTPS_PROXY} = $opt_p;
$ENV{HTTPS_CERT_FILE} = $opt_cert;
$ENV{HTTPS_KEY_FILE} = $opt_key;

$opt_cafile && ( $ENV{HTTPS_CA_FILE} = $opt_cafile );
$opt_cadir  && ( $ENV{HTTPS_CA_DIR} = $opt_cadir   );

if($opt_version) {
    grep($opt_version eq $_, '2', '3', '23')
	|| die("$opt_version must be one of 2, 3, or 23");
    $ENV{HTTPS_VERSION} = $opt_version;
}

unless(eval { &ssl_connect() }) {
    print <<OUT;
== FAILED TO CONNECT ==
Error: $@ 

If you need to use a proxy, please pass it in as an argument like  

  ./net_ssl_test -p 127.0.0.1:8080

which sets \$ENV{HTTPS_PROXY} for you.

OUT
    ;
}

if($opt_bench) {
    timethis($opt_bench, sub { &ssl_connect() });   
}
    

sub ssl_connect {
    my $sock = Net::SSL->new(
			     PeerAddr => $host,
			     PeerPort => $port,
			     SSL_Debug => $opt_debug,
			     Timeout => 15,
			     );
    $sock || ($@ ||= "no Net::SSL connection established");
    my $error = $@;
    $error && die("Can't connect to $host:$port; $error; $!");
  
    my $out;
    $out .= "WEB SITE       : $host:$port\n";
    $out .= "CIPHER         : ".$sock->get_cipher."\n";
    my $cert = $sock->get_peer_certificate;

    $out .= "CERT SUBJECT   : ".$cert->subject_name."\n";
    $out .= "CERTIFIED BY   : ".$cert->issuer_name."\n";
    $out .= "CERT NOT BEFORE: ".$cert->not_before."\n";
    $out .= "CERT NOT AFTER : ".$cert->not_after."\n";

    $out .= "\n";
    $sock->print("$method $path HTTP/1.0\n\n");
    print $out;
    $out = '';

    my $buf = '';
    while ($sock->read($buf, 1024)) {
	$out .= $buf;
    }

    unless($opt_bench) {
	print $out;
    }

    1;
}

