stas 2003/01/13 22:42:44 Modified: src/modules/perl modperl_callback.c . Changes Added: t/error push_handlers.t t/response/TestError push_handlers.pm Log: prevent a segfault when push_handlers are used to push a handler into the currently phase and switching the handler (perl-script/modperl) + tests Revision Changes Path 1.52 +8 -4 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.51 retrieving revision 1.52 diff -u -r1.51 -r1.52 --- modperl_callback.c 1 Jan 2003 03:45:54 -0000 1.51 +++ modperl_callback.c 14 Jan 2003 06:42:43 -0000 1.52 @@ -93,7 +93,7 @@ modperl_handler_t **handlers; apr_pool_t *p = NULL; MpAV *av, **avp; - int i, status = OK; + int i, nelts, status = OK; const char *desc = NULL; AV *av_args = Nullav; @@ -173,11 +173,15 @@ }; /* XXX: deal with {push,set}_handler of the phase we're currently in */ - MP_TRACE_h(MP_FUNC, "running %d %s handlers\n", - av->nelts, desc); + /* for now avoid the segfault by not letting av->nelts grow if + * somebody push_handlers to the phase we are currently in, but + * different handler e.g. jumping from 'modperl' to 'perl-script', + * before calling push_handler */ + nelts = av->nelts; + MP_TRACE_h(MP_FUNC, "running %d %s handlers\n", nelts, desc); handlers = (modperl_handler_t **)av->elts; - for (i=0; i<av->nelts; i++) { + for (i=0; i<nelts; i++) { if ((status = modperl_callback(aTHX_ handlers[i], p, r, s, av_args)) != OK) { status = modperl_errsv(aTHX_ status, r, s); } 1.100 +4 -0 modperl-2.0/Changes Index: Changes =================================================================== RCS file: /home/cvs/modperl-2.0/Changes,v retrieving revision 1.99 retrieving revision 1.100 diff -u -r1.99 -r1.100 --- Changes 12 Jan 2003 04:05:48 -0000 1.99 +++ Changes 14 Jan 2003 06:42:44 -0000 1.100 @@ -10,6 +10,10 @@ =item 1.99_09-dev +prevent a segfault when push_handlers are used to push a handler into +the currently phase and switching the handler (perl-script/modperl) +[Stas] + Add $filter->seen_eos to the streaming filter api to know when eos has been seen, so special signatures can be passed and any data stored in the context flushed + tests. [Stas] 1.1 modperl-2.0/t/error/push_handlers.t Index: push_handlers.t =================================================================== use strict; use warnings FATAL => 'all'; use Apache::Test; use Apache::TestUtil; use Apache::TestRequest; plan tests => 1; my $location = "/TestError::push_handlers"; my $expected = "ok"; my $received = GET_BODY $location; ok t_cmp($expected, $received); 1.1 modperl-2.0/t/response/TestError/push_handlers.pm Index: push_handlers.pm =================================================================== package TestError::push_handlers; # This test verifies that we don't segfault when push_handlers are # used incorrectly. Here the handler() is running under # SetHandler modperl # and it modifies its handler to be 'perl-script', plus pushes another # handler to run. The result is that the first time handler() is run # under the 'modperl' handler it returns declined, therefore Apache # runs the registered 'perl-script' handler (which handler() has # pushed in plus itself. So the handler() is executed again, followed # by real_response(). Notice that it pushes yet another real_response # callback onto the list of handlers. # # suprisingly the response eventually works, but this is a wrong way # to accomplish that thing. And one of the earlier stages should be # used to push handlers. # # Don't modify the handler (modperl|perl-script) during the response # handler run-time, because if OK is not returned, the handler will be # executed again. use strict; use warnings;# FATAL => 'all'; use Apache::RequestRec (); use Apache::RequestIO (); use Apache::RequestUtil (); use Apache::Const -compile => qw(OK DECLINED); sub handler { my $r = shift; #warn "handler called\n"; $r->handler("perl-script"); $r->push_handlers(PerlResponseHandler => \&real_response); return Apache::DECLINED; } sub real_response { my $r = shift; #warn "real_response called\n"; $r->content_type('text/plain'); $r->print('ok'); return Apache::OK; } 1; __END__