http://www.perlmonks.org?node_id=590199

duzvik has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I need hide real links from users, i write such script, but i'n not support resume downloading .... here my script:
#!/usr/bin/perl $| = 1; use strict; use Date::Format; use CGI qw(Fatalstobrouser); my $filename = "Proklate2.avi"; my $path = "/tmp/upload/"; unless ( -e $path . $filename ) { print STDERR "No such file! $path$filename"; return 0; } my @finfo = stat("$path$filename"); my $filesize = $finfo[7]; my $mfile = $finfo[9]; my $filemtime = time2str( "%D, %d %M %Y %H%i%s %T", $mfile ); open FH, "< $path$filename" or die "Can't open $path$filename: $!"; my $contentSize; $| = 1; my $HTTP_RANGE = $ENV{HTTP_RANGE}; if ($HTTP_RANGE) { my $range = $HTTP_RANGE; # bytes 7210589-14411430/14411431 $range =~ m/bytes=(\d+)-/; $range = $1; $contentSize = $filesize - $1; warn("cont size is $contentSize and range is $range\n"); my $p1 = $filesize - $contentSize; my $p2 = $filesize - 1; my $p3 = $filesize; seek( FH, $p1, 0 ) or die "Couldn't seek to $p1: $!\n"; print STDOUT "HTTP/1.1: 206 Partial Content\r\n"; print STDOUT "Last-Modified: $filemtime\r\n"; print STDOUT "Cache-Control: None\r\n"; print STDOUT "Pragma: no-cache\r\n"; print STDOUT "Accept-Ranges: byte\r\n"; print STDOUT "Content-Disposition: attachment; filename=\"$filena +me\"\r\n"; print STDOUT "Content-Range: bytes " . $p1 . "-" . $p2 . "/" . $p +3."\r\n"; print STDOUT "Content-Length: $contentSize\r\n"; print STDOUT "Proxy-Connection: close\r\n"; print STDOUT "Content-type: application/octet-stream\r\n"; print STDOUT "\r\n"; } else { $contentSize = $filesize; print STDOUT "Last-Modified: $filemtime\r\n"; print STDOUT "Cache-Control: None\r\n"; print STDOUT "Pragma: no-cache\r\n"; print STDOUT "Accept-Ranges: bytes\r\n"; print STDOUT "Content-Disposition: attachment; filename='$filenam +e'\r\n"; print STDOUT "Content-Length: $contentSize\r\n"; print STDOUT "Content-type: application/octet-stream\r\n"; print STDOUT "Proxy-Connection: close\r\n"; print STDOUT "\r\n"; } binmode FH; my $buffer; STREAM: while ( read( FH, my $buffer, 65536 ) ) { last STREAM unless print STDOUT $buffer; } close FH;
But log of sended headers:
25 16.12.2006 14:45:28 GET /cgi-bin/downl.pl HTTP/1.0 User-Agent: Download Master Accept: */* Referer: http://localhost/cgi-bin/ Range: bytes=391001341- Pragma: no-cache Cache-Control: no-cache Host: localhost 26 16.12.2006 14:45:28 HTTP/1.1 200 OK <-----------------HERE IS STRA +NGE(not my ) HEADER Date: Sat, 16 Dec 2006 12:45:28 GMT Server: Apache/1.3.33 (Cygwin) Accept-Ranges: byte Cache-Control: None Content-Disposition: attachment; filename="Prok +late2.avi" Content-Range: bytes 391001341-734490623/734490 +624 HTTP/1.1: 206 Partial Content<---HERE IS CORREC +T HEADER Pragma: no-cache Proxy-Connection: close Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT Content-Length: 343489283 Connection: close Content-Type: application/octet-stream
Than script sends 200 OK response, but I need 206. Can you please advice how to make workaround for this?

Replies are listed 'Best First'.
Re: hide direct link script
by rhesa (Vicar) on Dec 16, 2006 at 13:23 UTC
    Your 206 header is malformed. Try this:
    print STDOUT "Status: 206 Partial Content\r\n";
      Great, it works, thanks! but i meed new problem : ( i use for testing download master, and DM create 5 threads for this scripts, and before creating 5 threads(set by default) it freeze while opening thread 2,3,4,5. Opening thread 1 - are done quickly. Any ideas how workaround it ?
        seems it's problem of DM! Thanks for help! all is fine!
Re: hide direct link script
by nobull (Friar) on Dec 16, 2006 at 17:07 UTC
    That's a lot of work already and you've only just started to scratch the surface of all the things you need to consider for a full featured restartable download (etags etc).

    Much simpler to simply have the CGI generate an internal redirect to a location holding the file and use web server configuration directives to cause it to reject HTTP direct requests to that location. This way the web server does all the hard work for you. You probably want to avoid the server putting on Content-location: headers too so that real smart browsers don't get the idea that they should be able to bypass your script.