geoff 2003/08/11 13:34:23
Modified: lib/ModPerl Code.pm src/modules/perl mod_perl.c modperl_callback.c modperl_callback.h modperl_config.c modperl_filter.c modperl_types.h modperl_util.h t/hooks/TestHooks init.pm push_handlers.pm stacked_handlers.pm xs/tables/current/ModPerl FunctionTable.pm Added: t/hooks stacked_handlers2.t t/hooks/TestHooks stacked_handlers2.pm Log: alter stacked handler interface so that mod_perl follows Apache as closely as possible with respect to VOID/RUN_FIRST/RUN_ALL handler types. now, for phases where OK ends the Apache call list (RUN_FIRST handlers, such as the PerlTransHandler), mod_perl follows suit and leaves some handlers uncalled. Submitted by: geoff Reviewed by: stas Revision Changes Path 1.101 +21 -6 modperl-2.0/lib/ModPerl/Code.pm Index: Code.pm =================================================================== RCS file: /home/cvs/modperl-2.0/lib/ModPerl/Code.pm,v retrieving revision 1.100 retrieving revision 1.101 diff -u -r1.100 -r1.101 --- Code.pm 20 May 2003 01:31:49 -0000 1.100 +++ Code.pm 11 Aug 2003 20:34:22 -0000 1.101 @@ -37,27 +37,32 @@ Process => { ret => 'void', args => [{type => 'apr_pool_t', name => 'p'}, - {type => 'server_rec', name => 's'}], + {type => 'server_rec', name => 's'}, + {type => 'dummy', name => 'VOID'}], }, Files => { ret => 'int', args => [{type => 'apr_pool_t', name => 'pconf'}, {type => 'apr_pool_t', name => 'plog'}, {type => 'apr_pool_t', name => 'ptemp'}, - {type => 'server_rec', name => 's'}], + {type => 'server_rec', name => 's'}, + {type => 'dummy', name => 'RUN_ALL'}], }, PerSrv => { ret => 'int', - args => [{type => 'request_rec', name => 'r'}], + args => [{type => 'request_rec', name => 'r'}, + {type => 'dummy', name => 'RUN_ALL'}], }, Connection => { ret => 'int', - args => [{type => 'conn_rec', name => 'c'}], + args => [{type => 'conn_rec', name => 'c'}, + {type => 'dummy', name => 'RUN_FIRST'}], }, PreConnection => { ret => 'int', args => [{type => 'conn_rec', name => 'c'}, - {type => 'void', name => 'csd'}], + {type => 'void', name => 'csd'}, + {type => 'dummy', name => 'RUN_ALL'}], }, ); @@ -211,6 +216,12 @@ my($protostr, $pass) = canon_proto($prototype, $name); my $ix = $self->{handler_index}->{$class}->[$i]; + if ($callback =~ m/modperl_callback_per_(dir|srv)/) { + if ($ix =~ m/AUTH|TYPE|TRANS/) { + $pass =~ s/RUN_ALL/RUN_FIRST/; + } + } + print $h_fh "\n$protostr;\n"; print $c_fh <<EOF; @@ -557,8 +568,12 @@ sub canon_args { my $args = shift->{args}; - my @in = map { "$_->{type} *$_->{name}" } @$args; my @pass = map { $_->{name} } @$args; + my @in; + foreach my $href (@$args) { + push @in, "$href->{type} *$href->{name}" + unless $href->{type} eq 'dummy'; + } return wantarray ? ([EMAIL PROTECTED], [EMAIL PROTECTED]) : [EMAIL PROTECTED]; } 1.177 +2 -2 modperl-2.0/src/modules/perl/mod_perl.c Index: mod_perl.c =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/mod_perl.c,v retrieving revision 1.176 retrieving revision 1.177 diff -u -r1.176 -r1.177 --- mod_perl.c 11 Aug 2003 18:02:43 -0000 1.176 +++ mod_perl.c 11 Aug 2003 20:34:22 -0000 1.177 @@ -660,7 +660,7 @@ char *level = NULL; server_rec *s = (server_rec *)data; - modperl_callback_process(MP_CHILD_EXIT_HANDLER, server_pool, s); + modperl_callback_process(MP_CHILD_EXIT_HANDLER, server_pool, s, VOID); if ((level = getenv("PERL_DESTRUCT_LEVEL"))) { modperl_destruct_level = atoi(level); @@ -849,7 +849,7 @@ modperl_response_init(r); - retval = modperl_callback_per_dir(MP_RESPONSE_HANDLER, r); + retval = modperl_callback_per_dir(MP_RESPONSE_HANDLER, r, RUN_FIRST); if ((retval == DECLINED) && r->content_type) { r->handler = r->content_type; /* let http_core or whatever try */ 1.55 +71 -20 modperl-2.0/src/modules/perl/modperl_callback.c Index: modperl_callback.c =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_callback.c,v retrieving revision 1.54 retrieving revision 1.55 diff -u -r1.54 -r1.55 --- modperl_callback.c 17 Feb 2003 09:03:16 -0000 1.54 +++ modperl_callback.c 11 Aug 2003 20:34:22 -0000 1.55 @@ -81,7 +81,8 @@ request_rec *r, conn_rec *c, server_rec *s, apr_pool_t *pconf, apr_pool_t *plog, - apr_pool_t *ptemp) + apr_pool_t *ptemp, + modperl_hook_run_mode_e run_mode) { #ifdef USE_ITHREADS pTHX; @@ -188,17 +189,61 @@ MP_TRACE_h(MP_FUNC, "%s returned %d\n", handlers[i]->name, status); - if ((status != OK) && (status != DECLINED)) { - status = modperl_errsv(aTHX_ status, r, s); + /* follow Apache's lead and let OK terminate the phase for + * RUN_FIRST handlers. RUN_ALL handlers keep going on OK. + * VOID handler ignore all errors. + */ + + if (run_mode == RUN_ALL) { + /* the normal case: + * OK and DECLINED continue + * errors end the phase + */ + if ((status != OK) && (status != DECLINED)) { + + status = modperl_errsv(aTHX_ status, r, s); #ifdef MP_TRACE - if (i+1 != nelts) { - MP_TRACE_h(MP_FUNC, "there were %d uncalled handlers\n", - nelts-i-1); - } + if (i+1 != nelts) { + MP_TRACE_h(MP_FUNC, "error status %d leaves %d uncalled handlers\n", + status, desc, nelts-i-1); + } #endif - break; + break; + } } + else if (run_mode == RUN_FIRST) { + /* the exceptional case: + * OK and errors end the phase + * DECLINED continues + */ + if (status == OK) { +#ifdef MP_TRACE + if (i+1 != nelts) { + MP_TRACE_h(MP_FUNC, "OK ends the %s stack, leaving %d uncalled handlers\n", + desc, nelts-i-1); + } +#endif + break; + } + if (status != DECLINED) { + status = modperl_errsv(aTHX_ status, r, s); +#ifdef MP_TRACE + if (i+1 != nelts) { + MP_TRACE_h(MP_FUNC, "error status %d leaves %d uncalled handlers\n", + status, desc, nelts-i-1); + } +#endif + break; + } + } + else { + /* the rare case. + * VOID handlers completely ignore the return status + * Apache should handle whatever mod_perl returns, + * so there is no need to mess with the status + */ + } } SvREFCNT_dec((SV*)av_args); @@ -213,46 +258,52 @@ return status; } -int modperl_callback_per_dir(int idx, request_rec *r) +int modperl_callback_per_dir(int idx, request_rec *r, + modperl_hook_run_mode_e run_mode) { return modperl_callback_run_handlers(idx, MP_HANDLER_TYPE_PER_DIR, r, NULL, r->server, - NULL, NULL, NULL); + NULL, NULL, NULL, run_mode); } -int modperl_callback_per_srv(int idx, request_rec *r) +int modperl_callback_per_srv(int idx, request_rec *r, + modperl_hook_run_mode_e run_mode) { return modperl_callback_run_handlers(idx, MP_HANDLER_TYPE_PER_SRV, r, NULL, r->server, - NULL, NULL, NULL); + NULL, NULL, NULL, run_mode); } -int modperl_callback_connection(int idx, conn_rec *c) +int modperl_callback_connection(int idx, conn_rec *c, + modperl_hook_run_mode_e run_mode) { return modperl_callback_run_handlers(idx, MP_HANDLER_TYPE_CONNECTION, NULL, c, c->base_server, - NULL, NULL, NULL); + NULL, NULL, NULL, run_mode); } -int modperl_callback_pre_connection(int idx, conn_rec *c, void *csd) +int modperl_callback_pre_connection(int idx, conn_rec *c, void *csd, + modperl_hook_run_mode_e run_mode) { return modperl_callback_run_handlers(idx, MP_HANDLER_TYPE_PRE_CONNECTION, NULL, c, c->base_server, - NULL, NULL, NULL); + NULL, NULL, NULL, run_mode); } -void modperl_callback_process(int idx, apr_pool_t *p, server_rec *s) +void modperl_callback_process(int idx, apr_pool_t *p, server_rec *s, + modperl_hook_run_mode_e run_mode) { modperl_callback_run_handlers(idx, MP_HANDLER_TYPE_PROCESS, NULL, NULL, s, - p, NULL, NULL); + p, NULL, NULL, run_mode); } int modperl_callback_files(int idx, apr_pool_t *pconf, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *s) + apr_pool_t *ptemp, server_rec *s, + modperl_hook_run_mode_e run_mode) { return modperl_callback_run_handlers(idx, MP_HANDLER_TYPE_FILES, NULL, NULL, s, - pconf, plog, ptemp); + pconf, plog, ptemp, run_mode); } 1.23 +14 -7 modperl-2.0/src/modules/perl/modperl_callback.h Index: modperl_callback.h =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_callback.h,v retrieving revision 1.22 retrieving revision 1.23 diff -u -r1.22 -r1.23 --- modperl_callback.h 17 Feb 2003 09:03:16 -0000 1.22 +++ modperl_callback.h 11 Aug 2003 20:34:22 -0000 1.23 @@ -26,20 +26,27 @@ request_rec *r, conn_rec *c, server_rec *s, apr_pool_t *pconf, apr_pool_t *plog, - apr_pool_t *ptemp); + apr_pool_t *ptemp, + modperl_hook_run_mode_e run_mode); -int modperl_callback_per_dir(int idx, request_rec *r); +int modperl_callback_per_dir(int idx, request_rec *r, + modperl_hook_run_mode_e run_mode); -int modperl_callback_per_srv(int idx, request_rec *r); +int modperl_callback_per_srv(int idx, request_rec *r, + modperl_hook_run_mode_e run_mode); -int modperl_callback_connection(int idx, conn_rec *c); +int modperl_callback_connection(int idx, conn_rec *c, + modperl_hook_run_mode_e run_mode); -int modperl_callback_pre_connection(int idx, conn_rec *c, void *csd); +int modperl_callback_pre_connection(int idx, conn_rec *c, void *csd, + modperl_hook_run_mode_e run_mode); -void modperl_callback_process(int idx, apr_pool_t *p, server_rec *s); +void modperl_callback_process(int idx, apr_pool_t *p, server_rec *s, + modperl_hook_run_mode_e run_mode); int modperl_callback_files(int idx, apr_pool_t *pconf, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *s); + apr_pool_t *ptemp, server_rec *s, + modperl_hook_run_mode_e run_mode); #endif /* MODPERL_CALLBACK_H */ 1.64 +1 -1 modperl-2.0/src/modules/perl/modperl_config.c Index: modperl_config.c =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_config.c,v retrieving revision 1.63 retrieving revision 1.64 diff -u -r1.63 -r1.64 --- modperl_config.c 20 May 2003 06:02:47 -0000 1.63 +++ modperl_config.c 11 Aug 2003 20:34:22 -0000 1.64 @@ -290,7 +290,7 @@ rcfg->pnotes = Nullhv; } - retval = modperl_callback_per_dir(MP_CLEANUP_HANDLER, r); + retval = modperl_callback_per_dir(MP_CLEANUP_HANDLER, r, RUN_ALL); return retval; } 1.65 +2 -0 modperl-2.0/src/modules/perl/modperl_filter.c Index: modperl_filter.c =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_filter.c,v retrieving revision 1.64 retrieving revision 1.65 diff -u -r1.64 -r1.65 --- modperl_filter.c 13 May 2003 09:18:58 -0000 1.64 +++ modperl_filter.c 11 Aug 2003 20:34:22 -0000 1.65 @@ -341,6 +341,7 @@ modperl_filter_mg_set(aTHX_ AvARRAY(args)[0], modperl_filter_new(f, NULL, mode, 0, 0, 0)); + /* XXX filters are VOID handlers. should we ignore the status? */ if ((status = modperl_callback(aTHX_ handler, p, r, s, args)) != OK) { status = modperl_errsv(aTHX_ status, r, s); } @@ -384,6 +385,7 @@ av_push(args, newSViv(filter->readbytes)); } + /* XXX filters are VOID handlers. should we ignore the status? */ if ((status = modperl_callback(aTHX_ handler, p, r, s, args)) != OK) { status = modperl_errsv(aTHX_ status, r, s); } 1.68 +6 -0 modperl-2.0/src/modules/perl/modperl_types.h Index: modperl_types.h =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_types.h,v retrieving revision 1.67 retrieving revision 1.68 diff -u -r1.67 -r1.68 --- modperl_types.h 30 May 2003 12:55:14 -0000 1.67 +++ modperl_types.h 11 Aug 2003 20:34:22 -0000 1.68 @@ -248,4 +248,10 @@ const char *func_name; } modperl_module_cmd_data_t; +typedef enum { + RUN_ALL, + RUN_FIRST, + VOID +} modperl_hook_run_mode_e; + #endif /* MODPERL_TYPES_H */ 1.43 +1 -1 modperl-2.0/src/modules/perl/modperl_util.h Index: modperl_util.h =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_util.h,v retrieving revision 1.42 retrieving revision 1.43 diff -u -r1.42 -r1.43 --- modperl_util.h 14 Mar 2003 05:50:31 -0000 1.42 +++ modperl_util.h 11 Aug 2003 20:34:22 -0000 1.43 @@ -64,7 +64,7 @@ } /* turn off cgi header parsing. in case we are already inside - * modperl_callback_per_dir(MP_RESPONSE_HANDLER, r); + * modperl_callback_per_dir(MP_RESPONSE_HANDLER, r, RUN_FIRST); * but haven't sent any data yet, it's too late to change * MpReqPARSE_HEADERS, so change the wbucket's private flag directly */ 1.1 modperl-2.0/t/hooks/stacked_handlers2.t Index: stacked_handlers2.t =================================================================== use strict; use warnings FATAL => 'all'; use Apache::TestRequest; use Apache::Test; use Apache::TestUtil; my $module = "TestHooks::stacked_handlers2"; Apache::TestRequest::module($module); my $config = Apache::Test::config(); my $hostport = Apache::TestRequest::hostport($config); my $path = Apache::TestRequest::module2path($module); my $location = "http://$hostport/$path"; t_debug("connecting to $location"); plan tests => 1; my $expected = q!ran 2 PerlPostReadRequestHandler handlers ran 1 PerlTransHandler handlers ran 4 PerlHeaderParserHandler handlers ran 2 PerlAccessHandler handlers ran 2 PerlAuthenHandler handlers ran 2 PerlAuthzHandler handlers ran 1 PerlTypeHandler handlers ran 2 PerlFixupHandler handlers ran 2 PerlResponseHandler handlers ran 2 PerlOutputFilterHandler handlers!; chomp(my $received = GET_BODY_ASSERT $location); ok t_cmp($expected, $received, "stacked_handlers"); 1.5 +2 -2 modperl-2.0/t/hooks/TestHooks/init.pm Index: init.pm =================================================================== RCS file: /home/cvs/modperl-2.0/t/hooks/TestHooks/init.pm,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- init.pm 31 Mar 2003 01:50:52 -0000 1.4 +++ init.pm 11 Aug 2003 20:34:22 -0000 1.5 @@ -8,7 +8,7 @@ use APR::Table (); use Apache::RequestRec (); -use Apache::Const -compile => 'OK'; +use Apache::Const -compile => qw(OK DECLINED); sub first { my $r = shift; @@ -35,7 +35,7 @@ $r->notes->set(ok3 => $ok + 1); - Apache::OK; + Apache::DECLINED; } sub response { 1.6 +1 -1 modperl-2.0/t/hooks/TestHooks/push_handlers.pm Index: push_handlers.pm =================================================================== RCS file: /home/cvs/modperl-2.0/t/hooks/TestHooks/push_handlers.pm,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- push_handlers.pm 18 Apr 2003 06:18:57 -0000 1.5 +++ push_handlers.pm 11 Aug 2003 20:34:22 -0000 1.6 @@ -39,7 +39,7 @@ } sub end { return Apache::DONE } -sub say { shift->print(shift,"\n"); return Apache::OK } +sub say { shift->print(shift,"\n"); return Apache::DECLINED } sub conf { # this one is configured from httpd.conf 1.6 +2 -2 modperl-2.0/t/hooks/TestHooks/stacked_handlers.pm Index: stacked_handlers.pm =================================================================== RCS file: /home/cvs/modperl-2.0/t/hooks/TestHooks/stacked_handlers.pm,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- stacked_handlers.pm 18 Apr 2003 06:18:57 -0000 1.5 +++ stacked_handlers.pm 11 Aug 2003 20:34:22 -0000 1.6 @@ -28,7 +28,7 @@ $r->content_type('text/plain'); $r->print("one\n"); - return Apache::OK; + return Apache::DECLINED; } sub two { @@ -36,7 +36,7 @@ $r->print("two\n"); - return Apache::OK; + return Apache::DECLINED; } sub three { 1.1 modperl-2.0/t/hooks/TestHooks/stacked_handlers2.pm Index: stacked_handlers2.pm =================================================================== package TestHooks::stacked_handlers2; # this test exercises the execution of the stacked handlers # connection, translation, authen, authz, type, and response # phases should end for the first handler that returns OK use strict; use warnings FATAL => 'all'; use Apache::RequestRec (); use Apache::RequestIO (); use Apache::Filter (); use APR::Table; use Apache::Const -compile => qw(OK DECLINED AUTH_REQUIRED SERVER_ERROR); sub ok { callback(shift); return Apache::OK } sub declined { callback(shift); return Apache::DECLINED } sub auth_required { callback(shift); return Apache::AUTH_REQUIRED } sub server_error { callback(shift); return Apache::SERVER_ERROR } sub callback { my $obj = shift; my ($r, $callback); if ($obj->isa('Apache::Filter')) { $r = $obj->r; $callback = 'PerlOutputFilterHandler'; } else { $r = $obj } $callback ||= Apache::current_callback; my $count = $r->notes->get($callback) || 0; $r->notes->set($callback, ++$count); } sub handler { my $r = shift; $r->content_type('text/plain'); callback($r); foreach my $callback (qw(PerlPostReadRequestHandler PerlTransHandler PerlHeaderParserHandler PerlAccessHandler PerlAuthenHandler PerlAuthzHandler PerlTypeHandler PerlFixupHandler PerlResponseHandler)) { my $count = $r->notes->get($callback) || 0; $r->print("ran $count $callback handlers\n"); } return Apache::OK; } sub passthru { my $filter = shift; unless ($filter->ctx) { callback($filter); $filter->ctx({seen => 1}); } while ($filter->read(my $buffer, 1024)) { $filter->print($buffer); } # this should be ignored? Apache::OK; } sub filter { my $filter = shift; unless ($filter->ctx) { callback($filter); $filter->ctx({seen => 1}); } while ($filter->read(my $buffer, 1024)) { $filter->print($buffer); } if ($filter->seen_eos) { my $count = $filter->r->notes->get('PerlOutputFilterHandler') || 0; $filter->print("ran $count PerlOutputFilterHandler handlers\n"); } # this should be ignored? Apache::OK; } 1; __DATA__ # create a new virtual host so we can test (almost all) all the hooks <NoAutoConfig> <VirtualHost TestHooks::stacked_handlers2> PerlModule TestHooks::stacked_handlers2 # all 2 run PerlPostReadRequestHandler TestHooks::stacked_handlers2::ok TestHooks::stacked_handlers2::ok # 1 run, 1 left behind PerlTransHandler TestHooks::stacked_handlers2::ok TestHooks::stacked_handlers2::server_error <Location /TestHooks__stacked_handlers2> # all 4 run PerlHeaderParserHandler TestHooks::stacked_handlers2::ok TestHooks::stacked_handlers2::declined PerlHeaderParserHandler TestHooks::stacked_handlers2::declined TestHooks::stacked_handlers2::ok # all 2 run PerlAccessHandler TestHooks::stacked_handlers2::ok TestHooks::stacked_handlers2::ok # 2 run, 1 left behind PerlAuthenHandler TestHooks::stacked_handlers2::declined TestHooks::stacked_handlers2::ok PerlAuthenHandler TestHooks::stacked_handlers2::auth_required # 2 run, 1 left behind PerlAuthzHandler TestHooks::stacked_handlers2::declined TestHooks::stacked_handlers2::ok PerlAuthzHandler TestHooks::stacked_handlers2::auth_required # 1 run, 1 left behind PerlTypeHandler TestHooks::stacked_handlers2::ok TestHooks::stacked_handlers3::server_error # all 2 run PerlFixupHandler TestHooks::stacked_handlers2::ok TestHooks::stacked_handlers2::ok # 2 run, 2 left behind PerlResponseHandler TestHooks::stacked_handlers2::declined TestHooks::stacked_handlers2 PerlResponseHandler TestHooks::stacked_handlers2::ok TestHooks::stacked_handlers2::server_error SetHandler modperl AuthType Basic Require valid-user PerlOutputFilterHandler TestHooks::stacked_handlers2::passthru TestHooks::stacked_handlers2::filter </Location> </VirtualHost> </NoAutoConfig> 1.118 +28 -0 modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm Index: FunctionTable.pm =================================================================== RCS file: /home/cvs/modperl-2.0/xs/tables/current/ModPerl/FunctionTable.pm,v retrieving revision 1.117 retrieving revision 1.118 diff -u -r1.117 -r1.118 --- FunctionTable.pm 7 Jul 2003 03:06:14 -0000 1.117 +++ FunctionTable.pm 11 Aug 2003 20:34:22 -0000 1.118 @@ -150,6 +150,10 @@ { 'type' => 'conn_rec *', 'name' => 'c' + }, + { + 'type' => 'modperl_hook_run_mode_e', + 'name' => 'run_mode' } ] }, @@ -176,6 +180,10 @@ { 'type' => 'server_rec *', 'name' => 's' + }, + { + 'type' => 'modperl_hook_run_mode_e', + 'name' => 'run_mode' } ] }, @@ -190,6 +198,10 @@ { 'type' => 'request_rec *', 'name' => 'r' + }, + { + 'type' => 'modperl_hook_run_mode_e', + 'name' => 'run_mode' } ] }, @@ -204,6 +216,10 @@ { 'type' => 'request_rec *', 'name' => 'r' + }, + { + 'type' => 'modperl_hook_run_mode_e', + 'name' => 'run_mode' } ] }, @@ -222,6 +238,10 @@ { 'type' => 'void *', 'name' => 'csd' + }, + { + 'type' => 'modperl_hook_run_mode_e', + 'name' => 'run_mode' } ] }, @@ -240,6 +260,10 @@ { 'type' => 'server_rec *', 'name' => 's' + }, + { + 'type' => 'modperl_hook_run_mode_e', + 'name' => 'run_mode' } ] }, @@ -278,6 +302,10 @@ { 'type' => 'apr_pool_t *', 'name' => 'ptemp' + }, + { + 'type' => 'modperl_hook_run_mode_e', + 'name' => 'run_mode' } ] },