#!/usr/bin/perl -w # browse zipfiles (in this same directory) like a filesystem via http # # (c) Heiko Hellweg (hellweg@snark.de) 2002 # current version should be findable at http://www.snark.de/tools/ # # License: do to it whatever you want: use, modify, redistribute, hate it... # no warranties that it does or does not perform in any predictable way. # ####################### # $Id: zipcat.cgi,v 1.5 2002/03/07 09:48:31 hh Exp $ ###################### use HTTP::Date ; ###################### # you may want to configure the following parameters to suit your needs # # location ot the unzip binary # (tested only with 'UnZip 5.42 of 14 January 2001, by Info-ZIP') my $unzip = '/usr/bin/unzip' ; # # should a specific file be served when requesting a directory? these are # tried in ascending order (and should be used case insensiteve by unzip). my @indexfiles = ("index.html", "index.htm") ; # # map fileExtensions to mimeTypes (use lowercase here) my $mimeMap = { htm => 'text/html', html => 'text/html', txt => 'text/plain', gif => 'image/gif', jpg => 'image/jpeg', jpeg => 'image/jpeg', png => 'image/png', doc => 'application/msword', ps => 'application/postscript', rtf => 'application/rtf', xml => 'text/xml', dtd => 'text/xml', css => 'text/css' } ; # # end of config section ###################### # debugging: this way it works on the commandline also if(!$ENV{'SCRIPT_NAME'} ) { $ENV{'SCRIPT_NAME'} = $0 ; $ENV{'SCRIPT_FILENAME'} = $0 ; $ENV{'PATH_INFO'} = shift || '' ; } if($ENV{SCRIPT_NAME} =~ /\/nph/) { # running in nph-mode? print("HTTP/1.0 200 OK\n") ; } if($ENV{'PATH_INFO'} && $ENV{'PATH_INFO'} ne "/") { if($ENV{'PATH_INFO'} eq '/showsource/nph-zipcat.cgi') { # don't run zipcat but rather show the source showSource($0) ; exit(0) ; } # try to serve the content of a zipfile my $path = unURL($ENV{'PATH_INFO'}) ; my $queryString = "" ; # will be ignored completely if($path =~ s/(\?.*)$//) { $queryString = $1 ; } # does it look sane? (better safe than sorry) if($path !~ /^[A-Za-z0-9\.\-\_\ \/]+$/ || $path =~ /\.\./) { print("ContentType: text/plain\n\n $path looks illegal to me\n") ; exit(0) ; } if($path =~ s!^/([^\/]+)/!/!) { my $zipfile = $1 ; my $base = $ENV{'SCRIPT_FILENAME'} ; $base =~ s/\/[^\/]+$/\/$zipfile/ ; print("ContentType: text/plain\n\n no way!\n") unless (-r $base) ; if($path =~ /\/$/) { # ending in a / ? browseDir($base, $path) ; } else { catFile($base, $path) ; } exit(0) ; } else { print("ContentType: text/plain\n\n") ; print("huh? what? where?\n") ; # foreach(sort keys %ENV) { print "$_ => $ENV{$_}\n"; } exit(0) ; } } else { # no path-info show, which zipfiles are available in the current dir my $path = $ENV{'SCRIPT_FILENAME'} ; $path =~ s/\/[^\/]+$// ; my $curdir = $path ; $curdir =~ s/.+\/// ; print("Content-Type: text/html\n\n
\n") ; print("parent$notfound\n") ; my $cmd = "$unzip -l $base '$searchfor*' |" ; my $matchpat = "$searchfor" . "[^/]+/?" ; my $zippar = $base ; $zippar =~ s/.+\/// ; my %knownElems = () ; if(open(RH, $cmd)) { while(\n") ; } sub showSource { my ($showfile) = (@_) ; my @stat = stat($showfile) ; print("Content-Type: text/plain\n") ; print("Content-Length: $stat[7]\n") ; print("Last-Modified: $stat[9]\n") ; print("\n") ; if(open(RH, $showfile)) { while() { chomp ; if(/^(\s+\d+)\s+([\d\-]+\s+[\d\:]+)\s+(.+)/) { my $size = $1 ; my $timestamp = $2 ; my $filename = $3 ; if($filename =~ /^$searchfor([^\/]+\/?)$/) { # directory, not too deep? print("$size $timestamp $1\n") ; $knownElems{$1}++ ; } elsif($filename =~ /^$searchfor([^\/]+\/).+$/) { # a file within a deeper subdir - do we know the subdir? if(! $knownElemss{$1}) { print("$size $timestamp $1\n") ; $knownElemss{$1}++ ; } } else { # print("$filename does not match\n") ; } } elsif(/^\s*\d+\s+\d+\s+files\s*$/ || /Archive:\s+/) { # wrong summary line or Archive-line containing real filename # - just drop it # print("wrong summary $_\n") ; } else { print "$_\n" ; # plain text } } close(RH) } print("