Apache-ProxyScan
view release on metacpan or search on metacpan
ProxyScan.pm view on Meta::CPAN
use vars qw($VERSION);
use LWP::UserAgent ();
use URI::URL;
use File::MMagic;
use Apache::Const qw(OK DECLINED :log);
use APR::Const qw(:error SUCCESS);
use APR::Table;
use Apache::RequestRec;
use Apache::RequestUtil;
use Apache::RequestIO;
use Apache::Log;
use Apache::Response ();
$VERSION = "0.92";
# create a mime type detector once.
# You need File::Magic even if you don't use it
my $MIME = File::MMagic::new('/etc/httpd/conf/magic');
sub handler {
my($r) = @_;
return DECLINED unless $r->proxyreq;
return DECLINED if ($r->method eq "CONNECT");
# If there are Trusted Extensions DECLINE the requests here
my $filetype = $r->dir_config("ProxyScanTrustedExtension");
if (defined $filetype) {
my %extension;
foreach (split(/\s+/, $filetype)) {
s/^\.//igs;
$extension{lc("$_")} = 1;
}
my @pc = (URI::URL->new($r->uri))->path_components;
my $ext = pop @pc;
if ($ext =~ s/^.*\.([^.]+)/$1/igs) {
if (defined $extension{lc("$ext")}) {
$r->log->warn($r, "Trusted File Extension: ".$r->uri);
return DECLINED;
}
}
}
$r->handler("perl-script"); #ok, let's do it
$r->push_handlers(PerlHandler => \&proxy_handler);
return OK;
}
sub proxy_handler {
my($r) = @_;
# get the configuration variables
my $scanner = $r->dir_config("ProxyScanScanner");
my $tmpdir = $r->dir_config("ProxyScanTempDir") || '/tmp/';
my $presendsize = $r->dir_config("ProxyScanPredeliverSize") || 102400;
my $trustmime = $r->dir_config("ProxyScanTrustedMIME");
if (defined $trustmime) {
$trustmime =~ s/\*/.*/igs;
$trustmime = join('|', split(/\s+/, $trustmime));
}
# create the request
my $request = new HTTP::Request $r->method, $r->uri;
# copy request headers
my $table = $r->headers_in;
foreach my $key (keys %{$table}) {
$request->header($key,$table->{$key});
}
# transfer request if it's POST
# try to handle without content length
if ($r->method eq 'POST') {
my $len = $r->headers_in->{'Content-length'};
if (defined $len) {
my $buf;
$r->read($buf, $len);
$request->content($buf);
} else {
$request->content(scalar $r->content);
}
}
# do a predeliver
# if you do predelivering there are several problems with the
# http protocol. For this reason we do it only for large files.
# This makes downloading easier, because the save-as window still
# appears.
my $callcount = 0;
my $delivered = 0;
my $headersent = 0;
my $trustworthy = 0;
my $file;
my $outfile = undef;
my $fetchref = sub {
my($data, $res, $protocol) = @_;
if ($callcount == 0) {
my $mime = $MIME->checktype_contents($data);
if ((defined $trustmime ) && ($mime =~ m§^($trustmime)$§i)) {
$trustworthy = 1;
$r->log->warn($r, "Trusted MIME Type: ".$r->uri);
prepareheaders(\$r,\$res);
$r->rflush();
} else {
# make a nice filename
my @chars = ( "A" .. "Z", "a" .. "z", 0 .. 9 );
$file = substr($r->uri , 0, 200);
$file =~ s/[^A-Z0-9]+/_/igs;
$file .= join("", @chars[ map { rand @chars } ( 1 .. 16 ) ] );
open($outfile, ">$tmpdir/$file");
my $len = $res->header('Content-Length');
if ($len > $presendsize) {
$r->log->warn($r,"started predelivery on: ".$r->uri);
$res->remove_header('Content-Length');
prepareheaders(\$r,\$res);
$r->rflush();
$headersent=1;
print substr $data,0,5;
$delivered += 5;
$r->rflush;
}
}
( run in 0.740 second using v1.01-cache-2.11-cpan-39bf76dae61 )