[Pdx-pm] Sorry CGI question

Tom Phoenix rootbeer at redcat.com
Sat Dec 13 00:32:15 CST 2003


On Fri, 12 Dec 2003, Roderick A. Anderson wrote:

> Is there a way to end a CGI script with dynamic content (username,
> connection info, etc.) so that a reload/refresh won't rerun the CGI
> script?

Isn't there a module on CPAN for this? I couldn't find it, but my sleepy
brain probably didn't think of the right search term.

If you're using a form, browsers are not supposed to blindly re-use a POST
action without asking the user. Not that you can completely rely upon that
happening... :-)  Of course, GET requests, such as clicking on link text,
may be reused without any problem. So it sounds like this is a job for a
POST, for one thing.

I think you want to do something like this: Include something that makes
each request unique, so that you'll know if the "same" form is used twice.
For example, each time you generate the form, include some random data
item, such as 'random_id=12345987'. (Or the equivalent as a form element,
or whatever.)

Now, on each submission, check to see whether that same ID number has been
used in the past, say, 100 seconds. If it has, you have several options.
One is to just dump out a page scolding the user for multiple impatient
clicks. Another would be to try to re-create the request page that they
were requesting, perhaps with a little scolding included. (That is, you
try to give them the page they would have gotten from doing the request
just once.) But if it's hard or impossible to give them the true page, you
could keep a page cache and give out the page from the cache.

A page cache sounds hard, but it's easy if you combine it with the ID
number idea: Keep a small directory for your cache. Each file is named
with the random ID number used on its form. When the ID number is new
(that is, on the first click) save the HTML to the file and output it to
the browser. If there's a file with the needed ID number, and if that
file's mtime is within the past 100 seconds, your program simply dumps out
the contents of that file. (Well, but see below.)

Odds and ends: How do you keep the cache clean? Each time your program
runs, it deletes any cache files older than 100 seconds. (Does that sound
inefficient? It's okay in this case; unless several people have submitted
the form in the previous few minutes, there should be few cache files in
the directory.) Why make the ID numbers random? Because that was the first
idea in my head; unless security is an issue, it's probably simpler to
make them sequential. (Well, security is always an issue with CGI
programs. But unless there's something special going on, there's not much
that an attacker can do by guessing the number that they can't do in a
general denial-of-service attack.) How do you scold users when the page is
pulled from the cache? I'd probably do it quick-and-dirty, like this: Put
a place holder into your original HTML:

    <!-- ###place holder### -->

Now it's easy to use a single simple s/// to replace that with whatever
scolding is needed, after you pull in the page from the cache.

One last note: Beware of concurrent processes. Somebody who repeat-clicks
on your link will give you two or more processes running at the same time,
sooner or later. It's probably best to have a single file somewhere that
your program gets an exclusive lock on; I often use a log file for that
purpose, keeping it open for the entire run of the program. If you don't
use a lock file, you may start dumping out a cache entry while it's still
being saved into the file, or something worse.

Hope this helps!

--Tom Phoenix



More information about the Pdx-pm-list mailing list