Миграция на apache2

22 Mar 2012


...

Источники

1.0 vs 2.0

http://perl.apache.org/docs/2.0/user/porting/compat.html – A Reference to mod_perl 1.0 to mod_perl 2.0 Migration, подробный список “что на что менять”

http://perl.apache.org/docs/2.0/user/porting/porting.html – Общее обсуждение mod_perl 1.0 и mod_perl 2.0

1.0

http://perl.apache.org/docs/1.0/guide/config.html – mod_perl Configuration (1.0)

2.0

http://perl.apache.org/docs/2.0/user/index.html – документация по mod_perl2

http://perl.apache.org/docs/2.0/user/config/config.html – mod_perl 2.0 Server Configuration

http://perl.apache.org/docs/2.0/user/handlers/intro.html – все про mod_perl’овые хендлеры (2.0)

http://perl.apache.org/docs/2.0/user/coding/coding.html – Writing mod_perl Handlers and Scripts

Разное

PerlRequire directive not allowed in a <Location> block

$r->notes
… in mod_perl 2.0, $r->notes() returns an APR::Table object, which can be used as a tied hash or calling its get() / set() / add() / unset() methods.
http://perl.apache.org/docs/2.0/user/porting/compat.html

$r->get_server_port

UseCanonicalName Off, иначе все плохо
Под 1.3 работало и с UseCanonicalName On

http://web.archiveorange.com/archive/v/wudV5MzM5e5mzvzkmFOY – пишут интересное:

“It seems that get_server_port gives the wrong answer when responding to an HTTP/1.0 request. That is, it always says port ‘80’ for HTTP/1.0”

“the behavior of ap_get_server_port looks to be very different between apache 1.3 and 2.0, so I suspect the difference is really there.”

$ENV{REMOTE_ADDR}

Наблюдаемое поведение: внутри PerlResponseHandler ModPerl::Registry – ok, переменная $ENV{REMOTE_ADDR} есть. А в модуле, установленном как PerlFixupHandler для того же локейшена – не ok, переменная пуста.

Решение:

  • Пользоваться $r->connection->remote_ip – там правильное значение
  • В начале хендлера сделать $r->subprocess_env; – тогда появлятся %ENV, в т.ч. и $ENV{REMOTE_ADDR}

Цитата из документации по $r->subprocess_env (http://perl.apache.org/docs/2.0/api/Apache2/RequestRec.html):

When called in VOID context with no arguments, it populate %ENV with special variables (e.g. $ENV{QUERY_STRING}) like mod_cgi does.

Apache::Registry

http://perl.apache.org/docs/2.0/user/porting/compat.html

Apache::Registry, Apache::PerlRun and other modules from the registry family now live in the ModPerl:: namespace. In mod_perl 2.0 we put mod_perl specific functionality into the ModPerl:: namespace, similar to APR:: and Apache2:: which are used for libapr and Apache, respectively.

ModPerl::Registry (and others) doesn’t chdir() into the script’s dir like Apache::Registry does, because chdir() affects the whole process under threads. If you need this functionality use ModPerl::RegistryPrefork or ModPerl::PerlRunPrefork.

Хендлеры

PerlHandler

PerlHandler was replaced with PerlResponseHandler.

http://perl.apache.org/docs/2.0/user/porting/compat.html

Устаревшие, но поддерживаемые директивы

http://perl.apache.org/docs/2.0/user/config/config.html#mod_perl_Directives_Argument_Types_and_Allowed_Location

mod_perl 1.0 back-compatibility directives:

    Directive                 Arguments  Scope
  --------------------------------------------
  PerlHandler                   ITERATE   DIR
  PerlSendHeader                FLAG      DIR
  PerlSetupEnv                  FLAG      DIR
  PerlTaintCheck                FLAG      SRV
  PerlWarn                      FLAG      SRV

Stacked handlers

Жизненный цикл (фазы) запроса: http://perl.apache.org/docs/2.0/user/handlers/http.html#HTTP_Request_Cycle_Phases

Нескольно хендлеров на одну фазу == “stacked handlers”.

http://perl.apache.org/docs/2.0/user/porting/compat.html#Stacked_Handlers
Both mod_perl 1.0 and 2.0 support the ability to register more than one handler in each runtime phase, a feature known as stacked handlers.

The behavior of stacked Perl handlers differs between mod_perl 1.0 and 2.0. In 2.0, mod_perl respects the run-type of the underlying hook - it does not run all configured Perl handlers for each phase but instead behaves in the same way as Apache does when multiple handlers are configured, respecting (or ignoring) the return value of each handler as it is called.

http://perl.apache.org/docs/2.0/user/handlers/intro.html#Stacked_Handlers
For each phase there can be more than one handler assigned (also known as hooks, because the C functions are called ap_hook_<phase_name>). Phases’ behavior varies when there is more then one handler registered to run for the same phase.

Типы хендлеров

VOID
Handlers of the type VOID will be all executed in the order they have been registered disregarding their return values. Though in mod_perl they are expected to return Apache2::Const::OK.

RUN_FIRST
Handlers of the type RUN_FIRST will be executed in the order they have been registered until the first handler that returns something other than Apache2::Const::DECLINED. If the return value is Apache2::Const::DECLINED, the next handler in the chain will be run. If the return value is Apache2::Const::OK the next phase will start. In all other cases the execution will be aborted.

RUN_ALL
Handlers of the type RUN_ALL will be executed in the order they have been registered until the first handler that returns something other than Apache2::Const::OK or Apache2::Const::DECLINED.

PerlResponseHandler – RUN_FIRST

register_cleanup + child_terminate

- Apache->register_cleanup(sub {Apache->child_terminate();});
+ Apache2::RequestUtil->request->pool->cleanup_register(sub{Apache2::RequestUtil->request->child_terminate();});

$r->notes, utf8

Из документации на APR::Table (http://search.cpan.org/~phred/mod_perl/docs/api/APR/Table.pod):

APR::Table allows its users to manipulate opaque string-content tables.

On the C level the “opaque string-content” means: you can put in ‘\0’-terminated strings and whatever you put in your get out.

On the Perl level that means that we convert scalars into strings and store those strings. Any special information that was in the Perl scalar is not stored. So for example if a scalar was marked as utf8, tainted or tied, that information is not stored. When you get the data back as a Perl scalar you get only the string.

Что делать, варианты:

1. Явно декодировать строки (и самостоятельно отслеживать, что надо декодировать, а что нет)

$r->notes->set(aaa => $var);
...
$var = Encode::decode_utf8($r->notes->get('aaa'));

2. Пользоваться pnotes

$r->pnotes(aaa => $var);
...
$var = $r->pnotes->get('aaa');

Важно: для записи в access.log Apache может пользоваться значениями из notes (пример: %{uid}n, вообще %...{Foobar}n – The contents of note Foobar from another module.). Их надо по-прежнему записывать в notes, не только в pnotes.

3. Наследоваться и делать utf-обертки

Куки при редиректах, $r->err_headers_out

Устанавливаем куку и делаем редирект.

Документация по Apache и Apache2::RequestRec говорит, что для этого подходит $r->err_headers_out, цитата:

The difference between headers_out and err_headers_out, is that the latter are printed even on error

Однако под Apache 1.3 работала и конструкция headers_out + редирект (кука устанавливалась). А под Apache 2.2 – нет, при редиректе надо использовать err_headers_out

Глобальный объект $r

Умолчательное поведение отличается для разных фаз обработки запроса

См. http://perl.apache.org/docs/2.0/user/config/config.html, опция GlobalRequest:

Setup the global $r object for use with Apache2->request.

This setting is enabled by default during the PerlResponseHandler phase for sections configured as:

  <Location ...>
      SetHandler perl-script
      ...
  </Location>

but is not enabled by default for sections configured as:

  <Location ...>
      SetHandler modperl
      ....
  </Location>

And can be disabled with:

  <Location ...>
      SetHandler perl-script
      PerlOptions -GlobalRequest
      ...
  </Location>

Notice that if you need the global request object during other phases, you will need to explicitly enable it in the configuration file.

You can also set that global object from the handler code, like so:

  sub handler {
      my $r = shift;
      Apache2::RequestUtil->request($r);
      ...
  }