#! /usr/local/bin/perl -w
# proxy.pl Version 1.2
# Release Date 3/16/2001
# By Marc Waldman (waldman@cs.nyu.edu)
# Publius Project WWW page - cs.nyu.edu/waldman/publius
# Publius Project E-mail address - publius@cs.nyu.edu
# Copyright 2000 - New York University
#
#PUBLIUS TERMS AND CONDITIONS
#THIS SOFTWARE IS EXPERIMENTAL AND IS PROVIDED "AS IS."
#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
#LIMITED TO, THE IMPLIED WARRANTIES OF
#MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
#
#IN NO EVENT SHALL AT&T OR THE AUTHORS BE LIABLE FOR ANY DIRECT,
#INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
#OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#OR BUSINESS INTERRUPTION) HOWEVER
#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
#STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#ARISING IN ANY WAY OUT OF THE USE OF THIS
#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#You are granted a royalty-free, non-exclusive, non-transferable right to
#install and use the Publius software for non-commercial purposes during
#the Publius trial. You
#may not redistribute the code, with or without alterations,
#or use the code for
#commercial purposes without the permission of AT&T and the authors.
BEGIN { push @INC, "./Lib" }
use strict;
use Common;
use Publish;
use HostTable;
use URI;
use Update;
use Delete;
use HTTP::Daemon;
use HTTP::Status;
use HTTP::Date;
use LWP::UserAgent;
use MIME::Base64;
use HTTP::Request::Common;
use HTTP::Response;
use Digest::MD5;
use Cwd;
use POSIX qw(:sys_wait_h);
sub debug{
print @_,"\n";
}
my $proxyNonPubliusUrls="YES"; # Set to "NO" if you don't want to proxy non Publius
# URLs. Any value other than "YES" (in uppercase) will indicate that
#non Publius URLs will not be proxied.
sub removeUrlWhitespace{
# Used only for forms that are URLencoded (Delete and Retreive).
# Don't use in mime encoded forms that have attachments (Publish and Update)
my $fullPath=shift @_;
# strip out the + signs embedded in form that represent white space
# all "user-entered" + signs are already URI escaped by the browser
$fullPath=~ s/[+]//g;
$fullPath=URI::Escape::uri_unescape($fullPath);
$fullPath =~ s/\s//g; #remove all unescaped whitespace
return $fullPath;
}
sub removeWhitespace{
my $str=shift @_;
$str =~ s/\s//g;
return $str;
}
sub makeRequest{
my ($command,$hostTableIndex,$directory)=@_;
my ($serverIp,$serverName,$cgiLocation)=HostTable::getAllHostInfo($hostTableIndex);
my $publishURL="http://".$serverName . $cgiLocation;
#debug ($publishURL,"\n");
#debug ("directory=$directory\n");
my $request=HTTP::Request::Common::POST($publishURL,
Content_Type => 'form-data',
Content => [command => $command,
directory=> $directory,
]
);
my $ua=LWP::UserAgent->new();
$ua->timeout($Common::httpTimeOutValue);
my $response=$ua->request($request);
return $response;
}
sub sendDocToBrowser{
my ($connection,$plainTextRef)=@_;
#add all headers except content-type.
my $header=HTTP::Headers->new("expires"=>HTTP::Date::time2str(),"date"=>HTTP::Date::time2str(),"last_modified"=>HTTP::Date::time2str(),"pragma"=>"no-cache");
# determine correct Mime-type
my $defaultMimeType;
if (-T "$Common::workDir/dec"){ # text file
$defaultMimeType="text/plain";
}
else{
$defaultMimeType="octet/stream";
}
my $fileExtensionLength=length($Common::emptyFileExtension);
my $fileExtension=substr($$plainTextRef,0,$fileExtensionLength);
# remove white space at end of extension and convert to lower case
$fileExtension =~ s/^[\s]+//;
$fileExtension =~ tr/A-Z/a-z/;
if ($Common::MimeTypes{$fileExtension}){
$defaultMimeType=$Common::MimeTypes{$fileExtension};
}
#debug("Mime-type:",$defaultMimeType);
$header->push_header("content-type"=>$defaultMimeType);
# when return document to browser remove file extension
my $response=HTTP::Response->new(200,"OK",$header,substr($$plainTextRef,$fileExtensionLength));
# debug($response->as_string());
$response->protocol("HTTP/1.0");
$connection->send_response($response);
push (@Common::filesToDelete,"$Common::workDir/dec");
push (@Common::filesToDelete,"$Common::workDir/key");
}
sub trySharesOnEncryptedFile{
my ($connection,$usedIndexValuesRef,$filesRetrievedRef,$reorderedHashesRef,$hostTableIndicesRef,$elementsRef)=@_;
my $testIndex=$$usedIndexValuesRef[$#$usedIndexValuesRef];
if (!($$filesRetrievedRef[$testIndex])){
my $response=makeRequest("RETRIEVE_F",$$hostTableIndicesRef[$testIndex],Common::hexStringFromHash(Common::base64DecodeHash($$reorderedHashesRef[$testIndex])));
if (($response->is_success()) && (defined($response->header("update")))){
if ($response->header("update")=="0"){
$$filesRetrievedRef[$testIndex]="F";
open(FH,">$Common::workDir/" . "F$testIndex");
print FH $response->content();
close(FH);
push (@Common::filesToDelete,"$Common::workDir/F$testIndex");
}
else{ #returned an update, consider an error
$$filesRetrievedRef[$testIndex]="E";
return 0;
}
}
else{ #error occured - could be a time out
$$filesRetrievedRef[$testIndex]="E";
return 0;
}
}
if ($$filesRetrievedRef[$testIndex] eq "F"){
Common::assembleShares("key", @$usedIndexValuesRef);
my ($errorCode,$keyRef)=Common::readFileIntoString("$Common::workDir/key");
if ($errorCode<0){
return 0; # can't read the key - don't use this combination
}
Common::decryptFile("F$testIndex","dec",$$keyRef);
($errorCode, my $plainTextRef)=Common::readFileIntoString("$Common::workDir/dec");
if ($errorCode<0){
return 0; # can't read the document - don't use this combination
}
for (my $i=0; $i<=$#$usedIndexValuesRef; $i++){
my $digest=Digest::MD5->new();
$digest->add($$plainTextRef);
$digest->add($$elementsRef[$$usedIndexValuesRef[$i]]);
my $d=MIME::Base64::encode_base64(Common::xorHash($digest->digest()),"");
# debug ("d=$d r=$$reorderedHashesRef[$$usedIndexValuesRef[$i]]\n");
# append "=" onto reorderedHashesRef since removed during url split
if ($d ne ($$reorderedHashesRef[$$usedIndexValuesRef[$i]]."=")){
return 0;
}
}
# if made it here then document must have verified
sendDocToBrowser($connection,$plainTextRef);
return 1;
}
else{
return 0; # requested file was not available
}
}
sub retrieveAnonDocument{
my ($connection,$request,$fullPathRef)=@_;
#debug($$fullPathRef);
if (substr($$fullPathRef,0,1) eq "/"){
$$fullPathRef=substr($$fullPathRef,1); #move past initial slash
}
if ($$fullPathRef eq ""){
# http://!publius!/ empty file path so just display User Interface
my $header=HTTP::Headers->new(-type=>"text/html");
my ($errorCode,$fileContentRef)=Common::readFileIntoString("$Common::guiDir/menu.html");
$connection->send_response(200,"OK",$header,$$fileContentRef);
return;
}
my @hashes=Common::splitUrlIntoHashes($$fullPathRef);
my @hostTableIndices;
my @reorderedHashes;
$#reorderedHashes=$#hashes; #set array to same size as hashes
$#hostTableIndices=$#hashes;
my $randomIndex;
my $numOfHashes=$#hashes+1;
# mix up hash ordering so retrieval order not predictable
for (my $i=0; $i<$numOfHashes; $i++){
$randomIndex=rand(100) % $numOfHashes;
if (!($reorderedHashes[$randomIndex])){
$reorderedHashes[$randomIndex]=$hashes[$i];
$hostTableIndices[$randomIndex]=Common::getIndexFromBase64Hash($hashes[$i]);
}
else{ #already something at $randomIndex location, search for free loc.
for (my $j=1; $j<$numOfHashes; $j++){
if (!($reorderedHashes[($randomIndex+$j)%$numOfHashes])){
$reorderedHashes[($randomIndex+$j)%$numOfHashes]=$hashes[$i];
$hostTableIndices[($randomIndex+$j)%$numOfHashes]=Common::getIndexFromBase64Hash($hashes[$i]);
last;
}
}
}
}
# start to retrieve shares
my @maxIndexValue;
my @currentIndexValue;
# setup for generating all combinations of shares
for (my $i=1; $i<=$Common::numSharesToReconstruct; $i++){
$maxIndexValue[$i-1]=$numOfHashes-$Common::numSharesToReconstruct+$i;
$currentIndexValue[$i-1]=$i-1;
}
my $moreCombinations=0;
my @elementRetrieved; # "S"=Share, "U"=Update
my @elements; # actual share or update
my @filesRetrieved;
while (1){
# test each combination
my $shareCount=0;
my $updateCount=0;
my @usedIndexValues;
# may need to undef @usedIndexValues
# retrieve information corresponding to current combination
for (my $i=0; $i<$Common::numSharesToReconstruct; $i++){
my $testIndex=$currentIndexValue[$i];
push(@usedIndexValues, $testIndex);
if (!($elementRetrieved[$testIndex])){
my $response=makeRequest("RETRIEVE_S",$hostTableIndices[$testIndex],Common::hexStringFromHash(Common::base64DecodeHash($reorderedHashes[$testIndex])));
if (($response->is_success()) && (defined($response->header("update")))){
if ($response->header("update")=="1"){
$updateCount++;
$elementRetrieved[$testIndex]="U"; #update
$elements[$testIndex]=$response->content();
# check size of Url retured
if (length($elements[$testIndex])>$Common::maxUpdateUrlSize){
# consider too long URL as error
$elementRetrieved[$testIndex]="E";
$elements[$testIndex]="Too Large";
}
}
else{ #must be a share
$shareCount++;
$elementRetrieved[$testIndex]="S"; #share
$elements[$testIndex]=$response->content();
# check size of share returned
if (length($elements[$testIndex])>$Common::maxShareSize){
# consider large share as an error
$elementRetrieved[$testIndex]="E";
$elements[$testIndex]="Too Large";
}
else{
open(FH,">$Common::workDir/" . $testIndex);
print FH $response->content();
close(FH);
push (@Common::filesToDelete,"$Common::workDir/$testIndex");
}
}
}
else{ #error - could be a time out
$elementRetrieved[$testIndex]="E"; #error
$elements[$testIndex]=$response->message();
}
}
elsif ($elementRetrieved[$testIndex] eq "U"){
$updateCount++;
}
elsif ($elementRetrieved[$testIndex] eq "S"){
$shareCount++;
}
}
# check if all updates and if willing to accept updates
if (($updateCount==$Common::numSharesToReconstruct) &&
($Common::updateBit eq "1")){
# check if all updates are the same
my $allEqual=1;
for (my $j=1; $j<=$#usedIndexValues; $j++){
if ($elements[$usedIndexValues[$j]] ne $elements[$usedIndexValues[0]]){
$allEqual=0;
last;
}
}
if ($allEqual==1){
$connection->send_redirect($elements[$usedIndexValues[0]],301,"Redirecting");
return;
}
}
elsif ($shareCount==$Common::numSharesToReconstruct){
my $result=trySharesOnEncryptedFile($connection,\@usedIndexValues,\@filesRetrieved,\@reorderedHashes,\@hostTableIndices,\@elements);
if ($result==1){
return; #all done - process next request
}
}
$moreCombinations=0;
# generate next combination
for (my $i=$Common::numSharesToReconstruct-1; $i>=0; $i--){
if ($currentIndexValue[$i]+1<$maxIndexValue[$i]){
$currentIndexValue[$i]++;
$moreCombinations=1;
for (my $j=$i+1; $j<$Common::numSharesToReconstruct; $j++){
$currentIndexValue[$j]=$currentIndexValue[$i]+($j-$i);
}
last;
}
}
if ($moreCombinations==0){
$connection->send_response(200,"OK",undef,"
Unable To Reconstruct Document
");
last;
}
}
}
sub processMimeForm{
my ($request)=@_;
my $boundary;
my $requestString=$request->as_string;
my %fieldsFound;
my $prependString=""; #Used to prepend file extension to file contents
#Find the boundary string that separates the fields
if ($requestString=~ /Content-Type.*boundary=(.*)/i){
$boundary="--".$1 #field boundaries will start with two "-" characters
#and end line with "\r\n" (RFC 2046)
#last boundary ends with "--\r\n"
}
# find boundary for first field
my $fieldStartLocation=index($requestString,$boundary);
while ($fieldStartLocation>0){
#move past initial boundary
$fieldStartLocation+=length($boundary)+2; #move past "\r\n"
#find the field name associated with this entry
my $nameIndex=index($requestString,"name=",$fieldStartLocation);
$nameIndex+=6; # move onto field name
my $nameEndIndex=index($requestString,'"',$nameIndex);
my $fieldname=substr($requestString,$nameIndex,$nameEndIndex-$nameIndex);
#save program name - located in field "filename"
if ($fieldname eq "DOCUMENT"){
my $endOfLine=index($requestString,"\r\n",$nameEndIndex);
# Store filename if available - Used to display fn in publish window
if (substr($requestString,$nameEndIndex,$endOfLine-$nameEndIndex)=~/filename=\"([^\"]*)\"/){
$fieldsFound{$fieldname}=$1;
my $periodIndex=rindex($1,"."); #find last period in file
if ($periodIndex>-1){
$prependString=substr($1,$periodIndex+1,length($Common::emptyFileExtension));
# The file extension could be less than # of chars set aside for ext.
if (length($prependString)$Common::maxFileSize){
$fieldsFound{$fieldname}="";
#don't save field contents to disk
}
else{
open (FLD,">$Common::workDir/$fieldname");
print FLD $prependString.substr($requestString,$doubleCrlfIndex,$fieldEndLocation-$doubleCrlfIndex-2); #subtract two to remove the CRLF characters preceding end boundary tag
close(FLD);
push (@Common::filesToDelete,"$Common::workDir/$fieldname");
}
$prependString="";
$fieldStartLocation=index($requestString,$boundary."\r\n",$fieldEndLocation);
#debug($fieldStartLocation,"\n");
# fieldStartLocation should be less than zero when we hit the final boundary
# of the document since the boundary will have a "--\r\n" suffix,
# we just check for "\r\n" suffix;
}
return \%fieldsFound;
}
sub processPubFile{
my ($connection,$request)=@_;
#debug($request->as_string);
my $fieldsFoundRef=processMimeForm($request);
if (!($$fieldsFoundRef{"DOCUMENT"})){
$connection->send_response(200,"OK",undef,"Unable To Locate Document - May Have Exceeded Allowable Size");
return;
}
if (!($$fieldsFoundRef{"PASSWORD"})){
$connection->send_response(200,"OK",undef,"Unable To Locate Password - May Have Exceeded Allowable Size");
return;
}
if (!($$fieldsFoundRef{"PUBLISH_OPTIONS"})){
$connection->send_response(200,"OK",undef,"Unable To Locate Publish Options - May Have Exceeded Allowable Size");
return;
}
else{
# read PUBLISH_OPTIONS and NUM_SHARES
my ($errorCode,$optionsRef)=Common::readFileIntoString($Common::workDir."/PUBLISH_OPTIONS");
if ($$optionsRef eq "NORM"){
# allow both update and delete
$Common::updateBit="1";
$Common::deleteBit="1";
}
elsif ($$optionsRef eq "NOUP"){
#debug("No Update Specified");
$Common::updateBit="0";
$Common::deleteBit=$Common::defaultDeleteBit;
}
elsif ($$optionsRef eq "NODL"){
#debug("No Delete Specified");
$Common::updateBit="0";
$Common::deleteBit="0"
}
else{
$connection->send_response(200,"OK",undef,"Unknown Publish Options");
return;
}
if (!($$fieldsFoundRef{"NUM_SHARES"})){
$Common::numSharesToReconstruct=$Common::defaultNumSharesToReconstruct;
}
else{
my ($errorCode,$sharesRef)=Common::readFileIntoString($Common::workDir."/NUM_SHARES");
if ((($$sharesRef+0)>0) && (($$sharesRef+0)<$Common::numSharesToSplit)){
$Common::numSharesToReconstruct=$$sharesRef+0;
}
else{
$connection->send_response(200,"OK",undef,"Incorrect Number of Shares Specified Options");
}
}
}
# found password and path so attempt to publish file
my $filePath=$Common::workDir."/DOCUMENT";
my ($errorCode,$passwordRef)=Common::readFileIntoString($Common::workDir."/PASSWORD");
if ($errorCode<0){
$$passwordRef="";
return;
}
Publish::publishFile($filePath,$$passwordRef,$$fieldsFoundRef{"DOCUMENT"});
$connection->send_response(200,"OK",undef,"".$Common::outputString."");
return;
}
sub processRetrieve{
my ($connection,$request)=@_;
if ($request->as_string =~ /URL=([^\s&]*)/){
my $fullPath=removeUrlWhitespace($1);
$fullPath=(new URI::URL($fullPath))->full_path();
retrieveAnonDocument($connection,$request,\$fullPath)
}
else{
$connection->send_response(200,"OK",undef," Cannot Find URL field
");
}
}
sub processUpdate{
my ($connection,$request)=@_;
my $fieldsFoundRef=processMimeForm($request);
if (!($$fieldsFoundRef{"DOCUMENT"})){
$connection->send_response(200,"OK",undef,"Unable To Locate Document");
return;
}
if (!($$fieldsFoundRef{"NEWPASSWORD"})){
$connection->send_response(200,"OK",undef,"Unable To Locate New Password -- Try publishing with command line publishing tools");
return;
}
if (!($$fieldsFoundRef{"OLDPASSWORD"})){
$connection->send_response(200,"OK",undef,"Unable To Locate Old Password -- Try publishing with command line publishing tools");
return;
}
if (!($$fieldsFoundRef{"OLDURL"})){
$connection->send_response(200,"OK",undef,"Unable To Locate Password -- Try publishing with command line publishing tools");
return;
}
# found all fields so read all data from files
my ($errorCode,$newPasswordRef)=Common::readFileIntoString($Common::workDir."/NEWPASSWORD");
if ($errorCode<0){
$connection->send_response(200,"OK",undef,"Unable To Read New Password -- Try publishing with command line publishing tools");
}
($errorCode, my $oldPasswordRef)=Common::readFileIntoString($Common::workDir."/OLDPASSWORD");
if ($errorCode<0){
$connection->send_response(200,"OK",undef,"Unable To Read Old Password -- Try publishing with command line publishing tools");
}
($errorCode, my $oldURLRef)=Common::readFileIntoString($Common::workDir."/OLDURL");
if ($errorCode<0){
$connection->send_response(200,"OK",undef,"Unable To Read Previous URL -- Try publishing with command line publishing tools");
return;
}
if (Common::isUrlUpdateable(removeWhitespace($$oldURLRef))<1){
$connection->send_response(200,"OK",undef,"This URL is not updateable");
return;
}
$Common::outputString="Update Operation
";
Common::addToOutput("The result of the Publish operation performed on the update document is shown first. The result of the Update operation follows.
");
Common::addToOutput("Output of Publish Operation
");
my $newURL=Publish::publishFile($Common::workDir."/DOCUMENT",$$newPasswordRef,$$fieldsFoundRef{"DOCUMENT"});
# found all fields so attempt update operation
$Common::outputString=$Common::outputString."
Output of Update Operation
\n";
Update::update(removeWhitespace($$oldURLRef),removeWhitespace($newURL),$$oldPasswordRef);
$connection->send_response(200,"OK",undef,"$Common::outputString");
return;
}
sub processDelete{
my ($connection,$request)=@_;
my $url;
my $password;
if ($request->as_string =~ /URL=([^\s&]*)/){
$url=removeUrlWhitespace($1);
}
else{
$connection->send_response(200,"OK",undef,"Cannot Find URL field
");
return;
}
if ($request->as_string =~ /PASSWORD=([^\s&]*)/){
#debug($request->as_string);
#debug($1);
# remove non-escaped "+" signs, they are white space
$password=$1;
$password=~ s/[+]/ /g;
$password=URI::Escape::uri_unescape($password);
}
else{
$connection->send_response(200,"OK",undef,"Cannot Find PASSWORD field
");
return;
}
# found all fields so attempt delete operation
Delete::deleteDoc(\$url,$password);
$connection->send_response(200,"OK",undef,"$Common::outputString");
}
sub processAnonCommand{
my ($connection,$request)=@_;
my $fullPath=$request->url->full_path;
my $anonCommand=substr($request->url->host,9);
if (length($anonCommand)>0){ #URL contains embedded command
if ($anonCommand eq "gui_ret"){
my $header=HTTP::Headers->new(-type=>"text/html");
my ($errorCode,$fileContentRef)=Common::readFileIntoString("$Common::guiDir/retrieve.html");
$connection->send_response(200,"OK",$header,$$fileContentRef);
return;
}
if ($anonCommand eq "gui_pub"){
my $header=HTTP::Headers->new(-type=>"text/html");
my ($errorCode,$fileContentRef)=Common::readFileIntoString("$Common::guiDir/publish.html");
$connection->send_response(200,"OK",$header,$$fileContentRef);
return;
}
if ($anonCommand eq "gui_del"){
my $header=HTTP::Headers->new(-type=>"text/html");
my ($errorCode,$fileContentRef)=Common::readFileIntoString("$Common::guiDir/delete.html");
$connection->send_response(200,"OK",$header,$$fileContentRef);
return;
}
if ($anonCommand eq "gui_upd"){
my $header=HTTP::Headers->new(-type=>"text/html");
my ($errorCode,$fileContentRef)=Common::readFileIntoString("$Common::guiDir/update.html");
$connection->send_response(200,"OK",$header,$$fileContentRef);
return;
}
if ($anonCommand eq "gui_adv"){
my $header=HTTP::Headers->new(-type=>"text/html");
my ($errorCode,$fileContentRef)=Common::readFileIntoString("$Common::guiDir/advpub.html");
$connection->send_response(200,"OK",$header,$$fileContentRef);
return;
}
# all other options require crypto
Common::connectToCrypto();
if ($anonCommand eq "retrieve"){
processRetrieve($connection,$request);
Common::quitCrypto();
return;
}
elsif ($anonCommand eq "update"){
processUpdate($connection,$request);
Common::quitCrypto();
return;
}
elsif ($anonCommand eq "delete"){
processDelete($connection,$request);
Common::quitCrypto();
return;
}
elsif ($anonCommand eq "pubfile"){
processPubFile($connection,$request);
Common::quitCrypto();
return;
}
else { #unknown command
$connection->send_response(200,"OK",undef,"Unknown Command - $anonCommand
");
Common::quitCrypto();
return;
}
}
else{ # regular publius URL
if (($fullPath eq "") || ($fullPath eq "/")){
# http://!publius!/ empty file path so just display User Interface
my $header=HTTP::Headers->new(-type=>"text/html");
my ($errorCode,$fileContentRef)=Common::readFileIntoString("$Common::guiDir/menu.html");
$connection->send_response(200,"OK",$header,$$fileContentRef);
return;
}
else{
Common::connectToCrypto();
retrieveAnonDocument($connection,$request,\$fullPath);
Common::quitCrypto();
}
}
}
sub acceptConnection{
my $connection=shift;
my $request;
my $pid=fork;
#debug("Child pid value = $pid\n");
if ($pid){
return;
}
$request = $connection->get_request;
if (!$request){ # $request was undefined
close($connection);
#debug("Undefined Request\n");
close($connection);
exit 0;
}
#debug($request->url->host."\n");
if (substr($request->url->host,0,9) eq "!publius!"){
# $found a "publius" URL
#debug("Publius URL found\n");
processAnonCommand($connection,$request);
Common::clearOutputString();
Common::cleanUpWorkDir();
}
else {
# found a regular URL
# debug("regular URL found\n");
my $response;
if ($proxyNonPubliusUrls eq "YES"){
my $ua=LWP::UserAgent->new();
$response=$ua->request($request);
#debug($response->message());
}
else{
my $header=HTTP::Headers->new(-type=>"text/html");
$response=HTTP::Response->new(200,"OK",$header,"This proxy will not process non-Publius URLs.
Make sure the requested host's domain name is listed in the proxy exception list -- See step 4 of the Netscape instructions, or step 6 of the Internet Explorer instructions.
");
}
$connection->send_response($response);
}
close($connection);
exit 0;
}
sub removeDirectory{
my $dirname=shift;
my $entry;
#directory should be empty if Publius
#operation completed, might be non-empty
#if operation canceled
opendir(DH,$dirname);
while ($entry=readdir(DH)){
if (substr($entry,0,1) ne "."){
unlink("$dirname/$entry");
}
}
closedir(DH);
rmdir($dirname);
}
sub main{
my $d = new HTTP::Daemon(Reuse => 1, LocalPort=> $Common::publiusLocalPort,Timeout=>5);
if (!$d){
die "Couldn't connect to port $Common::publiusLocalPort\n";
}
Common::initialize();
srand(); #for later use in retrieve function
$Common::useHTML=1; #assume sending output to the browser
print "Publius daemon installed at: URL:", $d->url, "\n";
my $pid;
my $s;
my $cd=Cwd::getcwd().$Common::workDir."/";
while (1){
$s=$d->accept();
if ($s){
acceptConnection($s);
}
while (1){
$pid=waitpid(-1,WNOHANG);
last if $pid <1;
removeDirectory($cd.$pid) if (-e $cd.$pid);
}
}
}
main();