Персональный
сайт
Игоря
Сысоева


 
english
 
sysoev.ru
 
nginx
 поехали!    
 документация    
 поддержка    
 изменения    
 скачать    
 ссылки    
 
mod_accel
mod_realip
mod_deflate
программирование
всякая всячина
windows
freebsd
apache
pppd
unix
web
 
обо мне
для писем
для денег
 

Директивы модуля 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