AIS-client
view release on metacpan or search on metacpan
package AIS::client;
use 5.006;
$VERSION = 0.07;
use Carp;
use DirDB 0.09; # or any other concurrent-access-safe
# persistence abstraction
# that can store and retreive hash references
# and has a working DELETE method
#
# but if you change it, you'll also need to change
# the lines that refer to DirDB subsequently,
# including the tieing of %{"caller().'::AIS_STASH'}
sub miniget($$$$){
my($HostName, $PortNumber, $Desired, $agent) = @_;
eval <<'ENDMINIGET';
use Socket qw(:DEFAULT :crlf);
$PortNumber ||= 80;
$agent ||= "$ENV{SERVER_NAME}$ENV{SCRIPT_NAME}";
my $iaddr = inet_aton($HostName) || die "Cannot find host named $HostName";
my $paddr = sockaddr_in($PortNumber,$iaddr);
my $proto = getprotobyname('tcp');
socket(SOCK, PF_INET, SOCK_STREAM, $proto) || die "socket: $!";
connect(SOCK, $paddr) || die "connect: $!";
# SOCK->autoflush(1);
my $ofh = select SOCK;
$| = 1;
select $ofh;
my $Query = join("\r\n", # "CRLF"
"GET $Desired HTTP/1.1",
# Do we need a Host: header with an "AbsoluteURI?"
# not needed: http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.2
# but this is trumped by an Apache error message invoking RFC2068 sections 9 and 14.23
"Host: $HostName",
"User-Agent: $agent",
"Connection: close",
'','') ;
print SOCK $Query or croak "could not print to miniget socket";
join('',<SOCK>);
ENDMINIGET
}
sub housekeeping(){
my @deletia;
my $t = time;
while(($k,$v) = each %Sessions){
if ($v->{last_access} < ($t - $maxage)){
push @deletia, $k
};
};
@Sessions{@deletia} = ();
};
sub redirect($){
print <<EOF;
Location: $_[0]
Content-Type: text/html
<HTML><HEAD><TITLE>Relocate </TITLE>
<META HTTP-EQUIV="REFRESH" CONTENT="1;URL=$_[0]">
</HEAD>
<BODY>
<A HREF="$_[0]">
<H1>Trying to relocate to $_[0]</H1>please click
here</A>.
</BODY></HTML>
EOF
};
sub import{
shift;
my %params = @_;
my $Coo;
$ssl_ext = exists($ENV{SSL_CIPHER}) ? 's' : '';
$freq = (defined($params{freq}) ? $params{freq} : 2000);
$maxage = $params{maxage} || 72*60*60;
$aissri = $params{aissri} || 'http://www.pay2send.com/cgi/ais/';
$agent = $params{agent} ||
"http$ssl_ext://$ENV{SERVER_NAME}$ENV{SCRIPT_NAME}";
$SessionPrefix = $params{prefix} || 'AIS'; # 'AIS_session';
eval{
tie %Sessions => DirDB => "${SessionPrefix}_sessions";
};
if($@){
print <<EOF;
Content-Type: text/plain
AIS::client module was not able to open DirDB [${SessionPrefix}_sessions]
eval result:
$@
AIS::client version $VERSION
EOF
exit;
};
if($freq){
housekeeping unless ($$ % $freq)
};
if ($ENV{QUERY_STRING} eq 'LOGOUT'){
# eval <<'LOGOUT';
($Coo) = ($ENV{HTTP_COOKIE} =~ /${SessionPrefix}_session=(\w+)/)
and delete $Sessions{$Coo};
print <<EOF;
Set-Cookie:/${SessionPrefix}_session=
Content-Type: text/html
<html><head><title> LOGGED OUT </title></head>
<body bgcolor=ffffff>
Cookie cleared, you are logged out of "${SessionPrefix}"
<p>
<a href="${aissri}logout">
click here to log out of AIS service $aissri</a>
</body></html>
EOF
exit;
# LOGOUT
};
# check for cookies
($Coo) = ($ENV{HTTP_COOKIE} =~ /${SessionPrefix}_session=(\w+)/);
if($Coo){
# print "Content-Type: text/plain\n\n";
# print "We have a cookie: $Coo\n";
# print( %{$Sessions{$Coo}});
# exit;
# Do we have an identity?
if (exists($Sessions{$Coo}->{identity}) and $Sessions{$Coo}->{identity} ne 'ERROR'){
# most of the time, this is what we are expecting
goto HAVE_ID ; # unless $Sessions{$Coo}->{identity} eq 'ERROR';
}else{
# eval <<'NOIDENTITYEVAL';
# get an identity from the AIS server
# (process might be underway already)
if ($ENV{QUERY_STRING} =~ /^OTU_KEY=(\w+)/){
# eval <<'HAVEOTUKEYEVAL';
my $OTUkey = $1;
# carp "have aissri [$aissri]";
my ($method, $host, $port, $path) =
($aissri =~ m#^(\w+)://([^:/]+):?(\d*)(.+)$#)
or die "Could not get meth,hos,por,pat from aissri <$aissri>";
# carp "have \$method, \$host, \$port, \$path $method, $host, $port, $path";
unless ($method eq 'http'){
croak "aissri parameter must begin 'http://' at this time";
};
# issue the AIS QUERY request
# carp "doing miniget $host, $port,${aissri}query?$OTUkey, $agent";
my $Response = miniget $host, $port,
"${aissri}query?$OTUkey", $agent;
# carp "got $Response";
(my $AISXML) =
$Response =~ m#<aisresponse>(.+)</aisresponse>#si
or die "no <aisresponse> element from ${aissri}query?$OTUkey\n in BEGINRESPONSE\n$Response\nENDRESPONSE";
$Sessions{$Coo}->{AISXML} = $AISXML;
# parse AISXML...
my %aisvar;
foreach (qw{
identity
error
aissri
user_remote_addr
}
# ,@{$Param{XML}}
){
$AISXML =~ m#<$_>(.+)</$_>#si or next;
$aisvar{$_} = $1;
# print STDERR "ais var $_ is $1\n";
};
if ($aisvar{identity} eq 'NULL'){
redirect(
"$aisvar{aissri}add?RU=http$ssl_ext://$ENV{SERVER_NAME}$ENV{SCRIPT_NAME}$ENV{PATH_INFO}");
exit;
};
# hooray! we have an identity.
foreach (keys %aisvar){
$Sessions{$Coo}->{$_} = $aisvar{$_};
};
#reconstruct initial form data if any
$ENV{QUERY_STRING} = delete $Sessions{$Coo}->{QueryString};
if(exists $Sessions{$Coo}->{PostData}){
pipe(POSTREAD,POSTWRITE) or die "Cannot create pipe: $!";
if (fork){
# we are in parent
close POSTWRITE;
open STDIN, "<&POSTREAD";
$ENV{REQUEST_METHOD} = 'POST';
}else{
# in child -- write POSTdata to pipe and exit
close STDOUT;
( run in 1.342 second using v1.01-cache-2.11-cpan-ceb78f64989 )