Как сделать интерпретатор mod_perl привязанным к некоторым соглашениям?

Похоже, что mod_perl управляет только Интерпретаторы Perl для каждого VHOST, могу ли я каким-либо образом повлиять на то, какой клонированный интерпретатор mod_perl выбирает для обработки запроса? Я прочитал настраиваемые области действия и взглянул на «modperl_interp_select» в источнике, и я мог видеть, что если с запросом уже связан интерпретатор, он выбирается mod_perl.

else if (r) {
    if (is_subrequest && (scope == MP_INTERP_SCOPE_REQUEST)) {
[...]
    }
    else {
        p = r->pool;
        get_interp(p);
    }

Я хотел бы добавить какой-то обработчик, прежде чем mod_perl выберет интерпретатор для обработки запроса, а затем выберет интерпретатор, чтобы назначить его самому запросу, на основе различных критериев, включенных в запрос.

Но мне трудно понять, может ли вообще существовать такой обработчик или все, что касается запроса, уже обрабатывается выбранным интерпретатором mod_perl.

Вдобавок я вижу APR :: Pool-API, но, похоже, он не дает возможности установить некоторые пользовательские данные для текущего объекта пула, что mod_perl читает с помощью «get_interp».

Может ли кто-нибудь помочь мне в этом? Спасибо!

Немного о предыстории: у меня есть структура каталога в cgi-bin, подобная следующей:

cgi-bin
    software1
        customer1
            *.cgi
            *.pm
        customer2
            *.cgi
            *.pm
    software2
        customer1
            *.cgi
            *.pm
        customer2
            *.cgi
            *.pm

Каждый клиент использует частную копию программного обеспечения, и программное обеспечение использует себя, например программное обеспечение1 клиента1 может взаимодействовать с программным обеспечением2 клиента1, загружая некоторые специальные клиентские библиотеки программного обеспечения2 в свой собственный интерпретатор Perl. Чтобы усложнить ситуацию, программное обеспечение2 может даже иметь общие / общие части программного обеспечения1 с собственной частной установкой с использованием svn: external. Итак, у меня есть много одного и того же программного обеспечения с одинаковыми пакетами Perl в одном VHOST, и я не могу гарантировать, что все эти частные установки всегда имеют один и тот же уровень версии.

Это довольно путаница, но она, как известно, работает по правилам, установленным в том же интерпретаторе Perl.

Но теперь приходит mod_perl, клонирует интерпретаторы по мере необходимости и повторно использует их для запросов в любой подкаталог cgi-bin, который ему нравится, и в этом случае что-то сломается, потому что внезапно интерпретатор уже обработал программное обеспечение1 клиента1 и теперь должен обрабатывать программное обеспечение2 клиента2, которое использует общие пакеты программного обеспечения1, которые уже были загружены интерпретатором Perl раньше и используются из-за% INC вместо частных пакетов программного обеспечения2 и тому подобного ...

Да, есть разные способы справиться с этим, например, VHOST и субдомены, программное обеспечение или клиент или что-то еще, но я хотел бы проверить различные способы сохранения одного VHOST и текущей структуры каталогов, просто используя то, что предоставляет mod_perl или Apache httpd. И одним из способов было бы, если бы я мог сказать mod_perl всегда использовать один и тот же интерпретатор Perl для запросов к одному и тому же каталогу. Таким образом, mod_perl создаст пул интерпретаторов, и я буду отвечать за выбор каждого из них для каждого каталога.


person Thorsten Schöning    schedule 31.12.2014    source источник
comment
У вас есть конкретная причина использовать mod_perl? Используя Plack, вы получаете (AFAIK) гораздо больший контроль. (возможно, я упустил некоторые ключевые моменты) ...   -  person jm666    schedule 31.12.2014
comment
PLACK был бы совершенно новым для нас, как бы вы достигли моего запроса с помощью PLACK? Я бы хотел, чтобы он запускался в httpd, как это делает mod_perl, а не автономно, но мне нужно было бы контролировать, какой интерпретатор Perl будет использоваться для какого обслуживаемого каталога с простыми старыми сценариями CGI по разным причинам. Последнее важно, интерпретаторы нельзя повторно использовать для разных скриптов / каталогов.   -  person Thorsten Schöning    schedule 31.12.2014
comment
Возможно, я неправильно понял ваши требования, но я бы установил apache (или любой httpd, например nginx) как reverse proxy для определенных URL-адресов (каждый ваш сценарий CGI имеет свой собственный URL-адрес) и будет запускать для каждого сценария собственный сервер на основе Plack (на разных портах ) с помощью CGI :: Emulate :: PSGI или CGI :: PSGI. Короче говоря, каждый CGI-скрипт будет запускать один отдельный сервер Plack (perl) на своем собственном порту в полностью изолированной (но httpd-проксированной) среде.   -  person jm666    schedule 31.12.2014
comment
Это то направление, которое мне нужно, но слишком много накладных расходов на настройку. Поскольку мне нужен только каталог, а не только сценарий, я мог бы добиться того же, используя VHOST и поддомены. Дело в том, что я хотел бы избежать этого и вместо этого просто использовать специальную структуру каталогов для автоматического прикрепления интерпретаторов Perl к каталогам без какой-либо дополнительной настройки или настройки в каждом отдельном каталоге.   -  person Thorsten Schöning    schedule 31.12.2014
comment
Для эмуляции классического ../cgi-bin (например, множества скриптов в одном каталоге) вот Plack :: Приложение :: CGIBin. Но, конечно, если вы должны придерживаться apache (и не можете использовать собственный perl-plack / веб-сервер), например starman и / или другие, более простым (?) Способом будет патчить исходники mod_perl и поддерживать исправленную версию. ;) Это была не рекомендация (мало подробностей) - только комментарий. (Я фанат Plack) :)   -  person jm666    schedule 31.12.2014
comment
Я уже заметил CGIBin, но думаю, что это не решит мою первоначальную проблему, потому что мне все равно нужно будет влиять на то, какой интерпретатор Perl используется для какого каталога. Это снова означало бы настройку множества серверов CGIBin для каждого подкаталога cgi-bin, как вы описали ранее. Я добавил немного предыстории в свой вопрос, надеюсь, это проясняет его.   -  person Thorsten Schöning    schedule 31.12.2014


Ответы (2)


До сих пор я узнал, что повлиять на решение mod_perl о выбранном интерпретаторе нелегко. Если кто-то хочет, кажется, что нужно действительно исправить mod_perl на уровне C или предоставить собственный C-обработчик для httpd в качестве ловушки для запуска перед mod_perl. В конце концов, mod_perl - это всего лишь комбинация обработчиков для самого httpd, поэтому можно разместить один перед ним для выполнения некоторых особых действий. Другой вопрос, разумно ли это сделать, потому что придется иметь дело с некоторыми внутренностями mod_perl, такими как тот факт, что в настоящее время нет доступного интерпретатора, и, в конце концов, в моем случае мне понадобится где-то карта для интерпретаторов и связанный с ними каталог для обработки.

В конце концов, это не так просто, и я не хочу патчить mod_perl или начинать с низкого уровня C для обработчика / перехвата httpd.

В целях документации я хочу упомянуть два возможных обходных пути, которые пришли мне в голову:

Пул потоков Perl

Проблема с текущим подходом mod_perl в моем случае заключается в том, что он клонирует интерпретаторы Perl низкого уровня в C, и они запускаются потоками, предоставленными пулом httpd, каждый поток может запускать любой интерпретатор в любой момент времени, если он еще не используется другой поток. При таком подходе кажется невозможным получить доступ к интерпретаторам внутри самого Perl без использования какого-либо низкоуровневого XS, особенно невозможно управлять интерпретаторами и потоками с помощью Perl Threads API просто потому, что это не потоки Perl, это интерпретаторы Perl, выполняемые потоками httpd. В конце концов, оба ведут себя одинаково, потому что во время создания потоков Perl также клонируется текущий интерпретатор и создаются связанные потоки ОС и тому подобное. Но при использовании потоков Perl у вас больше влияния на общие данные и тому подобное.

Таким образом, обходной путь для моей текущей проблемы может заключаться в том, чтобы не позволить mod_perl и его интерпретаторам обрабатывать запрос, а вместо этого создать собственный пул потоков Perl-потоков напрямую при запуске в VHOST с использованием PerlModule или подобное. Этими потоками можно полностью управлять напрямую в Perl, можно создать несколько очередей для диспетчеризации работы в форме абсолютных путей к запрошенным CGI-приложениям и тому подобное. Помимо самого пула потоков потребуется обработчик, который будет вызываться вместо, например, ModPerl :: Registry для работы в качестве диспетчера: ему нужно будет решить на основе некоторых критериев, какой поток использовать, и поместить запрошенный путь в его очередь, а сам поток может в конечном итоге, например, просто создайте новые экземпляры ModPerl :: Registry для обработки данного файла. Конечно, кое-где понадобится клей ...

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

@ INC-Hook с изменениями исходного кода

Другой, и я полагаю, более простой подход - использовать @INC-хуки для Perl-кода require снова в комбинации с собственным обработчиком mod_perl, расширяющим ModPerl :: Registry. Ключевым моментом является то, что обработчик - это первое место, где читается запрошенный файл, и его источник может быть изменен перед его компиляцией. Каждый

use XY::Z;
XY::Z->new(...);

можно изменить на

use SomePrefix::XY::Z;
SomePrefix::XY::Z->new(...);

где SomePrefix - это просто полный путь к родительскому каталогу запрошенного файла, измененный на действительный Perl название пакета. ModPerl :: Registry уже делает нечто подобное при преобразовании запрошенный сценарий CGI автоматически в обработчик mod_perl, так что это работает в целом, и ModPerl :: Registry уже предоставляет некоторую логику для генерации имени пакета и тому подобного. Это изменение приводит к тому, что Perl больше не будет находить пакеты автоматически, просто потому, что они не существуют с новым именем в месте, известном Perl, где применяется ловушка @INC.

Хук отвечает за распознавание таких измененных пакетов просто из-за имени SomePrefix или префикса маркера перед SomePrefix или чего-то еще, и сопоставляет их с файлом в файловой системе, чтобы предоставить дескриптор запрошенного файла, который Perl может загрузить во время «требуется». Кроме того, ловушка будет обеспечивать обратный вызов, который вызывается Perl для каждой строки прочитанного файла и будет функционировать как фильтр исходного кода, снова изменяя каждый оператор «package», «use» или «require» так, чтобы SomePrefix был перед . Это снова приведет к тому, что ловушка будет отвечать за предоставление дескрипторов файлов для этих пакетов и т. Д.

Ключевым моментом здесь является изменение исходного кода один раз во время выполнения: вместо «XY / Z.pm», который обычно требуется Perl, он будет доступен n раз в моей структуре каталогов и будет сохранен как «XY / Z.pm» в % INC позволяет Perl требовать "SomePrefix / XY / Z.pm", который будет храниться в% INC и уникален для каждого интерпретатора Perl, используемого mod_perl, поскольку SomePrefix отражает уникальный установочный каталог запрошенного файла. Perl больше не может думать, что он уже загрузил XY :: Z только потому, что раньше он обрабатывал запрос из другого каталога.

Конечно, это работает только для простого "использования ...;" операторы, такие как "eval (" require $ package ");" немного усложнит ситуацию.

Комментарии приветствуются ... :-)

person Thorsten Schöning    schedule 08.01.2015

PerlOptions - это переменная с областью действия DIR, не ограниченная VirtualHosts, поэтому новые пулы интерпретаторов могут быть созданы для любого местоположения. Эти директивы могут быть даже помещены в файлы .htaccess для простоты настройки, но что-то вроде этого в вашем httpd.conf должно дать вам желаемый эффект:

<Location /cgi-bin/software1/customer1>
   PerlOptions +Parent
</Location>
<Location /cgi-bin/software1/customer2>
   PerlOptions +Parent
</Location>
<Location /cgi-bin/software2/customer1>
   PerlOptions +Parent
</Location>
<Location /cgi-bin/software2/customer2>
   PerlOptions +Parent
</Location>
person Ben Grimm    schedule 31.12.2014
comment
Вы пробовали это? Я сам могу читать документы, но вы действительно пробовали? Это не работает, ошибки mod_perl говорят, что Parent не является параметром per dir, и я нашел других с той же проблемой: Invalid per-directory PerlOption: Parent Я нашел соответствующий исходный код в mod_perl для этой ошибки. Я предполагаю, что это потому, что интерпретаторы привязаны к пулам APR, и они, похоже, доступны только для объектов запроса, объектов конфигурации сервера и т. Д. Наличие такого оператора в .htaccess было первым, что я пробовал много лет назад ... - person Thorsten Schöning; 01.01.2015
comment
Верно, это должно работать согласно документации, но @ithread_opts отсутствует в каталоге lib / ModPerl / Code.pm +136. Итак, тест PerlOption не прошел. Это может быть таким же простым, как добавление параметров ithread в массив Dir и восстановление mod_perl. - person Ben Grimm; 01.01.2015
comment
Спасибо за подсказку, я сам не смог найти этот код и поэтому не понял, где установлена ​​валидность Parent. COde.pm используется только во время сборки для генерации собственного кода для двоичного файла mod_perl, который фактически выполняет проверки? Или вы знаете какой-либо способ повлиять на действительность ithread_opts после сборки? - person Thorsten Schöning; 01.01.2015
comment
Он используется только для этой цели во время процесса сборки - изменение установленного Code.pm не имеет никакого эффекта. Но мне определенно было бы любопытно, работает ли исправление этого файла, поскольку в mod_perl, по-видимому, отсутствовала эта задокументированная функция с момента его появления: svn.apache.org/viewvc?view=revision&revision=68023 Хотя меня не удивило бы, если бы это было намеренно опущено. - person Ben Grimm; 01.01.2015
comment
Я надеюсь, что смогу попробовать завтра, но даже если они намеренно пропустили это, им следовало тем временем обновить документацию. Но и по этому поводу в списках рассылки их пользователей нет полезного ответа. - person Thorsten Schöning; 02.01.2015
comment
Изменение + Parent на просто разрешенную конфигурацию dir не работает, modperl_init_vhost - единственная функция, распознающая + Parent и запускающая новый интерпретатор Perl с помощью modperl_startup. Это также может понадобиться для каждого каталога где-то, и другие утверждения вокруг + Parent также специфичны для vhost. Документация о + Parent просто неверна, она не может легко работать для каждого каталога ... - person Thorsten Schöning; 05.01.2015