agn has asked for the wisdom of the Perl Monks concerning the following question:

Hi,
Am writing a basic webserver where I need to check if a the requested URI has a slash at the end or not and respond appropriately according to the condition.
my $DOCROOT = '/home/agn/htdocs'; if (-e $DOCROOT.$uri) { if (-f $DOCROOT.$uri) { if (-r $DOCROOT.$uri) { logme("200 HTTP OK\n"); $status_code = 200; } else { logme("403 Forbidden\n"); $status_code = 403; } } elsif (-d $DOCROOT.$uri) { if (-r $DOCROOT.$uri && -x $DOCROOT.$uri && ($DOCROOT.$uri !~ /\/$/)) { logme("301 Moved Permanently\n"); $status_code = 301; } elsif (-r $DOCROOT.$uri && -x $DOCROOT.$uri) { logme("200 HTTP OK\n"); $status_code = 200; } else { logme("403 Forbidden\n"); $status_code = 403; } } else { logme("406 Not Acceptable\n"); $status_code = 406; } } else { logme("404 Not Found\n"); $status_code = 404; } } return 0; }
The problem is that whether the $DOCROOT.$uri contains a / at the end or not, it always sets $status_code to 301.
$DOCROOT.$uri !~ m/\/$/
The above condition isn't being checked. Or if it is, I have a bug in the RE. Any ideas ?

Replies are listed 'Best First'.
Re: problem with if condition
by Corion (Patriarch) on Jul 13, 2009 at 09:30 UTC

    . binds less strong than ~= does. Using double quotes or parentheses makes your code work. Change

    && ($DOCROOT.$uri !~ /\/$/)) {
    to
    && ("$DOCROOT$uri" !~ /\/$/)) {

    or, even better, construct a variable $local_path from $DOCROOT and $uri. Note that your webserver will allow access to directories outside of $DOCROOT if $uri contains for example ../../.

      Doh! I feel stupid for not knowing that. I should really read about the precedence rules. Thanks a bunch. I've really been frustrated with this. Also I didn't catch this while running it through the debugger (perl -d).

      About .. traversals, I sanitise $uri before passing it to the above snippet.

      -agn
Re: problem with if condition
by Bloodnok (Vicar) on Jul 13, 2009 at 12:01 UTC
    TIMTOWTDI:

    If you're using Apache, IIRC, you can simplify things by doing the same thing (or similar) in /etc/httpd.conf.

    A user level that continues to overstate my experience :-))