У меня есть CGIшка, которую хочется запустить под FastCGI.
Она использует фреймвок, который обрабатывает html-шаблоны, выводит ошибки (die) в браузер, делает всяческие редиректы, отдаёт файлы, etc. — всё как обычно. Этот фреймвок, после формирования и вывода ответа на STDOUT, делает
Этот
Но под FastCGI
Следовательно, приходится оный exit перехватывать, и делать либо
It may not be used to go into any construct that requires initialization, such as a subroutine or a «foreach» loop. It also can't be used to go into a construct that is optimized away, or to get out of a block or subroutine given to «sort».
Похоже, единственная проблема с
Какие ещё могут быть грабли при использовании
Она использует фреймвок, который обрабатывает html-шаблоны, выводит ошибки (die) в браузер, делает всяческие редиректы, отдаёт файлы, etc. — всё как обычно. Этот фреймвок, после формирования и вывода ответа на STDOUT, делает
exit() — что тоже, в общем, не оригинально.Этот
exit() может быть вызван внутри eval(), а то и нескольких вложенных eval-ов — к примеру, если где-то, в глубине вычислений, CGIшка решает выдать юзеру редирект. Она при этом вызывает функцию фреймвока, он делает print "Location: ..." и exit().Но под FastCGI
exit() делать нельзя.Следовательно, приходится оный exit перехватывать, и делать либо
die() (точно так же, как это делает, например, mod_perl), либо goto. Проблема с die() заключается в том, что в случае если exit() был вызван внутри eval(), и после вызова eval юзер не передаст неизвестную ему ошибку выше снова вызвав die() (а гарантировать такое поведение после каждого eval в этой CGIшке я не могу — скорее могу гарантировать что обычно этого не происходит), то exit() приведёт просто к выходу из ближайшего eval(), на что CGIшка вызвавшая редирект явно не рассчитывала!Псевдо-код CGIшки
sub that_cgi_script {
...
eval { do_something() };
...
}
sub do_something {
# 1) may return if everything ok
# 2) may die on error, but such error non-important to
# calling code in above case and will be catched by
# eval and ignored
# 3) may redirect: print Location header and call exit()
}
Вариант exit через die
my $FCGI_EXIT = "FCGI NORMAL EXIT\n";
BEGIN { *CORE::GLOBAL::exit = sub { die $FCGI_EXIT }; }
while (CGI::Fast->new()) {
eval { that_cgi_script(); };
die $@ if $@ && $@ ne $FCGI_EXIT;
$CGI::Fast::Ext_Request->Finish();
}
Вариант exit через goto
BEGIN { *CORE::GLOBAL::exit = sub { goto EXIT }; }
while (CGI::Fast->new()) {
eval { that_cgi_script(); };
die $@ if $@;
EXIT:
$CGI::Fast::Ext_Request->Finish();
}
Что говорит perldoc -f goto
It may not be used to go into any construct that requires initialization, such as a subroutine or a «foreach» loop. It also can't be used to go into a construct that is optimized away, or to get out of a block or subroutine given to «sort».
Итак, где же грабли?
Похоже, единственная проблема с
goto, применимая к этой ситуации, это вызов exit() внутри sort. :) Я искренне верю, что эта CGIшка такого себе не позволяет. Аминь.Какие ещё могут быть грабли при использовании
goto в CORE::GLOBAL::exit? Меня настораживает то, что mod_perl goto не использует, хотя вроде-бы это более эффективное решение, чем die().