[cgiapp] run mode issues when posting data

Michael De Soto pronet at quarghost.com
Tue Nov 25 12:32:56 EST 2008


Hi all.

I've been a long time user of C::A and I dig it. Until now, the
applications I've written have been pretty simple. They basically
consisted of a form with data passed via GET. A hidden input with the
run mode was all I needed to pass the data off to the right run mode.
Too easy.

The trouble comes when using POST. And the frustrating thing is that I
know there's a simple way to handle this that I'm missing. I've
scoured all the docs and I think I'm just missing something. This is
why I seek your collective wisdom.

Consider this simple use case: my application does basic user
management. There's a login form, a run mode to list the users and a
run mode to edit/create users.

The login aspect works great. cgiapp_prerun checks the server side
session and if a session variable denoting the user is logged in is
missing (or the session is expired), then it directs the user to the
login run mode. When the user submits the login form, we go through
the same process, except this time the presence of username and
password parameters triggers the login run mode to check to see if
they're valid. If they are, then the session variable is set and
cgiapp_prerun isn't triggered again until the session expires:

sub cgiapp_prerun {
    my $app = shift;

    unless ($app->session->param('__logged_in')) {
        $app->prerun_mode('login');
    }
}

I had a little bit of trouble passing the POST parameters to the login
run mode. This was solved by stashing them in the app's param during
cgiapp_init. I assume this is how we handle POST parameters. All the
docs I read didn't differentiate between GET and POST. I found out the
hard way that GET parameters were always available to the app, while
POST had to be handled with kid gloves. Any wisdom regarding POST and
"best practices" would be greatly appreciated. I simply do the
following:

sub cgiapp_init {
    my $app = shift;

    $app->param('query', $app->query);

    [...]
}

And then in the run modes that require POST variables:

sub login {
    my $app = shift;
    my $q = $app->param('query');

    [...]
}

As opposed to run modes that require GET variables:

sub list_user {
    my $app = shift;
    my $q = $app->query;

    [...]
}

The above works great for the the authentication aspect of my
application. Advice on the above would be great, but it's not the
primary reason I write now. Now I have trouble with a run mode called
edit_user. This simply displays a form pre-populated with user data if
the query string looks like: "?rm=edit_user&user_id=1", and displays a
blank from if the query string looks like: "?rm=edit_user". This is
simple enough.

The trouble comes when I try to submit that form. When submitted, the
parameters are passed and stored as they should be in
$app->param('query'), but the run mode that is fired is the default
run mode as specified in setup(). If I change POST to GET (and make no
other change) the app works as it should and edit_user is triggered
allowing the form to be posted back to itself. If I change the form
back to POST, we trigger the default run mode.

So there's where I am. I know there's something simple I'm
overlooking. I know that what I'm doing isn't unusual. I hope that I'm
not going to have to overload mode_param to do the run mode switching
for me. I can't for the life of me see how C::A would be written to
natively and nicely handle run modes in GET variables but not in POST
variables. Seems to me that I'm just not doing something right.

So now I humbly ask you for advice. Show me the error of my ways.

Michael De Soto


More information about the cgiapp mailing list