ljr/wcmtools/perlbal/lib/Perlbal/Test/WebClient.pm

128 lines
2.8 KiB
Perl
Executable File

#!/usr/bin/perl
package Perlbal::Test::WebClient;
use strict;
use IO::Socket::INET;
use HTTP::Response;
use Socket qw(MSG_NOSIGNAL);
require Exporter;
use vars qw(@ISA @EXPORT $FLAG_NOSIGNAL);
@ISA = qw(Exporter);
@EXPORT = qw(new);
eval { $FLAG_NOSIGNAL = MSG_NOSIGNAL; };
# create a blank object
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
return $self;
}
# get/set what server we should be testing; "ip:port" generally
sub server {
my $self = shift;
if (@_) {
return $self->{server} = shift;
} else {
return $self->{server};
}
}
# set which HTTP version to emulate; specify '1.0' or '1.1'
sub http_version {
my $self = shift;
if (@_) {
return $self->{http_version} = shift;
} else {
return $self->{http_version};
}
}
# set on or off to enable or disable persistent connection
sub keepalive {
my $self = shift;
if (@_) {
$self->{keepalive} = shift() ? 1 : 0;
}
return $self->{keepalive};
}
# construct and send a request
sub request {
my $self = shift;
return undef unless $self->{server};
my $cmds = join(',', map { eurl($_) } @_);
return undef unless $cmds;
# keep-alive header if 1.0, also means add content-length header
my $headers = '';
$headers .= "Connection: keep-alive\r\n"
if $self->{keepalive};
my $send = "GET /$cmds HTTP/$self->{http_version}\r\n$headers\r\n";
my $len = length $send;
# send setup
my $rv;
my $sock = $self->{_sock};
local $SIG{'PIPE'} = "IGNORE" unless $FLAG_NOSIGNAL;
### send it cached
if ($sock) {
$rv = send($sock, $send, $FLAG_NOSIGNAL);
if ($! || ! defined $rv) {
undef $self->{_sock};
} elsif ($rv != $len) {
return undef;
}
}
# failing that, send it through a new socket
unless ($rv) {
$sock = IO::Socket::INET->new(
PeerAddr => $self->{server},
Timeout => 3,
) or return undef;
$rv = send($sock, $send, $FLAG_NOSIGNAL);
if ($! || $rv != $len) {
return undef;
}
$self->{_sock} = $sock
if $self->{keepalive};
}
my $res = '';
while (<$sock>) {
$res .= $_;
last if ! $_ || /^\r?\n/;
}
my $resp = HTTP::Response->parse($res);
return undef unless $resp;
my $cl = $resp->header('Content-Length');
if ($cl > 0) {
my $content = '';
while (($cl -= read($sock, $content, $cl)) > 0) {
# don't do anything, the loop is it
}
$resp->content($content);
}
return $resp;
}
# general purpose URL escaping function
sub eurl {
my $a = $_[0];
$a =~ s/([^a-zA-Z0-9_\,\-.\/\\\: ])/uc sprintf("%%%02x",ord($1))/eg;
$a =~ tr/ /+/;
return $a;
}
1;