Директивы модуля ngx_http_perl_module 19.12.2007
Модуль ngx_http_perl_module позволяет работать со встроенным в nginx perl'ом:
делать обработчики location и переменной и вставлять вызовы perl'а в SSI.
По умолчанию модуль не собирается, нужно разрешить его сборку
при конфигурировании параметром --with-http_perl_module.
Для сборки необходим perl версии 5.6.1 и выше, и компилятор C, совместимый
с тем, которым был собран perl.
СодержаниеИзвестные проблемы Пример конфигурации Директивы- perl
- perl_modules
- perl_require
- perl_set
Вызов perl'а из SSI Методы объекта запроса $r
Известные проблемы
Модуль экспериментальный, поэтому возможно всё.
Для того, чтобы во время переконфигурации perl перекомпилировал
изменённые модули, его нужно собрать с параметрами -Dusemultiplicity=yes
или -Dusethreads=yes.
Кроме того, чтобы во время работы perl меньше терял память, его нужно собрать
с параметром -Dusemymalloc=no.
Узнать значения этих параметров у уже собранного
perl'а можно так (в примерах приведены желаемые значения параметров):
$perl -V:usemultiplicity
usemultiplicity='define';
$perl -V:usemymalloc
usemymalloc='n';
Необходимо учитывать, что после пересборки perl'а с новыми параметрами
-Dusemultiplicity=yes или -Dusethreads=yes
придётся также переустановить и все бинарные perl'овые модули они
просто перестанут работать с новым perl'ом.
Возможно, основной процесс, а вслед за ним и рабочие процессы,
будет увеличиваться в размерах при каждой переконфигурации.
Когда основной процесс вырастет до неприемлемых размеров, можно
воспользоваться процедурой
обновления сервера на лету,
не меняя при этом сам исполняемый файл.
Если perl'овый модуль выполняет длительную операцию, например, определяет
адрес по имени, соединяется с другим сервером, делает запрос к базе данных,
то на это время все остальные запросы данного рабочего процесса не будут
обрабатываться. Поэтому рекомендуется ограничиться операциями,
время исполнения которых короткое и предсказуемое, например, обращение
к локальной файловой системе.
Нижеописанные проблемы отностятся только к версиям nignx'а до 0.6.22.
Данные, возвращаемые методами объекта запроса $r,
имеют только текстовое значение, причём само значение хранится
в памяти, выделяемой не perl'ом, а nginx'ом из собственных пулов.
Это позволяет уменьшить число операций копирования в большинстве случаев,
однако в некоторых ситуациях это приводит к ошибке,
например, при попытке использования таких значений в численном контексте
рабочий процесс выходит с ошибкой (FreeBSD):
nginx in realloc(): warning: pointer to wrong page
Out of memory!
Callback called exit.
или (Linux):
*** glibc detected *** realloc(): invalid pointer: ... ***
Out of memory!
Callback called exit.
Обход такой ситуации простой нужно присвоить значение метода
переменной, например, такой код
my $i = $r->variable('counter') + 1;
нужно заменить на
my $i = $r->variable('counter');
$i++;
Так как строки внутри nginx'а в большинстве случаев хранятся без
завершающего нуля, то они в таком же виде возвращаются методами
объекта запроса $r (исключения составляют методы $r->filename
и $r->request_body_file). Поэтому такие значения нельзя использовать
в качестве имени файла и тому подобном.
Обход такой же, как и предыдущей ситуации присвоение значения
переменной (при этом происходит копирование данных и добавление необходимого
нуля) или же использование в выражении, например:
open FILE, '/path/' . $r->variable('name');
Пример конфигурации
http {
perl_modules perl/lib;
perl_require hello.pm;
perl_set $msie6 '
sub {
my $r = shift;
my $ua = $r->header_in("User-Agent");
return "" if $ua =~ /Opera/;
return "1" if $ua =~ / MSIE [6-9]\.\d+/;
return "";
}
';
server {
location / {
perl hello::handler;
}
}
модуль perl/lib/hello.pm:
package hello;
use nginx;
sub handler {
my $r = shift;
$r->send_http_header("text/html");
return OK if $r->header_only;
$r->print("hello!\n<br/>");
if (-f $r->filename or -d _) {
$r->print($r->uri, " exists!\n");
}
return OK;
}
1;
__END__
Директивы syntax: perl модуль::функция|'sub { ... }' default: нет context: location, limit_except
Директива устанавливает обработчик для данного location.
syntax: perl_modules путь default: нет context: http
Директива задаёт дополнительный путь для perl'овых модулей.
syntax: perl_require модуль default: нет context: http
Директива задаёт имя модуля, который будет подгружаться при каждой
переконфигурации. Директив может быть несколько.
syntax: perl_set $переменная модуль::функция|'sub { ... }' default: нет context: http
Директива устанавливает обработчик переменной.
Вызов perl'а из SSI
Формат команды следующий
<!--# perl sub="модуль::функция" arg="параметр1" arg="параметр2" ...
-->
Методы объекта запроса $r- $r->args метод возвращает аргументы запроса.
- $r->filename метод возвращает имя файла,
соответствующее URI запроса.
- $r->has_request_body(обработчик) метод возвращает 0,
если в запросе нет тела. Если же тело запроса есть, то устанавливается
указанный обработчик и возвращается 1.
По окончании приёма тела nginx вызовет установленный обработчик.
Обратите внимание, что нужно передавать ссылку на функцию обработчика.
Пример использования:
package hello;
use nginx;
sub handler {
my $r = shift;
if ($r->request_method ne "POST") {
return DECLINED;
}
if ($r->has_request_body(\&post)) {
return OK;
}
return HTTP_BAD_REQUEST;
}
sub post {
my $r = shift;
$r->send_http_header;
$r->print("request_body: \"", $r->request_body, "\"<br/>");
$r->print("request_body_file: \"", $r->request_body_file, "\"<br/>\n");
return OK;
}
1;
__END__
- $r->allow_ranges метод разрешает использовать
byte ranges при передаче ответа.
- $r->discard_request_body метод указывает nginx'у
игнорировать тело запроса.
- $r->header_in(строка) метод возвращает значение
заданной строки в заголовке запроса клиента.
- $r->header_only метод определяет, нужно ли передавать
клиенту только заголовок ответа или весь ответ.
- $r->header_out(строка, значение) метод устанавливает
значение для заданной строки в заголовке ответа.
- $r->internal_redirect(uri) метод делает внутренний
редирект на указанный uri.
Редирект происходит уже после завершения perl'ового обработчика.
- $r->print(текст, ...) метод передаёт клиенту данные.
- $r->request_body метод возвращает тело запроса
клиента при условии, что тело не записано во временный файл.
Для того, чтобы тело запроса клиента гарантировано находилось в памяти,
нужно ограничить его размер с помощью client_max_body_size
и задать достаточной размер для буфера
client_body_buffer_size.
- $r->request_body_file метод возвращает имя файла,
в котором хранится тело запроса клиента.
По завершению работы файл необходимо удалить.
Для того, чтобы тело запроса клиента всегда записывалось в файл, нужно
указать client_body_in_file_only on.
- $r->request_method метод возвращает HTTP метод
запроса клиента.
- $r->remote_addr метод возвращает IP-адрес клиента.
- $r->flush метод немедленно передаёт данные клиенту.
- $r->sendfile(имя [, смещение [, длина]]) метод
передаёт клиенту содержимое указанного файла. Необязательные параметры
указывают начальное смещение и длину передаваемых данных.
Собственно передача данных происходит уже после завершения
perl'ового обработчика.
Необходимо учитывать, что при использовании
этого метода в подзапросе и директиве sendfile on
содержимое файла не будет проходить через
gzip,
SSI и
charset
фильтры.
- $r->send_http_header(тип) метод
передаёт клиенту заголовок ответа.
Необязательный параметр "тип" устанавливает значение строки "Content-Type"
в заголовке ответа.
Пустая строка в качестве типа запрещает строку "Content-Type".
- $r->status(код) метод устанавливает код ответа.
- $r->sleep(миллисекунды, обработчик) метод устанавливает
указанный обработчик и останавливает обработку запроса на заданное время.
nginx в это время продолжает обрабатывать другие запросы.
По истечении указанного времени nginx вызовет установленный обработчик.
Обратите внимание, что нужно передавать ссылку на функцию обработчика.
Для передачи данных между обработчиками следует использовать $r->variable().
Пример использования:
package hello;
use nginx;
sub handler {
my $r = shift;
$r->discard_request_body;
$r->variable("var", "OK");
$r->sleep(1000, \&next);
return OK;
}
sub next {
my $r = shift;
$r->send_http_header;
$r->print($r->variable("var"));
return OK;
}
1;
__END__
- $r->unescape(текст) метод декодирует текст,
заданный в виде %XX.
- $r->uri метод возвращает URI запроса.
- $r->variable(имя [, значение]) метод возвращает
или устанавливает значение указанной переменной.
Переменные локальны для каждого запроса.
(C) Игорь Сысоев http://sysoev.ru |