#!/usr/bin/perl -w # "harte" Perl-Regeln use strict; # für gettimeofday() (gettimeofday() ist mikrosekunden-genau) use Time::HiRes qw(gettimeofday); # für die Kommunikations mit dem HTTP-Server use LWP::UserAgent; use HTTP::Request; use HTML::Entities; # für GetOptions() (Kommandozeilenverarbeitung) use Getopt::Long; my $opts = { 'base-url' => 'http://rain/artikel/site/', # Basis-URL 'send-if-modified-since' => 0, # Switch, ob wir If-Last-Modified verwenden sollen 'send-if-none-match' => 0, # Switch, ob wir If-None-Match verwenden sollen 'help' => \&help }; # Optionen einlesen GetOptions( $opts, 'base-url=s', 'send-if-modified-since', 'send-if-none-match', 'help' ); my $time = 0; # Zeit, die wir für den Request gebraucht haben my $down = {}; # Verzeichnis von URLs, die wir bereits geladen haben # Das UserAgent-Objekt, dass unsere Anfragen an den HTTP-Server stellt my $ua = new LWP::UserAgent; # Nun führe bitte auch den Request durch... die Rückgabe brauchen wir # zum filtern der URLs (wir wollen schliesslich alles zum Rendern des # Dokumentes Notwendige herunterladen) my $str = do_request($ua,$opts->{'base-url'},$down,$opts,\$time); # ausserdem brauchen wir die Basis-URL, in der *nur* der # Verzeichnisname ist my $baseurl = $opts->{'base-url'}; $baseurl =~ s!/[^/]+$!/!g; # durchsuche alle src-Attribute (Bilder, Scripte, etc) while($str =~ m!src=(?:(?:(['"])(.+?))|(\S+))\1!ig) { my $uri = $2||$3; $uri = $baseurl.$uri unless $uri =~ m!^http://!; $uri =~ s/#.+$//; $uri = decode_entities($uri); $uri =~ s!([^:])//!$1/!g; do_request($ua,$uri,$down,$opts,\$time); } # durchsuche alle -Attribute, die ein Stylesheet referenzieren while($str =~ m!]+rel=["']stylesheet["'][^>]+href=(?:(?:(["'])(.+?)\1)|(\S+))!ig) { my $uri = $2||$3; $uri = $baseurl.$uri unless $uri =~ m!^http://!; $uri =~ s/#.+$//; $uri = decode_entities($uri); $uri =~ s!([^:])//!$1/!g; do_request($ua,$uri,$down,$opts,\$time); } # gib eine Meldung an den User print sprintf("\n".'Time elapsed: %5.6f seconds'."\n",$time/(10**6)); # Hilfetext sub help { print <{$uri}; # Datei im Katalog registrieren $down->{$uri}++; # Status-Meldung für den User print "Getting $uri...\n"; my $rq = new HTTP::Request('GET',$uri); # So, wir brauchen die Zeit von vor dem Request (möglichst genau; # gettimeofday liefert die Sekunden seit dem 1.1. 0:00 1970 plus # die Mikrosekunden der angebrochenen Sekunde) und die Zeit von # nach dem Request. Zeit vorher - Zeit nachher gibt dann die # Uebertragunszeit plus einen vernachlässigbaren Analyse-Overhead. @td1 = gettimeofday(); my $rsp = $ua->request($rq); @td2 = gettimeofday(); # Wenn wir If-Modified-Since schicken sollten, so brauchten wir den # ersten Request, um das Änderungsdatum zu bekommen. Das heisst, dergleiche # Request muss noch einmal getätigt werden, nur mit If-Modified-Since-Header. if($opts->{'send-if-modified-since'}) { if($rsp->header('Last-Modified')) { $rq->header('If-Last-Modified',$rsp->header('Last-Modified')); $re_send = 1; } } # Dasselbe gilt für If-None-Match. Soll dieser Header geschickt werden, # muss der aktuelle Request wiederholt werden, mit einem ausgefüllten # If-None-Match-Header if($opts->{'send-if-none-match'}) { if($rsp->header('ETags')) { $rq->header('If-None-Match',$rsp->header('ETags')); $re_send = 1; } } # Siehe oben... if($re_send) { @td1 = gettimeofday(); $rsp = $ua->request($rq); @td2 = gettimeofday(); } # Verbrauchte Übertragunszeit = alte Zeit + neue Zeit $$time += timediff(@td2,@td1); # uU brauchen wir den Inhalt des Dokumentes -- aber bitte ohne # JavaScript! my $txt = $rsp->content; $txt =~ s!]*)>.*?!!sig; return $txt; } # Zum errechnen der Differenz zwischen zwei # Zeiten sub timediff { my $s1 = shift; my $m1 = shift; my $s2 = shift; my $m2 = shift; my $diff = ($s1 * 1000000 + $m1) - ($s2 * 1000000 + $m2); die 'Sorry? Time diff is '.$diff if $diff < 0; $diff; } # eof