#!/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