1

I have an apache server whose main purpose is to handle RPC requests. All such requests hit a url that begins with a fixed prefix (e.g., /rpc) I use a Location directive to set the handler for this URL (e.g., <Location /rpc>...</Location>).

I'd now like this server to also serve static files. I put an index.html file into its DocumentRoot but cannot get apache to serve it to me. Instead, I get 404 responses. The access log shows this:

127.0.0.1 - - [18/Aug/2010:11:41:52 -0400] "GET /index.html HTTP/1.1" 404 208

The error log shows this:

[...] [error] [client 127.0.0.1] File does not exist: /www/htdocs/index.html

This error message is a filthy lie. I can copy and paste that path and run ls /www/htdocs/index.html and see that the file does indeed exist.

Things I have tried so far:

  • Checked all permissions in full path to the file: all dirs are 755, all files are 644
  • Checked ownership: all dirs and files are owned by the same user that apache is running as
  • Set LogLevel debug (no new messages appeared in the logs)
  • Added a <Location /> block with a SetHandler default-handler directive
  • Added a <Location /index.html> block with a SetHandler default-handler directive
  • Moved both of these Location blocks above and below the <Location /rpc> block
  • Ran dtruss and did not see apache issue a single stat() call while processing the request

I'm running out of ideas. What else should I try?

(I'm using apache 2.2.12 on Mac OS X 10.5.8 and apache 2.2.3 on CentOS 5.4.)

John Siracusa
  • 738
  • 7
  • 12
  • I think this question turned out to be more appropriate for StackOverflow.com. If anyone powerful enough to move/migrate this question over to there agrees with me, please do so. – John Siracusa Aug 24 '10 at 04:06

1 Answers1

3

The answer turned out to hinge on a piece of information not present in my question—but the dtruss output should have been a big hint!

I have a PerlMapToStorageHandler Apache2::Const::OK directive in my apache configuration as per the suggestion in the mod_perl documentation. This is a host-wide setting and it prevents apache from calling ap_directory_walk() and stat()ing a bunch of files every time it gets a request. This is desirable when all of your URIs are "virtual" (i.e., don't correspond to real files on disk) but it also means that you can't serve any static files!

My solution was to create a custom PerlMapToStorageHandler routine that avoids the stat() calls for every file except the one I want to serve:

package MyMapToStorageHandler;

use strict;  
use Apache2::RequestRec();
use Apache2::Const -compile => qw(DECLINED OK M_TRACE);

sub handler {
    my $r = shift;

    # Fall through to the default handling for TRACE requests and requests
    # for the index.html file.
    if ($r->method_number == Apache2::Const::M_TRACE || $r->uri eq '/index.html') {
        return Apache2::Const::DECLINED;
    }

    # Skip ap_directory_walk stat() calls by just returning OK
    return Apache2::Const::OK;
}

1;

Then, in my httpd.conf file I replaced my existing PerlMapToStorageHandler Apache2::Const::OK directive with this:

PerlLoadModule MyMapToStorageHandler
...
PerlMapToStorageHandler MyMapToStorageHandler

That did the trick.

John Siracusa
  • 738
  • 7
  • 12