jigit/iso-image.pl

256 lines
7.4 KiB
Perl
Executable File

#!/usr/bin/perl -w
#
# iso-image.pl
#
# (C) 2004 Steve McIntyre <steve@einval.com>
#
# CGI wrapper to work with mkimage
#
# Parse the parameters and call mkimage as appropriate, paying
# particular attention to byte ranges
#
# GPL v2
#
# v 0.1
use strict;
use File::Basename;
use Socket;
# Configure these for your system
my $mkimage = "/usr/local/bin/jigit-mkimage";
my $logfile = "/var/log/jigdo-logs/log.$$";
my $template_dir = "/mirror/jigdo";
my $matches = "-q -m Debian=/mirror/debian -m Non-US=/mirror/debian-non-US";
my $size;
my $image_name;
open LOGFILE, ">> $logfile" || die "Unable to open logfile!\n";
# Log an error to the user
sub user_error ($) {
my $my_name = "iso_image.pl";
print "Status: 400 Invalid Request\n";
print "Content-type: text/html\n\n";
print "$my_name: @_<p>Abort.\n";
}
# Log a message to the logfile and stop
sub log_die ($) {
print LOGFILE @_;
die @_;
}
# Convert the .iso filename into a .jigdo
sub jigdo_name ($) {
my ($jigdo_name) = @_;
$jigdo_name =~ s/\.iso$/\.jigdo/g;
$jigdo_name = $template_dir . "/" . $jigdo_name;
return $jigdo_name;
}
# Convert the .iso filename into a .template
sub template_name ($) {
my ($template_name) = @_;
$template_name =~ s/\.iso$/\.template/g;
$template_name = $template_dir . "/" . $template_name;
return $template_name;
}
# Grab the image size out of the template file
sub image_size ($) {
my ($image_name) = @_;
my $image_size;
my $cmdline = "$mkimage -l " . $logfile . " -z -t " . template_name($image_name);
open (FH, '-|', $cmdline);
$image_size = <FH>;
close FH;
return $image_size;
}
# We have no range headers; simply generate the full image
sub produce_full_image ($$) {
my ($image_name, $size) = @_;
my $output_name = basename($image_name);
my $cmdline;
my $err = 0;
$cmdline = "$mkimage -l " . $logfile;
$cmdline = $cmdline . " -t " . template_name($image_name);
$cmdline = $cmdline . " -j " . jigdo_name($image_name);
$cmdline = $cmdline . " " . $matches;
print "Status: 200 OK\n";
print "Content-Type: application/octet-stream\n";
print "Content-Disposition: inline;filename=$output_name\n";
print "Content-Length: $size\n\n";
$err = system($cmdline) >> 8;
if ($err) {
log_die ("Failed to rebuild image; error $err\n");
}
}
# Generate the desired range
sub produce_range ($$$) {
my ($image_name, $start, $end) = @_;
my $output_name = basename($image_name);
my $cmdline;
my $err = 0;
$cmdline = "$mkimage -l " . $logfile;
$cmdline = $cmdline . " -t " . template_name($image_name);
$cmdline = $cmdline . " -j " . jigdo_name($image_name);
$cmdline = $cmdline . " -s " . $start;
$cmdline = $cmdline . " -e " . $end;
$cmdline = $cmdline . " " . $matches;
# print "X-output: cmdline $cmdline\n";
$err = system($cmdline) >> 8;
if ($err) {
log_die ("Failed to rebuild image; error $err\n");
}
}
# Calculate start, end and length from the supplied range
sub parse_range ($$) {
my ($range, $size) = @_;
my @offsets;
my $content_length = 0;
if (length($range) == 1 && $range =~ m/-/g ) {
$offsets[0] = 0;
$offsets[1] = $size - 1;
} else {
@offsets = split(/-/, $range, 2);
}
if (!defined($offsets[0]) || !length($offsets[0])) {
$offsets[0] = -1;
}
if (!defined($offsets[1]) || !length($offsets[1])) {
$offsets[1] = $size - 1;
}
if ($offsets[0] == -1) {
$offsets[0] = $size - $offsets[1];
$offsets[1] = $size - 1;
}
# Make sure we have been given numbers
$offsets[0] = int($offsets[0]);
$offsets[1] = int($offsets[1]);
# Check they're valid
if ($offsets[0] < 0 || $offsets[0] >= $size) {
print "Range start $offsets[0] invalid!\n";
log_die "Range start $offsets[0] invalid!\n";
}
if ($offsets[1] < 0 || $offsets[1] >= $size) {
print "Range end $offsets[1] invalid!\n";
log_die "Range end $offsets[1] invalid!\n";
}
if ($offsets[0] > $offsets[1]) {
print "Range start $offsets[0] after end $offsets[1]!\n";
log_die "Range start $offsets[0] after end $offsets[1]!\n";
}
$content_length = $offsets[1] + 1 - $offsets[0];
return ($offsets[0], $offsets[1], $content_length);
}
# We've been asked for ranges. Calculate which ones, then start generating them
sub produce_ranges ($$$) {
my ($image_name, $size, $ranges) = @_;
my $output_name = basename($image_name);
my $cmdline;
my $err = 0;
my @range_array;
my ($start, $end, $range, $length);
chomp $ranges;
$ranges =~ s/^.*\=//g;
@range_array = split (/,/, $ranges);
if (scalar(@range_array) == 1) {
($start, $end, $length) = parse_range($range_array[0], $size);
print "Status: 206 Partial content\n";
print "Content-Type: application/octet-stream; filename=$output_name\n";
print "Content-Range: bytes $start-$end/$size\n";
print "Content-Length: $length\n\n";
$err = produce_range($image_name, $start, $end);
} else {
print "Status: 206 Partial content\n";
print "Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES\n\n";
for my $range (@range_array) {
($start, $end, $length) = parse_range($range, $size);
print "--THIS_STRING_SEPARATES\n";
print "Content-Type: application/octet-stream; filename=$output_name\n";
print "Content-Range: bytes $start-$end/$size\n\n";
$err = produce_range($image_name, $start, $end);
}
print "--THIS_STRING_SEPARATES\n";
}
}
################################################################################
#
# All starts here
#
my $remote_host = $ENV{'REMOTE_HOST'};
my $remote_addr = $ENV{'REMOTE_ADDR'};
my $ultimate = $ENV{'HTTP_X_FORWARDED_FOR'};
my $iaddr;
my $ult_name;
# Sanity checking
if (!defined($ARGV[0])) {
user_error("You must specify an image name to download.");
log_die "No file specified...!\n";
}
if (!defined($remote_host) || !length($remote_host)) {
$iaddr = inet_aton($remote_addr);
$remote_host = gethostbyaddr($iaddr, AF_INET);
}
print LOGFILE "Connection made from $remote_addr ($remote_host)\n";
if (defined($ultimate) && length($ultimate)) {
$iaddr = inet_aton($ultimate);
$ult_name = gethostbyaddr($iaddr, AF_INET);
print LOGFILE "Proxy for: $ultimate ($ult_name)\n";
}
print LOGFILE "Asking for $ENV{SCRIPT_NAME}/$ENV{QUERY_STRING}\n";
print LOGFILE "Generating $ARGV[0]:\n";
print LOGFILE scalar localtime;
print LOGFILE "\n\n\n";
$image_name = $ARGV[0];
if (! -f template_name($image_name)) {
user_error("No template file found to match image name \"$image_name\"");
log_die ("Couldn't find template file for image $image_name\n");
}
if (! -f jigdo_name($image_name)) {
user_error("No jigdo file file found to match image name \"$image_name\"");
log_die ("Couldn't find jigdo file for image $image_name\n");
}
$size = image_size($image_name);
chomp $size;
if (defined($ENV{HTTP_RANGE})) {
# We have range(s) specified. Parse what we've been given and call
# mkimage for each range
produce_ranges($image_name, $size, $ENV{HTTP_RANGE});
} else {
# If we don't have a Range: header, simply return the whole image
produce_full_image($image_name, $size);
}
print LOGFILE "Done\n";
print LOGFILE scalar localtime;
print LOGFILE "\n\n\n";
exit 0;