| #!/usr/bin/perl -w |
| |
| use strict; |
| |
| use CGI; |
| use File::stat; |
| |
| use constant CHUNK_SIZE_BYTES => 1024; |
| |
| my $query = new CGI; |
| |
| my $name = $query->param('name') or die; |
| my $filesize = stat($name)->size; |
| |
| # Get MIME type. |
| my $type = $query->param('type') or die; |
| |
| # Get throttling rate, assuming parameter is in kilobytes per second. |
| my $kbPerSec = $query->param('throttle') || 0; |
| my $chunkPerSec = $kbPerSec * 1024 / CHUNK_SIZE_BYTES; |
| |
| CGI->nph(1); |
| |
| my $contentRange = $ENV{'HTTP_RANGE'}; |
| |
| my $rangeEnd = $filesize - 1; |
| my @parsedRange = (0, $rangeEnd); |
| |
| my $acceptEncoding = $ENV{'HTTP_ACCEPT_ENCODING'}; |
| |
| my $httpStatus; |
| |
| if ($acceptEncoding) { |
| $httpStatus = "406 Not Acceptable"; |
| |
| print "Status: " . $httpStatus . "\n"; |
| print "Connection: close\n"; |
| print "\n"; |
| } else { |
| my $httpContentRange; |
| if ($contentRange) { |
| my @values = split('=', $contentRange); |
| my $rangeType = $values[0]; |
| @parsedRange = split("-", $values[1]); |
| |
| if (!$parsedRange[1]) { |
| $parsedRange[1] = $rangeEnd; |
| } |
| $httpStatus = "206 Partial Content"; |
| $httpContentRange = "bytes " . $parsedRange[0] . "-" . $parsedRange[1] . "/" . $filesize; |
| } else { |
| $httpStatus = "200 OK"; |
| } |
| |
| print "Status: " . $httpStatus . "\n"; |
| print "Connection: close\n"; |
| print "Content-Length: " . $filesize . "\n"; |
| print "Content-Type: " . $type . "\n"; |
| print "Accept-Ranges: bytes\n"; |
| if ($httpContentRange) { |
| print "Content-Range: " . $httpContentRange . "\n"; |
| } |
| print "\n"; |
| |
| open FILE, $name or die; |
| binmode FILE; |
| my ($data, $n); |
| my $total = $parsedRange[0]; |
| |
| seek(FILE, $parsedRange[0], 0); |
| |
| while (($n = read FILE, $data, 1024) != 0) { |
| print $data; |
| |
| $total += $n; |
| if (($total >= $filesize) || ($total > $parsedRange[1])) { |
| last; |
| } |
| |
| # Throttle if there is some. |
| if ($chunkPerSec > 0) { |
| select(undef, undef, undef, 1.0 / $chunkPerSec); |
| } |
| } |
| close(FILE); |
| } |