Building a simple Perl Module Database

Suppose your latest Perl project makes ample use of homegrown modules. (For an example of this, see the Iaijutsu or Jellybean projects.) Because these are designed to work in a web environment, security is a big concern. However, the modules (or objects, as we tend to call them) also must be mutable. Developers need to be able to modify them slightly via the web interface.

One solution is to use eval() liberally. This involves a performance hit, however, in that each instance where the module is used, it must be recompiled (unless there are steps taken of which I am unaware). Since the module is more likely to be invoked at least ten times for each edit (a low estimate), this introduces a large penalty.

Another concern is security. Is it wise to allow the uid of the web server to have write access to the module directory? A clever invader could exploit this to do all sorts of nasty things. (Then again, allowing real-time editing of executable objects on a production web server does have similar risks.)

A better option, at least in my opinion, and for the Unix world, is a quick method which I devised recently.

Set up your web server and Perl content, running normally with restrictive permissions. Set up a module server process, as in the code section.

In your web server process, you will need to do a couple of things when you want to require() in a module. First, open a pipe for writing. It connects to $INPIPE in the module server. Second, write the name of the module you want, when you want it, to the pipe. Third, call request() on the name of the output pipe in the module server.

Yes, it really works -- require() thinks that a module pulled out of a database somewhere (or off of a network share or something else entirely more bizarre) is the same as a module read from a normal file. If it's valid Perl, it will work.

Please note that I have not set any handlers for SIGPIPE, which you will want to do in a production environment, nor have I given any suggestions for the appropriate locations for the pipes. Still, it is my hope that something here has given you a wacky idea which will prove useful.

use ModuleServer;

my $modpath = "/foo";     # path to where modules are expected
my $module = "";

while (1) {
    open (INPIPE, "> $INPIPE) || die "Can't open $INPIPE: $!";
    my $modname = <INPIPE>;
    close INPIPE;

# fetch module $modname from database or wherever into $module

    unless (-p $modname) {
        unlink $modname;
        system('mknod', $modname, 'p') 
            && die "Can't make pipe $modname: $!";

    open (OUTPIPE, "> $modpath$modname") 
        || die "Can't write to $modname: $!";
    print OUTPIPE $module;
    close OUTPIPE;
    sleep (1);