nginx

Модуль ngx_http_perl_module


english
русский

简体中文
עברית
日本語
türkçe

новости [en]
об nginx
скачать
безопасность [en]
pgp ключи [en]
документация
faq
ссылки [en]
книги [en]
поддержка
пожертвования [en]

trac
wiki
twitter
nginx.com
Известные проблемы
Пример конфигурации
Директивы
     perl
     perl_modules
     perl_require
     perl_set
Вызов Perl из SSI
Методы объекта запроса $r

Модуль ngx_http_perl_module позволяет писать обработчики location и переменных на Perl, а также вставлять вызовы Perl в SSI.

По умолчанию этот модуль не собирается, его сборку необходимо разрешить с помощью конфигурационного параметра --with-http_perl_module.

Для сборки этого модуля необходим Perl версии 5.6.1 и выше. Компилятор C должен быть совместим с тем, которым был собран Perl.

Известные проблемы

Модуль экспериментальный, поэтому возможно всё.

Для того, чтобы во время переконфигурации Perl перекомпилировал изменённые модули, его нужно собрать с параметрами -Dusemultiplicity=yes или -Dusethreads=yes. Кроме того, чтобы во время работы Perl меньше терял память, его нужно собрать с параметром -Dusemymalloc=no. Узнать значения этих параметров у уже собранного Perl можно так (в примере приведены желаемые значения параметров):

$ perl -V:usemultiplicity -V:usemymalloc
usemultiplicity='define';
usemymalloc='n';

Необходимо учитывать, что после пересборки Perl с новыми параметрами -Dusemultiplicity=yes или -Dusethreads=yes придётся также пересобрать и все бинарные модули Perl — они просто перестанут работать с новым Perl.

Возможно, основной процесс, а вслед за ним и рабочие процессы, будут увеличиваться в размерах при каждой переконфигурации. Когда основной процесс вырастет до неприемлемых размеров, можно воспользоваться процедурой обновления сервера на лету, не меняя при этом сам исполняемый файл.

Если модуль Perl выполняет длительную операцию, например, определяет адрес по имени, соединяется с другим сервером, делает запрос к базе данных, то на это время все остальные запросы, обслуживаемые данным рабочим процессом, не будут обрабатываться. Поэтому рекомендуется ограничиться операциями, время исполнения которых короткое и предсказуемое, например, обращение к локальной файловой системе.

Нижеописанные проблемы относятся только к версиям nginx до 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__

Директивы

синтаксис: perl модуль::функция|'sub { ... }';
умолчание:
контекст: location, limit_except

Устанавливает обработчик Perl для данного location.

синтаксис: perl_modules путь;
умолчание:
контекст: http

Задаёт дополнительный путь для модулей Perl.

синтаксис: perl_require модуль;
умолчание:
контекст: http

Задаёт имя модуля, который будет подгружаться при каждой переконфигурации. Директив perl_require может быть несколько.

синтаксис: perl_set $переменная модуль::функция|'sub { ... }';
умолчание:
контекст: http

Устанавливает обработчик Perl для указанной переменной.

Вызов Perl из SSI

Формат команды SSI с вызовом Perl следующий:

<!--# 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.
На данный момент перенаправления в именованные location’ы не поддерживаются.
$r->log_error(код_ошибки, сообщение)
записывает указанное сообщение в error_log. Если код_ошибки ненулевой, то к сообщению будет добавлен код ошибки и её описание.
$r->print(текст, ...)
метод передаёт клиенту данные.
$r->request_body
возвращает тело запроса клиента при условии, что тело не записано во временный файл. Для того, чтобы тело запроса клиента гарантированно находилось в памяти, нужно ограничить его размер с помощью client_max_body_size и задать достаточной размер для буфера client_body_buffer_size.
$r->request_body_file
возвращает имя файла, в котором хранится тело запроса клиента. По завершению обработки файл необходимо удалить. Для того, чтобы тело запроса клиента всегда записывалось в файл, следует включить client_body_in_file_only.
$r->request_method
возвращает HTTP-метод запроса клиента.
$r->remote_addr
возвращает IP-адрес клиента.
$r->flush
немедленно передаёт данные клиенту.
$r->sendfile(имя[, смещение[, длина]])
передаёт клиенту содержимое указанного файла. Необязательные параметры задают начальное смещение и длину передаваемых данных. Непосредственно передача данных происходит уже после завершения обработчика Perl.
$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(имя[, значение])
возвращает или устанавливает значение указанной переменной. Переменные локальны для каждого запроса.