http://blah/blah/blah.wmv http://blah/blah/labh.wmv http://foo/foo/foo%04i 23 40 #### use IO::Socket::INET; use Data::Dumper; use strict; use warnings; $| ++; #@done is populated, but not really used in this version #in the future, might retry failed ones base on done. my (@page, @done); open(PAGES, "<", "pages.txt"); while () { chomp; my @data = split / /; if ($#data == 2) { for my $index ($data[1]..$data[2]) { push @page, sprintf($data[0], $index); push @done, 0; } } elsif ($#data == 0) { push @page, $data[0]; push @done, 0; } } close(PAGES); download(\@page, \@done); sub download { my ($page, $done) = @_; for my $index (0..$#{@$page}) { $done[$index] = download_one_file($page[$index]); } } sub download_one_file { my ($page) = @_; my $host = get_host($page); my $file = get_file($page); my $percentage; my $header = {}; my $return_code; print "Trying $host... "; my $connection = IO::Socket::INET->new(PeerAddr => $host, PeerPort => 80, Timeout => 30); if ($connection) { print "connected, download <$file>\n"; binmode($connection); my $req = "GET $page HTTP/1.0\r\nHost: $host\r\n\r\n"; print $connection $req; my $res; if (open(FILE, ">", $file)) { binmode(FILE); my $bytes_read = 0; while (1) { my $chunk; sysread($connection, $chunk, 4096); #stopped, just fail it if (!length($chunk)) { print " Connection dropped"; $return_code = 0; last; } if (!exists($header->{"status_code"})) { $res .= $chunk; if (got_header($res)) { $res =~ m/(.*?)\r\n\r\n(.*)/s; if ($2) { syswrite(FILE, $2); $bytes_read += length($2); } parse_header($1, $header); if ($header->{"status_code"} eq '200') { $percentage = get_percentage($header->{"Content-Length"}, $bytes_read); print "Content Length = " . $header->{"Content-Length"} . ", Received = $percentage"; } else { print "Status Code = " . $header->{"status_code"}; $return_code = 1; last; } } } else { syswrite(FILE, $chunk); $bytes_read += length($chunk); my $old_percentage = $percentage; $percentage = get_percentage($header->{"Content-Length"}, $bytes_read); if ($percentage != $old_percentage) { print $percentage; } } if ($header->{"Content Length"} && ($header->{"Content-Length"} <= $bytes_read)) { print "Read up to content length\n"; $return_code = 1; last; } if ($res =~ m/\/html/) { print "reached /html tag\n"; $return_code = 1; last; } } close(FILE); print "\n"; } else { $return_code = 0; print "failed to open local file\n"; } } else { $return_code = 0; print "failed, skip $file\n"; } return $return_code; } sub get_host { my ($page) = @_; $page =~ m/\/\/(.*?)\//; return $1; } sub get_file { my ($page) = @_; return (split /\//, $page)[-1]; } sub get_percentage { my ($total, $rcvd) = @_; return int(($rcvd / $total) * 10); } sub got_header { my $res = shift; if ($res =~ m/\r\n\r\n/s) { return 1; } else { return 0; } } sub parse_header { my ($res, $header) = @_; my @lines = split(/\r\n/, $res); $header->{"status_code"} = (split(/ /, $lines[0]))[1]; for my $index (1 .. $#lines) { my ($key, $value) = split(/: /, $lines[$index]); $header->{$key} = $value; } }