[Ilugc] [TIP] perl script for downloading using HTTP

  • From: girishvenkatachalam@xxxxxxxxx (Girish Venkatachalam)
  • Date: Thu, 17 Nov 2011 04:30:58 +0530

Before I begin I have to thank Balachandran Shivakumar for his
suggestion to add
the Host header. I have done that in the C code as well as Perl. Many thanks.

I also appreciate his help.

Now this time around we are doing the same thing in perl. Tomorrow
will be Python.

Then we will shift gears.

Look at the code.

$ cat htdl.pl
#!/usr/bin/perl

use IO::Socket::INET;

$url = shift;
if($url !~ /\w/) {
        die "Please give URL to download!\n";
}

$url =~ /http:\/\/(.*?)\/(.*)/;
$host = $1;
$path = $2;
$2 =~ /.*\/(.*)/;
$file = $1;

$sock = IO::Socket::INET->new(PeerAddr => $host,
                         PeerPort => 'http(80)',
                         Proto => 'tcp');
if(!defined($sock)) {
        die "Could not open socket to $host\n";
}

print $sock "GET /$path HTTP 1.1\r\n\r\nHost foo.bar\r\r\r\n";

open F, ">$file" or die "Could not open file in current dir, check perms\n";

read $sock, $buf, 8192;

$buf =~ s/(.*?)\r\n\r\n(.*)/$2/ms;

print "Wrote " . length($buf) . " bytes to file\n";
print F $buf;

while($bytes = read $sock, $buf, 8192) {
        print F $buf;
        print "Wrote $bytes to file\n";
}
close($sock);
close(F);

print "Wrote $file to disk\n";

You can download from
ftp://tulip.pye.org/htdl.pl

The code with syntax highlighting
ftp://tulip.pye.org/htdl.pl.html

Now you have to run like yday

$ chmod +x htdl.pl

$ ./htdl.pl http://ftp.openssl.org/source/openssl-source-0.9.6.tar.gz

If your perl is not in /usr/bin, then you will have to change the shebang line.

You also can run it like this:

$ perl htdl.pl http://ftp.openssl.org/source/openssl-source-0.9.6.tar.gz

Now I will do a bit of code walkthro'.

Before that I did a performance benchmark. Both the C and perl
versions take the same time.

Lines 10 to 14 use regular expressions to split the URL into host,
file and path tokens.

However I should have used split like this.

($d, $d, $host, @path) = split /\//, $url;

$file = $path[$#path];

$path = join "/", @path;

Instead I used the regex pattern capture operator () and the
backreference $1 to do the same thing.

The split idea would have been neat.

Anyway as you can see there is no need to do DNS is perl. It is a high
level language. Moreover number of lines also is
 less not because I am using perl. It is because I am using the
IO::Socket::INET module.

I think this is not a separate CPAN module. It is a standard perl distribution.

In using that I avoided some 15 lines of painful code of opening a
socket, connecting and so on.

This does it in one stroke(line 16). Also it uses Perl OO.

Remaining stuff is opening a file handle F and writing to it using print.

print $foo

will write to standard output.

print $sock $foo

will write to the TCP, UDP or UNIX socket we open.

prinf F $foo

will write to the file descriptor opened with open() call of perl.

Doing socket I/O in perl is easy. Just like regular socket I/O in C
except that you don't have to use
 buffers.Use scalars instead.

In both C and perl we are not using any HTTP library. So the header in
the response needs to be removed.

But tomorrow in python we see that this is not necessary since python
ships with httplib.

That is tomorrow.

-Girish

-- 
G3 Tech
Networking appliance company
web: http://g3tech.in ?mail: girish at g3tech.in

Other related posts: