#!/usr/bin/perl -w -s use Data::Dumper; use LWP::Simple; use IO::Socket qw(:DEFAULT :crlf); use Net::hostent; # for OO version of gethostbyaddr use POSIX 'WNOHANG'; use constant PORT => 2007; our $CACHE_DIR = "cache"; mkdir($CACHE_DIR) unless(-d $CACHE_DIR); system("touch $CACHE_DIR/cache.info") unless(-f "$CACHE_DIR/cache.info"); our $ERROR_PAGE = "$CACHE_DIR/error.html"; # Configuraçao do socket e mensagens de diagnostico $listen_socket = IO::Socket::INET->new( Proto => 'tcp', LocalPort => PORT, Listen => SOMAXCONN, Reuse => 1); die "can't setup server" unless $listen_socket; warn "[SProxy running and waiting for connections ...]\n"; warn "[SProxy $0 accepting clients at ".PORT."]\n"; # Night of the Living Dead :-) $SIG{CHLD} = sub {while(waitpid(-1, WNOHANG)>0){}}; # quit handler (Ctrl+C (SIGINT) ) my $quit = 0; $SIG{INT} = sub { $quit++ }; while(!$quit) { next unless my $connection = $listen_socket->accept; # Chegou cliente! my $peer = gethostbyaddr($connection->peeraddr,AF_INET) || $connection->peerhost; #TODO my $port = $connection->peerport; warn "Accepted connection from $peer:$port\n"; #my $ip = $connection->peeraddr; #my $host = gethostbyaddr($ip,AF_INET); #my $port = $connection->peerport; #warn "Accepted connection for client at IP: $peer, ADDRESS: $peer, PORT: $port\n"; defined(my $child = fork()) or die "Can't fork: $!\n"; if($child == 0) { $listen_socket->close; conn_handler($connection); exit 0; } $connection->close; } sub conn_handler { my $sock = shift; my $answer; while(<$sock>) { #TODO mais tarde sera: $/=\n\n e analisar pedido `a lupa. chomp; my $req = $_; $answer = req_handler($req); print $sock $answer."\n"; } } sub req_handler { use Digest::MD5; my $req = shift; my $content; my ($type,$url); if($req=~/^(\w+)\s+(.*)/g) { ($type,$url) = ($1,$2); } #Verifica request na forma: GET url (por exemplo) stats_handler($url); my $head = head($url); if(!$head) { $content = `cat $ERROR_PAGE`; } elsif($type eq "GET") { if(in_cache($url)) { my $head = head($url); warn "$url: temos sim senhor!\n"; my $path = url2path($url); $content = `cat $path`; } else { warn "$url: essa eh nova!\n"; $content = new_page($url); } } $content; } sub new_page { my $url = shift; use URI; use Digest::MD5; my $uri = URI->new($url); my ($host,$path,$query) = ($uri->host,$uri->path,$uri->query); my @path_segments = array_rem_empty($uri->path_segments); my $tail = pop(@path_segments); my $path2 = "$CACHE_DIR/$host/"; mkdir($path2); map { $path2.="$_/"; mkdir($path2); } @path_segments; $content = get($url); my ($content_type, $document_length, $modified_time, $expires, $server) = head($url); my $md5 = Digest::MD5::md5_hex($content); $content = transf($content); open(F,">$path2$tail"); print F $content; close F; open(F,">>$CACHE_DIR/cache.info"); print F "$url§$modified_time§$expires§$md5\n"; close F; $content; } sub array_rem_empty { my @foo = (); map { push(@foo,$_) if($_=~m/./g) } @_; @foo; } sub url2path { my $url = shift; use URI; my $uri = URI->new($url); my ($host,$path,$query) = ($uri->host,$uri->path,$uri->query); my @path_segments = array_rem_empty($uri->path_segments); my $tail = pop(@path_segments); my $path2 = "$CACHE_DIR/$host/".join("/",@path_segments)."/$tail"; $path2; } sub path2url { } sub in_cache { my $url = shift; return (grep {/$url§/} split(/\n/,`cat $CACHE_DIR/cache.info`)); } sub stats_handler { my ($url,$content) = @_; } sub transf { my $content = shift; $content=~s/\n//g; $content; }