The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package TestHooks::hookrun;

# this test runs all Apache phases from within the very first http
# phase

# XXX: may be improve the test to do a full-blown test, where each
# phase does something useful.

# see also TestProtocol::pseudo_http

use strict;
use warnings FATAL => 'all';

use Apache2::RequestRec ();
use Apache2::RequestUtil ();
use Apache2::HookRun ();
use APR::Table ();
use ModPerl::Util ();

use Apache::Test;
use Apache::TestUtil;
use Apache::TestTrace;

use Apache2::Const -compile => qw(OK DECLINED DONE SERVER_ERROR);

my $path = '/' . Apache::TestRequest::module2path(__PACKAGE__);

my @phases = qw(
    PerlPostReadRequestHandler
    PerlTransHandler
    PerlMapToStorageHandler
    PerlHeaderParserHandler
    PerlAccessHandler
    PerlAuthenHandler
    PerlAuthzHandler
    PerlTypeHandler
    PerlFixupHandler
    PerlResponseHandler
    PerlLogHandler
);

sub post_read_request {
    my $r = shift;
    my $rc;

    $r->push_handlers(PerlTransHandler        => \&any);
    $r->push_handlers(PerlMapToStorageHandler => \&any);
    $r->push_handlers(PerlHeaderParserHandler => \&any);
    $r->push_handlers(PerlAccessHandler       => \&any);
    $r->push_handlers(PerlAuthenHandler       => \&any);
    $r->push_handlers(PerlAuthzHandler        => \&any);
    $r->push_handlers(PerlTypeHandler         => \&any);
    $r->push_handlers(PerlFixupHandler        => \&any);
    $r->push_handlers(PerlLogHandler          => \&any);

    any($r); # indicate that the post_read_request phase was run

    # for the full Apache logic for running phases starting from
    # post_read_request and ending with fixup see
    # ap_process_request_internal in httpd-2.0/server/request.c

    $rc = $r->run_translate_name;
    return $rc unless $rc == Apache2::Const::OK or $rc == Apache2::Const::DECLINED;

    $rc = $r->run_map_to_storage;
    return $rc unless $rc == Apache2::Const::OK or $rc == Apache2::Const::DECLINED;

    # this must be run all a big havoc will happen in the following
    # phases
    $r->location_merge($path);

    $rc = $r->run_header_parser;
    return $rc unless $rc == Apache2::Const::OK or $rc == Apache2::Const::DECLINED;

    my $args = $r->args || '';
    if ($args eq 'die') {
        $r->die(Apache2::Const::SERVER_ERROR);
        return Apache2::Const::DONE;
    }

    $rc = $r->run_access_checker;
    return $rc unless $rc == Apache2::Const::OK or $rc == Apache2::Const::DECLINED;

    $rc = $r->run_auth_checker;
    return $rc unless $rc == Apache2::Const::OK or $rc == Apache2::Const::DECLINED;

    $rc = $r->run_check_user_id;
    return $rc unless $rc == Apache2::Const::OK or $rc == Apache2::Const::DECLINED;

    $rc = $r->run_type_checker;
    return $rc unless $rc == Apache2::Const::OK or $rc == Apache2::Const::DECLINED;

    $rc = $r->run_fixups;
    return $rc unless $rc == Apache2::Const::OK or $rc == Apache2::Const::DECLINED;

    # $r->run_handler is called internally by $r->invoke_handler,
    # invoke_handler sets all kind of filters, and does a few other
    # things but it's possible to call $r->run_handler, bypassing
    # invoke_handler
    $rc = $r->invoke_handler;
    return $rc unless $rc == Apache2::Const::OK or $rc == Apache2::Const::DECLINED;

    $rc = $r->run_log_transaction;
    return $rc unless $rc == Apache2::Const::OK or $rc == Apache2::Const::DECLINED;

    return Apache2::Const::DONE;

    # Apache runs ap_finalize_request_protocol on return of this
    # handler
}

sub any {
    my $r = shift;

    my $callback = ModPerl::Util::current_callback();

    debug "running $callback\n";
    $r->notes->set($callback => 1);

    # unset the callback that was already run
    $r->set_handlers($callback => []);

    Apache2::Const::OK;
}

sub response {
    my $r = shift;

    my @pre_response = (@phases)[0..($#phases-2)];
    plan tests => scalar(@pre_response);

    for my $phase (@pre_response) {
        my $note = $r->notes->get($phase);
        $r->print("$phase:$note\n");
    }

    Apache2::Const::OK;
}

1;
__END__
<NoAutoConfig>
<VirtualHost TestHooks::hookrun>
    PerlModule                 TestHooks::hookrun
    PerlPostReadRequestHandler TestHooks::hookrun::post_read_request
    <Location /TestHooks__hookrun>
        SetHandler modperl
        PerlResponseHandler    TestHooks::hookrun::response

        AuthName modperl
        AuthType none
        Require valid-user
    </Location>
</VirtualHost>
</NoAutoConfig>