[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r15574: adapt edgeproxy to rewrite HTML for reverse HTTP proxy into (blossom/trunk)



Author: goodell
Date: 2008-06-30 18:16:51 -0400 (Mon, 30 Jun 2008)
New Revision: 15574

Modified:
   blossom/trunk/edgeproxy
Log:
adapt edgeproxy to rewrite HTML for reverse HTTP proxy into Tor


Modified: blossom/trunk/edgeproxy
===================================================================
--- blossom/trunk/edgeproxy	2008-06-30 22:15:35 UTC (rev 15573)
+++ blossom/trunk/edgeproxy	2008-06-30 22:16:51 UTC (rev 15574)
@@ -23,6 +23,7 @@
 # fwdport -- act as proxy forwarder for dedicated services
 
 use strict;                 # require declarations
+use Fcntl;                  # polipo hack
 use Getopt::Long;           # for option processing
 use Net::hostent;           # by-name interface for host info
 use IO::Socket;             # for creating server and client sockets
@@ -40,6 +41,7 @@
 );
 
 my $DEBUG = 0;              # debug level
+my $PREFIX = undef;         # proxy server host[:port]
 
 ($ME = $0) =~ s,.*/,,;      # retain just basename of script name
 
@@ -56,8 +58,14 @@
         "local=s"     => \$LOCAL,
         "service=s"   => \$SERVICE,
         "debug=s"     => \$DEBUG,
+        "prefix=s"    => \$PREFIX,
     ) or die <<EOUSAGE;
-    usage: $0 [ --remote host ] [ --local interface ] [ --service service ] [ --debug level ]
+    usage: $0
+        [ --remote host ]
+        [ --local interface ]
+        [ --service service ]
+        [ --debug level ]
+        [ --prefix prefix ]
 EOUSAGE
     die "Need remote"                   unless $REMOTE;
     die "Need local or service"         unless $LOCAL || $SERVICE;
@@ -169,7 +177,9 @@
                 my $proxypath = "";
                 my $reverseproxy = undef;
 
+                my $serverhost = <READER>;
                 my $router = <READER>;
+                chomp $serverhost;
                 if($router) {
                     chomp $router;
                 } else {
@@ -192,6 +202,7 @@
                 my $length      = undef;
                 my $content     = "";
                 my $headers     = "";
+                my $data        = "";
                 my $type        = "";
 
                 while(<$remote_server>) {
@@ -211,20 +222,29 @@
                         my $before = "$pre$host$port$post";
 
                         $host = append_exit($host, $router) if $router;
-                        $pre = "$proxypath$pre" if $reverseproxy;
+                        if($PREFIX and $PREFIX ne "$host$port") {
+                            $proxypath = "http://$PREFIX/";;
+                            $pre = "$proxypath$pre";
+                        } elsif($reverseproxy) {
+                            $pre = "$proxypath$pre";
+                        }
 
                         my $after = "$pre$host$port$post";
 
                         log_info(2, "converting: Location: $before --> Location: $after");
 
                         $headers .= "Location: $after$rest\r\n";
-                    } elsif($reverseproxy and /^Location: \/(.*)\r$/) {
+                    } elsif(/^Location: \/(.*)\r$/) {
                         my $before = "/$1";
-                        my $after = "$reverseproxy$before";
 
-                        log_info(2, "converting: Location: $before --> Location: $after");
-
-                        $headers .= "Location: $after\n";
+                        if($PREFIX) {
+                            $reverseproxy = "/http://$serverhost";;
+                        }
+                        if($reverseproxy) {
+                            my $after = "$reverseproxy$before";
+                            log_info(2, "converting: Location: $before --> Location: $after");
+                            $headers .= "Location: $after\n";
+                        }
                     } elsif(/^\r$/) {
                         $headers .= $_;
                         last;
@@ -233,19 +253,50 @@
                     }
                 }
 
+                if($length) {
+                    log_info(0, "    data: $type [$length]");
+                    read($remote_server, $data, $length) or die "    error: $!";
+                } else {
+                    # chunked transfer coding
+                    # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
+
+                    if($type) {
+                        log_info(0, "    data: $type [chunked]");
+                    } else {
+                        log_info(0, "    data: unspecified type");
+                    }
+                    while(<$remote_server>) {
+                        my ($d, $length) = ("", 0);
+                        ($length = $_) =~ s/;.*$//;
+                        $length =~ s/\r$//;
+                        chomp $length;
+                        $length = hex $length;
+                        last unless $length;
+                        while(length $d < $length) {
+                            $d .= <$remote_server>;
+                        };
+                        $d =~ s/\r$//;
+                        chomp $d;
+                        $data .= $d;
+                    }
+                    $data .= "\r\n";
+                }
+
+                log_info(1, sprintf "    data: received %d bytes", length $data);
+
                 if($html) {
                     log_info(0, "    data: $type (recognized as HTML)");
                     my $next = "";
 
-                    while(<$remote_server>) {
-                        my $line = $_;
-
-                        unless($router or $reverseproxy) {
-                            $content .= $_;
+                    foreach my $line (split /\n/, $data) {
+                        unless($router or $reverseproxy or $PREFIX) {
+                            $content .= $line;
                             next;
                         }
 
-                        $line = "$next $line";
+                        my $space = "";
+                        $space = " " if length $next;
+                        $line = "$next$space$line";
                         chomp $line;
                         $next = "";
 
@@ -264,8 +315,10 @@
 
                                 if($router) {
                                     $host = append_exit($host, $router);
-                                    log_info(1, "<$tag tag: $host>");
                                 }
+                                if($PREFIX and $PREFIX ne "$host$port") {
+                                    $proxypath = "http://$PREFIX/";;
+                                }
 
                                 my $after = "$tag$attr$label=$quote$proxypath$pre$host$port";
 
@@ -273,20 +326,23 @@
 
                                 $content .= "<$after";
                                 $line = "$post$rest";
-                            } elsif($reverseproxy and $line =~ /^<(a|form|frame|img|input|link)([^>]+)(action|href|src)=(\'?\"?)\/(.*)$/i) {
+                            } elsif($line =~ /^<(a|form|frame|img|input|link)([^>]+)(action|href|src)=(\'?\"?)\/(.*)$/i) {
+                                my $after;
                                 my ($tag, $attr, $label, $quote, $rest) = ($1, $2, $3, $4, $5);
-
                                 my $before = "$tag$attr$label=$quote/";
 
                                 # normalize
                                 $tag =~ y/A-Z/a-z/;
 
-                                my $after = "$tag$attr$label=$quote$reverseproxy/";
-
-                                log_info(2, "converting: <$before --> <$after");
-
-                                $content .= "<$after";
-                                $line = $rest;
+                                if($PREFIX) {
+                                    $reverseproxy = "/http://$serverhost";;
+                                }
+                                if($reverseproxy) {
+                                    $after = "$tag$attr$label=$quote$reverseproxy/";
+                                    log_info(2, "converting: <$before --> <$after");
+                                    $content .= "<$after";
+                                    $line = $rest;
+                                }
                             } elsif($line =~ /^(<.*?>)(.*)$/) {
                                 $content .= $1;
                                 $line = $2;
@@ -304,35 +360,23 @@
                         $content .= "\n";
                     }
 
-                    foreach my $line (split /\n/, $headers) {
-                        if($line =~ /^Content-Length: (\S+)\r$/i) {
-                            $length = length $content;
-                            print "Content-Length: $length\n";
-                        } else {
-                            print "$line\n";
+                    # explicitly set Content-Length
+
+                    my @headerlines = split /\n/, $headers;
+                    my @newheaders = ();
+
+                    foreach my $headerline (@headerlines) {
+                        next if $headerline =~ /^Transfer-Encoding: chunked/;
+                        unless($headerline =~ /^Content-Length: (\S+)\r$/i) {
+                            push @newheaders, $headerline if length $headerline > 2;
                         }
                     }
-                    print $content;
-
-                } elsif($length) {
-                    my $data = "";
-                    print $headers;
-
-                    log_info(0, "    data: $type [$length]");
-                    read($remote_server, $data, $length) or die "    error: $?";
-                    print "$data\n";
+                    push @newheaders, sprintf "Content-Length: %d", length $content;
+                    $headers = join "\n", @newheaders;
+                    print "$headers\n\n$content";
                 } else {
-                    print $headers;
-                    if($type) {
-                        log_info(0, "    data: $type");
-                    } else {
-                        log_info(0, "    data: unspecified type");
-                    }
-                    while(<$remote_server>) {
-                        print;
-                    }
+                    print "$headers$data";
                 }
-
                 kill('TERM', $kidpid);          # kill my twin cause we're done
             }
             # this is the fork's child, the master's grandchild
@@ -356,7 +400,10 @@
                             $length = $1;
                             print;
                             log_info(1, "    send: $_");
+                        } elsif(/^Accept-Encoding: /i) {
+                            log_info(1, "    suppress: $_");
                         } elsif(/^Host: (\S+)\r$/i) {
+                            my $h = $1;
                             my $router = "";
                             my $repl = $reverseproxy || $1;
                             if($repl =~ /\.[A-Za-z0-9-]+\.exit(:[0-9]+)?$/) {
@@ -369,7 +416,7 @@
                             }
                             log_info(0, "transmitting router: [$router]");
                             $router .= "+$reverseproxy" if $reverseproxy;
-                            print WRITER "$router\n";
+                            print WRITER "$h\n$router\n";
                             close WRITER;
 
                             $repl = "Host: $repl\r\n";
@@ -464,4 +511,3 @@
     $SIG{CHLD} = \&REAPER;
 };
 
-