use constant REQUEST_HEADER_BLOCK => qr/^(accept-encoding|connection|te|transfer-encoding|via)$/;
use constant RESPONSE_HEADER_BLOCK => qr/^(connection|content-encoding|content-length|trailer|transfer-encoding)$/;
-
$accesstime = time();
$timeout_unlock = TIMEOUT_UNLOCK*60;
$timeout_inact = TIMEOUT_INACT*60;
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
###PATH;
-if (($ENV{'HTTP_HOST'} =~ UNLOCK_PROXY_HOST) and ($ENV{'PATH_INFO'} =~ UNLOCK_PROXY_PATH)){
+if (($ENV{'HTTP_HOST'} =~ UNLOCK_PROXY_HOST) and (urldecode($ENV{'PATH_INFO'}) =~ UNLOCK_PROXY_PATH)){
unlock();
}
else {
-# if(access()) {
+ if(access()) {
proxy();
-# }
-# else {
-# noaccess();
-# }
+ }
+ else {
+ noaccess();
+ }
}
sub proxy {
return fail("Status: 405 Method Not Allowed\nAllow: GET, POST, HEAD\n","405 Method Not Allowed","The proxy does not support the $ENV{'REQUEST_METHOD'} method.");
}
- if ($ENV{'REQUEST_URI'} =~ /^([a-z]*(:[0-9]*)?:\/\/.*)$/){
- $URL=$1;
+ if ($ENV{'REQUEST_URI'} =~ /^[a-z]*(:[0-9]*)?:\/\/.*$/){
+ $URL=$ENV{'REQUEST_URI'};
}
else{
- $URL=($ENV{'HTTPS'} eq 'on' ? 'https://' : 'http://');.$ENV{'HTTP_HOST'}.$ENV{'REQUEST_URI'};
+ $URL=($ENV{'HTTPS'} eq 'on' ? 'https://' : 'http://').$ENV{'HTTP_HOST'}.$ENV{'REQUEST_URI'};
}
- #HTTP_HOST might theoretically not agree with REQUESR_URI.
- if ($URL =~ /^https*:\/\/(.*)$/) {
- $host= $1;
- $host =~ s/\/.*$//;
- if($host =~ /^(.*):([0-9]+)$/) {
- $host=$1;
- $port=$2;
- }
- else {
- $port=($ENV{'HTTPS'} eq 'on' ? '443' : '80');
- }
+ if (validateurl($URL)) { #validate URL against illegal characters
+ $URL =~ /^(.*)$/;
+ $URL = $1;
}
else {
- return fail("Status: 400 Bad Request\n","400 Bad Request","The proxy couldn't understand this URL: $URL.");
+ return fail("Status: 400 Bad Request\n","400 Bad Request","Invalid URL: $URL.");
}
+ if ($port eq ''){
+ $port=($ENV{'HTTPS'} eq 'on' ? '443' : '80');
+ }
+
if ($host =~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) {#IP instead of hostname
if ($host =~ /^((0*10\..*)|(0*127\..*)|(0*172\.0*((1[6-9])|(2[0-9])|(3[0-1]))\..*)|(0*192\.0*168\..*))$/) {
return fail("Status: 403 Forbidden\n","403 Forbidden","The proxy does not accept a private IP address $host as hostname.");
$uppath=$temppath.'u';
} while (( -e $headpath) or ( -e $downpath) or ( -e $uppath));
- @curl_arg=(CURL_PATH,'-s','-o',$downpath,'-D',$headpath); #-s
+ # @curl_arg=(CURL_PATH,'-o',$downpath,'-D',$headpath); #-s
+ @curl_arg=(CURL_PATH,'-i','-#'); #-s
+
if ($ENV{'REQUEST_METHOD'} eq 'HEAD'){
push @curl_arg, '-I';
}
push @curl_arg, '--data-binary';
push @curl_arg, '@'.$uppath;
}
- # foreach $envk (keys %ENV) {
- # if ($envk =~ /^HTTP_/) {
- # $headname=formatheader($envk);
- # $headval=$ENV{$envk};
- # if ($headname !~ /^[A-Za-z\-]+$/) {
- # next;
- # }
- # if(lc($headname) =~ REQUEST_HEADER_BLOCK) {
- # next;
- # }
- # unless (exists $ENV{'HTTP_USER_AGENT'}) {
- # push @curl_arg, '-H';
- # push @curl_arg, 'User-Agent:';
- # }
- # unless (exists $ENV{'HTTP_ACCEPT'}) {
- # push @curl_arg, '-H';
- # push @curl_arg, 'ACCEPT:';
- # }
- # $headval=~ s/[\r\n]//g;
- # $headarg=$headname.(($headval eq '')?';':': '.$headval);
- # push @curl_arg, '-H';
- # push @curl_arg, $headarg;
- # }
- # }
+ foreach $envk (keys %ENV) {
+ if ($envk =~ /^(HTTP_[A-Z_]+)$/) {
+ $headname=formatheader($1);
+ if ($ENV{$envk} =~ /^([\x20-\x7e]*)$/) {
+ $headval=$1;
+ }
+ if(lc($headname) =~ REQUEST_HEADER_BLOCK) {
+ next;
+ }
+ unless (exists $ENV{'HTTP_USER_AGENT'}) {
+ push @curl_arg, '-H';
+ push @curl_arg, 'User-Agent:';
+ }
+ unless (exists $ENV{'HTTP_ACCEPT'}) {
+ push @curl_arg, '-H';
+ push @curl_arg, 'ACCEPT:';
+ }
+ $headval=~ s/[\r\n]//g;
+ $headarg=$headname.(($headval eq '')?';':': '.$headval);
+ push @curl_arg, '-H';
+ push @curl_arg, $headarg;
+ }
+ }
push @curl_arg, $URL;
+ pipe ($STDREAD, $STDWRITE) or return fail("Status: 500 Internal Server Error\n","500 Internal Server Error","Failed to create stdout pipe.");
+ pipe ($ERRREAD, $ERRWRITE) or return fail("Status: 500 Internal Server Error\n","500 Internal Server Error","Failed to create stderr pipe.");
+
+ $curlpid = fork();
+ unless (defined $curlpid) {
+ return fail("Status: 500 Internal Server Error\n","500 Internal Server Error","fork() failed.");
+ }
+ unless ($curlpid) {
+ close ($STDREAD);
+ close ($ERRREAD);
+
+ open(STDERR, ">&=" . fileno($ERRWRITE)) or die "Failed to open stderr pipe.\n";
+ open(STDOUT, ">&=" . fileno($STDWRITE)) or die "Failed to open stdout pipe.\n";
+
+ exec @curl_arg;
+ exit 1;
+ }
+
+ close ($STDWRITE);
+ close ($ERRWRITE);
- ##DO REAL WORK HERE!
+ $safelength=1;
+ $definedlength=0;
+ $safeerror=1;
+ $lastskipped=1;
+ $forceexit=0;
- print "Content-type: text/plain\n\n";
- print "host: $host\nport: $port\n\n";
- foreach $yyyb (@curl_arg) {
- print "$yyyb\n";
+ if ($line = <$STDREAD>) {
+ $line =~ s/\r?\n$//;
+ if ($line =~ /^HTTP\/[0-9]+\.[0-9]+ ([0-9]+ .*)$/) {
+ @resphead=('Status: '.$1);
+ while ($line = <$STDREAD>) {
+ $line =~ s/[\r\n]$//g;
+
+ if($line eq ''){
+ last;
+ }
+
+ if($line =~ /^[ \t](.*)$/){
+ if ($lastskipped) {
+ next;
+ }
+ else {
+ #$lastline = pop @resphead;
+ #push @resphead, $lastline.$1;
+ push @resphead, $line;
+ }
+ }
+
+ if ($line =~ /^([^:]*):(.*)$/) {
+ $headname=lc($1);
+ $headvalue=$2;
+ }
+ else {
+ $lastskipped=1;
+ next;
+ }
+
+ if($headname eq 'transfer-encoding') {
+ $safelength = 0;
+ }
+ if($headname eq 'content-encoding') {
+ if($headvalue !~ /^[\r\n \t]*identity[\r\n \t]*$/) {
+ $safelength = 0;
+ }
+ }
+ if($headname eq 'content-length') {
+ $definedlength=1;
+ $headvalue =~ s/^[\r\n \t]*//;
+ $headvalue =~ s/[\r\n \t]*$//;
+ $contentlength = int($headvalue);
+ }
+ if($headname =~ RESPONSE_HEADER_BLOCK) {
+ $lastskipped =1;
+ next;
+ }
+ $line;
+ $lastskipped=0;
+ push @resphead, $line;
+ }
+
+ if ($lengthdefined and ($lengthsafe or ($contentlength==0))) {
+ push @resphead, 'Content-length: '.$contentlength;
+ }
+
+ #! write this to file (h) too ! {
+ $safeerror=0;
+ foreach $line (@resphead) {
+ print $line."\n";
+ }
+ print "\n";
+ #! }
+
+ if ( ! binmode ($STDREAD)) {
+ print "FAIL 1\n";
+ $forceexit=1;
+ }
+ elsif ( ! binmode (STDOUT) ) {
+ print "FAIL 2\n";
+ $forceexit=1;
+ }
+ else {
+
+ #! write this to file (c) too ! {
+ while (read ($STDREAD,$buffer,65536)) {
+ unless (print (STDOUT $buffer)) {
+ $forceexit=1;
+ next;
+ }
+ }
+ #! }
+ }
+ }
+ else {
+ $errormsg="Server respose is not HTTP: $line";
+ }
}
- #print "\n".(system @curl_arg)."\n";
- unlink $headpath;
- unlink $downpath;
- unlink $uppath;
+ # print "Content-type: text/plain\n\n";
- print "\nDEBUGINFO:\n";
+ # print"\n";
- return debag();
+ waitpid($curlpid,0);
+ if ($? != 0) {
+ if ($safeerror) {
+ $errormsg='';
+ while ($line = <$ERRREAD>) {
+ $line =~ s/\r?\n/<br>/g;
+ $errormsg=$errormsg.$line;
+ }
+ }
+ else {
+ $forceexit=1;
+ }
+ }
+ close(STDREAD);
+ close(ERRREAD);
+
+ if($safeerror){
+ return fail("Status: 500 Internal Server Error\n","500 Internal Server Error",$errormsg);
+ }
+ elsif ($forceexit) {
+ exit 1;
+ }
+
+ # print "host: $host\nport: $port\n\n";
+ # foreach $yyyb (@curl_arg) {
+ # print "$yyyb\n";
+ # }
+ # #print "\n".(system @curl_arg)."\n";
+
+ # unlink $headpath;
+ # unlink $downpath;
+ # unlink $uppath;
+
+
+ # print "\nDEBUGINFO:\n";
+
+ # return debag();
}
}
print 'URL: ',$URL,"\n";
}
+
+sub validateurl {
+ my $url = $_[0];
+ my $prot;
+ my $hostportpathquery;
+ my $hostportpath;
+ $query;
+ my $hostport;
+ $path;
+ my $part;
+ $host;
+ $port;
+
+ if ($url =~ /^([A-Za-z]+):\/\/(.*)/) {
+ $prot = $1;
+ $hostportpathquery = $2;
+ }
+ else {
+ return 0;
+ }
+
+ if ($prot !~ /^https?$/) {
+ return 0;
+ }
+
+ if ($hostportpathquery eq ''){
+ return 0;
+ }
+
+ if ($hostportpathquery =~ /^([^?]+)\?(.*)$/) {
+ $hostportpath = $1;
+ $query = $2;
+
+ if ($query !~ /^((%[0-9A-Fa-f][0-9A-Fa-f])|([A-Za-z0-9;\/\?:@&=\+\$\,\-_\.~\*'\(\)]))*$/) {
+ return 0;
+ }
+ }
+ else {
+ $hostportpath = $hostportpathquery;
+ $query = '';
+ }
+
+ if($hostportpath =~ /^([^\/]+)(\/.*)$/){
+ $hostport = $1;
+ $path = $2;
+
+ if ($path !~ /^((%[0-9A-Fa-f][0-9A-Fa-f])|([A-Za-z0-9:;@&=\+\$\,-_\.~\*'\(\)]))*$/) {
+ return 0;
+ }
+
+ }
+ else {
+ $hostport = $hostportpath;
+ $path = '';
+ }
+
+ if ($hostport =~ /^(.*):([0-9]+)$/) {
+ $host = $1;
+ $port = $2;
+ }
+ else {
+ $host=$hostport;
+ $port='';
+ }
+
+ if ($host !~ /^[A-Za-z0-9\-\.]+$/) {
+ return 0;
+ }
+
+ return 1;
+}