У меня есть 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()
.