NB: These pages were mostly written in 2001 or so. The résumé dates are accurate but the code is aged and unlike whiskey, 8 year-old code doesn't usually taste better. For a look at my current skills and to see my CPAN modules, sample code, and code discussions, please see these pages instead: Perl resources and sample code and PangyreSoft.
File viewer
Social links
View Ashley Pond V's profile on LinkedIn
Miscellaneous

Other pages

Description

Let’s create a CGI that views the sources of files. This could be used to look at CGI code or even raw HTML, though your browser gives you this capability for HTML already, you cannot view the source code of executables (like CGIs). This is generally a good thing, but in certain environments, like this one or a programming environment, you want to be able to display code.

With Perl it’s an entirely trivial matter to make a CGI that will display files. It can be done in one line. The entire CGI script could look like this.

Do not use this code.

print "Content-type: text/plain\n\n", `cat $ENV{QUERY_STRING}`;

That CGI script (pretend it’s called “one_liner.cgi”) will print the contents of any file passed as the query string. So you could print this page, viewer.html, by calling the script this way (if you were an idiot and really installed it). It would be called like so.

http://host.com/one_liner.cgi?viewer.html

Anything in the URL that follows the “?” is passed to %ENV, and to Perl, in $ENV{QUERY_STRING}.

Now, you should be saying to yourself, “What!?! You’re a psycho! If I caught you installing a script like that on my server I’d have you shot and then deported.” Why? Because you can call the script like this.

http://host.com/one_liner.cgi?/usr/bin/*

Or worse. Don’t try it. Just be assured it works and that it’s not even the most dangerous hack possible. If you don’t know any, ask your sysadmin, but you won’t learn ‘em from me. To use it is to open your entire server, not just the webserver’s document root, to whomever wants to see it. You would give them a channel to mess with it and, depending on your permissions schemes, completely trash it.

When using backticks (`) in Perl to execute commands, you give access to the operating system’s shell to any visitor to your website. Web visitors are usually anonymous and sometimes malicious. We could use the multiple argument form of system() or exec() to make it safer. Without help the script is extremely foolish.

Also, you never want to print back anything unless you know what it is, ever. If you even just echo back, by printing to the browser page, the $ENV{QUERY_STRING}, you might be causing the browser to execute embedded <script> tags. This is usually known as a cross-site scripting attack.

We can make it safe and keep it one line of code (spread out below for readability) but it becomes hard to understand. So it’s only an exercise and really not suitable for production.

We use “text/html” instead of “text/plain” because some browsers won’t respect the plain text directive when showing the raw text contents of an HTML file. We have to provide a ”<PRE>” tag and then substitute all the opening tags “<” with “&lt;” so our page will print as plain text.

Code (one line, more or less)

This isn’t so bright, though it (probably) works. Here are the different ways it can be called.

It might not work as expected because of our HTML tag hack.

If we allow for using a module, we can make this approach much more reliable, if not more readable.

Code (minimalist, slightly improved)

So, even though it’s jazzed up, it’s still basically a one-liner that flows like this.

  1. Initialize module HTML::Entities; we’ll use encode_entities() from it.
  2. Print content header to browser (and body begins with a ”<PRE>” tag), correctly configured servers will error out unless the content-type is delivered in the page header.
  3. Match the query string.
    1. If it doesn’t match a conservative file name regex (dots, dashes and alphanumerics only and leads with a \w) then print You must provide a valid filename, this also happens when filename is missing.
  4. If it does match the regex but doesn’t exist in the same dir, report There is no file: blank.
  5. If it does exist, `cat` it and convert HTML characters to print correctly

-T, the taint flag

You might have noticed we didn’t use the -T(aint) flag. It’s a good idea to have it in all your CGIs. It requires that we check all our variables, especially environmental ones, to be sure we’ve at least looked at everything the script is doing. It isn’t a security blanket but it’s a good seatbelt. And it doesn’t make your scripts secure, it merely forces you to take action (right or wrong) on the most vulnerable parts.

Even in this short space we’ve made a program that is fairly secure and gives prominent user feedback when used incorrectly.

We could even simplify the script by printing “text/plain” instead of “text/html.” We would be able to dispense with the HTML::Entities if we did. We could do away with the map, split bit too. The <H2>s for error messages would have to go though and they clarify the usage well. Plus the browser might not respect the “text/plain” content and display the page wrong anyway because its text begins ”<HTML>.”

Are we there yet?

So the second stab is okay. It’s simple. It works. It’s probably not be the kind of thing we’d want in production but you never know. We might like more features and expandability. Fixing or extending the code shown would be an unpleasant excercise.

I’ve seen some wonderful code examples posted online. Often they have line numbers included. This helps when discussing the code but it is a pain in the rear (unless you’re fast with the -F switch or awk) to copy and paste. So, I’d like a viewer script that will display with lines or without. Also, some kids only number the lines with code and others number all the lines literally. We’d better provide for both of those as well. And since it’s a viewer, how about its default being to show its own code?

As you might already know from playing with it, the viewer used in these pages for code does these things. Without further ado, viewer.cgi; and for colored code, the new and improved perlview.cgi!

Discussion

There are some more general CGI usage notes and discussion here.

Search these pages via Google
Text, original code, fonts, and graphics ©1990-2009 Ashley Pond V.