7 use POSIX qw(strftime);
9 use File::Copy qw( copy );
12 use Digest::SHA qw(sha256_hex sha1);
15 use File::Spec::Functions qw(rel2abs);
19 use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );
22 my $transaction="unknown";
24 my $logfile = "/var/log/download.log";
25 my $datadir = dirname(rel2abs($0))."/";
26 my $secretfile="/etc/apache2/download.secret";
31 my $t0 = [gettimeofday];
38 my $now = strftime "%a, %d %b %Y %T %z", localtime;
39 printf $log "$now: [$$:%s][$transaction]: ", defined($remoteip)?$remoteip:"unknown";
46 close $log if defined($log);
53 open ($log, '>>', $logfile) || die ("Cannot open logfile $logfile: $!");
60 my $elapsed = tv_interval ( $t0, [gettimeofday]);
61 lprintf "ERROR: $err after %.3f secs\n", $elapsed;
64 my $error = encode_entities( $err );
65 print "Status: 404 Not Found\n";
66 print "Content-type: text/html\n\n";
67 print "<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>$error</p><hr><address>Download Server</address>";
68 print "</body></html>\n";
77 qdie ("Received SIG$signame");
82 my $name = basename($file);
84 open my $fh, '<:raw', $file
85 or qdie "Cannot open '$file': $!";
89 -type => 'application/octet-stream',
90 -Content_length=> $filesize,
94 binmode STDOUT, ':raw';
96 unless (copy $fh => \*STDOUT, 65536)
98 qdie "Cannot write to STDOUT";
102 or qdie "Cannot close '$file': $!";
109 return sha256_hex(shift @_);
114 my $fn = $datadir.(shift @_);
115 $fn = File::Spec->rel2abs( readlink($fn) ) if (-l $fn);
116 qdie ("File not found") unless ( -f $fn);
122 my $query = CGI::url(-absolute=>1);
123 my $clienttime = CGI::url_param('time');
124 my $clientid = CGI::url_param('id');
125 my $clienthash = CGI::url_param('hash');
126 my $clientfile = CGI::url_param('file');
127 $clientfile = "default" unless(defined($clientfile));
128 qdie ("Bad parameters") unless (defined($clienttime) && defined($clientid) && defined($clienthash) && ($clienttime=~/^[0-9]+$/));
130 my $drift = $now-$clienttime;
131 qdie ("Client time has drifted - $now - $clienttime = $drift") if (($drift < -$maxdrift) || ($drift > $maxdrift));
132 qdie ("Bad ID") unless ($clientid=~/^[-+._\@a-zA-Z0-9]+$/);
133 qdie ("Bad filename") unless ($clientfile=~/^[-+._a-zA-Z0-9]+$/);
134 qdie ("Bad filename") if ($clientfile=~/^\./);
136 my $hash = gethash($clienttime.":".$clientid.":".$clientfile.":".$secret);
137 qdie ("Bad hash") unless ($hash eq $clienthash);
138 my $fn = getfile($clientfile);
139 $clientfile = basename ($fn);
140 $transaction=$hash." ".$clientfile." ".$clientid;
146 my $clientfile = shift @_;
147 my $fn = getfile($clientfile);
148 $clientfile = basename ($fn);
149 my $size = "unknown";
151 $size = $sb->size if (defined($sb) && defined($sb->size));
152 my $md5sum = "unknown";
153 my $md5fn = $fn.".md5sum";
157 open $md5, "<", $md5fn || qdie ("Can't read md5sum");
161 $md5sum = $1 if (/^([a-f0-9]+)\b/);
167 -type => 'text/plain' );
169 print "$clientfile $size $md5sum\n";
172 open (my $sfh, "<", $secretfile) || qdie("Can't open secret file $secretfile: $!");
173 chomp($secret=join("",<$sfh>));
176 if (!defined($ENV{DOCUMENT_ROOT}) && !defined($ENV{SERVER_NAME}))
178 die ("Bad parameters") unless ($#ARGV == 1);
180 printf "id=%s&file=%s&time=%s&hash=%s",uri_escape($ARGV[0]),uri_escape($ARGV[1]),$t,gethash($t.":".$ARGV[0].":".$ARGV[1].":".$secret)."\n";
185 my $info = CGI::url_param('info');
191 $remoteip = CGI::remote_addr();
194 my $file = decodeparams;
195 my $sb = stat($file);
196 $filesize = $sb->size;
197 lprintf("STARTING\n");
198 $SIG{INT} = \&caughtsignal;
199 $SIG{QUIT} = \&caughtsignal;
200 $SIG{PIPE} = \&caughtsignal;
201 $SIG{HUP} = \&caughtsignal;
202 $SIG{KILL} = \&caughtsignal;
203 $SIG{TERM} = \&caughtsignal;
205 my $elapsed = tv_interval ( $t0, [gettimeofday]);
206 my $rate = $filesize/(1000000.0*(($elapsed<0.001)?0.001:$elapsed));
207 lprintf("SUCCESS %d bytes %.3f MB/s %.3f secs\n", $filesize, $rate, $elapsed);