5 # (C) 2004 Steve McIntyre <steve@einval.com>
7 # CGI wrapper to work with mkimage
9 # Parse the parameters and call mkimage as appropriate, paying
10 # particular attention to byte ranges
20 # Configure these for your system
21 my $mkimage = "/usr/local/bin/mkimage";
22 my $logfile = "/var/log/jigdo-logs/log.$$";
23 my $template_dir = "/mirror/jigdo";
24 my $matches = "-q -m Debian=/mirror/debian -m Non-US=/mirror/debian-non-US";
28 open LOGFILE, ">> $logfile" || die "Unable to open logfile!\n";
30 # Log an error to the user
32 my $my_name = "iso_image.pl";
33 print "Status: 400 Invalid Request\n";
34 print "Content-type: text/html\n\n";
35 print "$my_name: @_<p>Abort.\n";
38 # Log a message to the logfile and stop
44 # Convert the .iso filename into a .jigdo
46 my ($jigdo_name) = @_;
47 $jigdo_name =~ s/\.iso$/\.jigdo/g;
48 $jigdo_name = $template_dir . "/" . $jigdo_name;
52 # Convert the .iso filename into a .template
53 sub template_name ($) {
54 my ($template_name) = @_;
55 $template_name =~ s/\.iso$/\.template/g;
56 $template_name = $template_dir . "/" . $template_name;
57 return $template_name;
60 # Grab the image size out of the template file
62 my ($image_name) = @_;
64 my $cmdline = "$mkimage -l " . $logfile . " -z -t " . template_name($image_name);
66 open (FH, '-|', $cmdline);
72 # We have no range headers; simply generate the full image
73 sub produce_full_image ($$) {
74 my ($image_name, $size) = @_;
75 my $output_name = basename($image_name);
79 $cmdline = "$mkimage -l " . $logfile;
80 $cmdline = $cmdline . " -t " . template_name($image_name);
81 $cmdline = $cmdline . " -j " . jigdo_name($image_name);
82 $cmdline = $cmdline . " " . $matches;
84 print "Status: 200 OK\n";
85 print "Content-Type: application/octet-stream\n";
86 print "Content-Disposition: inline;filename=$output_name\n";
87 print "Content-Length: $size\n\n";
89 $err = system($cmdline) >> 8;
91 log_die ("Failed to rebuild image; error $err\n");
95 # Generate the desired range
96 sub produce_range ($$$) {
97 my ($image_name, $start, $end) = @_;
98 my $output_name = basename($image_name);
102 $cmdline = "$mkimage -l " . $logfile;
103 $cmdline = $cmdline . " -t " . template_name($image_name);
104 $cmdline = $cmdline . " -j " . jigdo_name($image_name);
105 $cmdline = $cmdline . " -s " . $start;
106 $cmdline = $cmdline . " -e " . $end;
107 $cmdline = $cmdline . " " . $matches;
109 # print "X-output: cmdline $cmdline\n";
110 $err = system($cmdline) >> 8;
112 log_die ("Failed to rebuild image; error $err\n");
116 # Calculate start, end and length from the supplied range
117 sub parse_range ($$) {
118 my ($range, $size) = @_;
120 my $content_length = 0;
122 if (length($range) == 1 && $range =~ m/-/g ) {
124 $offsets[1] = $size - 1;
126 @offsets = split(/-/, $range, 2);
129 if (!defined($offsets[0]) || !length($offsets[0])) {
132 if (!defined($offsets[1]) || !length($offsets[1])) {
133 $offsets[1] = $size - 1;
135 if ($offsets[0] == -1) {
136 $offsets[0] = $size - $offsets[1];
137 $offsets[1] = $size - 1;
140 # Make sure we have been given numbers
141 $offsets[0] = int($offsets[0]);
142 $offsets[1] = int($offsets[1]);
144 # Check they're valid
145 if ($offsets[0] < 0 || $offsets[0] >= $size) {
146 print "Range start $offsets[0] invalid!\n";
147 log_die "Range start $offsets[0] invalid!\n";
149 if ($offsets[1] < 0 || $offsets[1] >= $size) {
150 print "Range end $offsets[1] invalid!\n";
151 log_die "Range end $offsets[1] invalid!\n";
153 if ($offsets[0] > $offsets[1]) {
154 print "Range start $offsets[0] after end $offsets[1]!\n";
155 log_die "Range start $offsets[0] after end $offsets[1]!\n";
157 $content_length = $offsets[1] + 1 - $offsets[0];
158 return ($offsets[0], $offsets[1], $content_length);
161 # We've been asked for ranges. Calculate which ones, then start generating them
162 sub produce_ranges ($$$) {
163 my ($image_name, $size, $ranges) = @_;
164 my $output_name = basename($image_name);
168 my ($start, $end, $range, $length);
171 $ranges =~ s/^.*\=//g;
172 @range_array = split (/,/, $ranges);
173 if (scalar(@range_array) == 1) {
174 ($start, $end, $length) = parse_range($range_array[0], $size);
175 print "Status: 206 Partial content\n";
176 print "Content-Type: application/octet-stream; filename=$output_name\n";
177 print "Content-Range: bytes $start-$end/$size\n";
178 print "Content-Length: $length\n\n";
179 $err = produce_range($image_name, $start, $end);
181 print "Status: 206 Partial content\n";
182 print "Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES\n\n";
183 for my $range (@range_array) {
184 ($start, $end, $length) = parse_range($range, $size);
185 print "--THIS_STRING_SEPARATES\n";
186 print "Content-Type: application/octet-stream; filename=$output_name\n";
187 print "Content-Range: bytes $start-$end/$size\n\n";
188 $err = produce_range($image_name, $start, $end);
190 print "--THIS_STRING_SEPARATES\n";
194 ################################################################################
199 my $remote_host = $ENV{'REMOTE_HOST'};
200 my $remote_addr = $ENV{'REMOTE_ADDR'};
201 my $ultimate = $ENV{'HTTP_X_FORWARDED_FOR'};
206 if (!defined($ARGV[0])) {
207 user_error("You must specify an image name to download.");
208 log_die "No file specified...!\n";
211 if (!defined($remote_host) || !length($remote_host)) {
212 $iaddr = inet_aton($remote_addr);
213 $remote_host = gethostbyaddr($iaddr, AF_INET);
216 print LOGFILE "Connection made from $remote_addr ($remote_host)\n";
217 if (defined($ultimate) && length($ultimate)) {
218 $iaddr = inet_aton($ultimate);
219 $ult_name = gethostbyaddr($iaddr, AF_INET);
220 print LOGFILE "Proxy for: $ultimate ($ult_name)\n";
223 print LOGFILE "Asking for $ENV{SCRIPT_NAME}/$ENV{QUERY_STRING}\n";
224 print LOGFILE "Generating $ARGV[0]:\n";
225 print LOGFILE scalar localtime;
226 print LOGFILE "\n\n\n";
228 $image_name = $ARGV[0];
230 if (! -f template_name($image_name)) {
231 user_error("No template file found to match image name \"$image_name\"");
232 log_die ("Couldn't find template file for image $image_name\n");
235 if (! -f jigdo_name($image_name)) {
236 user_error("No jigdo file file found to match image name \"$image_name\"");
237 log_die ("Couldn't find jigdo file for image $image_name\n");
240 $size = image_size($image_name);
243 if (defined($ENV{HTTP_RANGE})) {
244 # We have range(s) specified. Parse what we've been given and call
245 # mkimage for each range
246 produce_ranges($image_name, $size, $ENV{HTTP_RANGE});
248 # If we don't have a Range: header, simply return the whole image
249 produce_full_image($image_name, $size);
252 print LOGFILE "Done\n";
253 print LOGFILE scalar localtime;
254 print LOGFILE "\n\n\n";