Apache2-Translation
view release on metacpan or search on metacpan
lib/Apache2/Translation.pod view on Meta::CPAN
Phase. It is somehow similar to C<mod_rewrite> but configuration
statements are read at runtime, thus, allowing to reconfigure
a server without restarting it.
The actual configuration statements are read by means of a
I<Translation Provider>, a Perl class offering
a particular interface, see below. Currently there are 3 providers
implemented, L<Apache2::Translation::DB>, L<Apache2::Translation::BDB>,
and L<Apache2::Translation::File>.
There is also a WEB interface (L<Apache2::Translation::Admin>).
=head2 B<An Example>
Let's begin with an example. Given some database table:
id key uri blk ord action
1 front :PRE: 0 0 Cond: $HOSTNAME !~ /^(?:www\.)xyz\.(?:com|de)$/
2 front :PRE: 0 1 Redirect: 'http://xyz.com'.$URI, 301
3 front :PRE: 1 0 Do: $CTX{lang}='en'
4 front :PRE: 1 1 Cond: $HOSTNAME =~ /de$/
5 front :PRE: 1 2 Do: $CTX{lang}='de'
6 front /static 0 0 File: $DOCROOT.'/'.$CTX{lang}.$MATCHED_PATH_INFO
7 front /appl1 0 0 Proxy: 'http://backend/'.$CTX{lang}.$URI
8 front /appl2 0 0 Proxy: 'http://backend/'.$URI.'?l='.$CTX{lang}
9 front / 0 0 Config: ['AuthName "secret"'], ['AuthType Basic']
10 back :PRE: 0 0 Cond: $r->connection->remote_ip ne '127.0.0.1'
11 back :PRE: 0 1 Error: 403, 'Forbidden by Apache2::Translation(11)'
12 back /appl1 0 0 PerlHandler: 'My::Application1'
13 back /appl2 0 0 PerlHandler: 'My::Application2'
The C<id> column in this table is not really necessary for
C<Apache2::Translation>. But if you want to deploy
L<Apache2::Translation::Admin> you need it.
Well, here we have a frontend/backend configuration. The frontend records
are labeled with the key C<front>, the backend records with C<back>.
When a request comes in first the records with C<:PRE:> in the C<uri>-field are
examined. Suppose, a request for C<http://abc.com/static/img.png>
comes in. Record 1 (id=1) checks the C<Host> header. The expression
after C<Cond:> is evaluated as Perl code. It obviously returns true.
C<Cond> stands for I<condition>. But how does it affect the further
workflow? Here C<blk> and C<ord> come in. All records with the same
C<key>, C<uri> and C<blk> form a B<block>. C<ord> gives an order within
this block. Within a block all actions are executed up to the first
condition that is false.
Now, because our condition in record 1 is true the action in record 2
(within the same block) is executed. It redirects the browser with a
HTTP code of 301 (MOVED PERMANENTLY) to C<http://xyz.com/static/img.png>.
When the redirected request comes back the condition in record 1 is
false. Hence, the next block (key=front, uri=:PRE:, blk=1) is evaluated.
First a C<lang> member of a context hash is set to C<en>. A C<Do> action
is similar to a condition, only its value is ignored. Record 4 then
checks if the C<Host> header matches C</de$/>. If so, then record 5 sets
the I<language> to C<de>.
Now, the records labeled with C<:PRE:> are finished. The handler starts
looking for blocks labeled with the request uri. That is, it looks
for a block with key=front, uri=/static/img.png. None is found.
Then it cuts off the last part of the uri (/img.png), repeats the
lookup and finds record 6. The C<File> action sets C<$r-E<gt>filename> to
C<$DOCROOT/en/img.png>. C<Apache2::Translation> provides some convenience
variables. They are tied to members of the request record.
C<$MATCHED_PATH_INFO> contains the uri part cut off
(C</img.png>). More on them below.
Now another round is started and the next uri part is cut off. Record 9
matches. We see a C<Config> action that sets C<AuthName> and C<AuthType>.
At the end the translation handler checks if C<$r-E<gt>filename> was set and
returns C<Apache2::Const::OK> or C<Apache2::Const::DECLINED> respectively.
I think that example gives a general idea, what C<Apache2::Translation>
does.
=head2 B<Processing States>
Internally C<Apache2::Translation> is implemented as a state machine. It
starts in the I<START> state, where some variables are initialized. From
there it shifts immediately to the I<PREPOC> state. Here all C<:PRE:>
rules are evaluated. From I<PREPROC> it shifts to I<PROC>. Now the rules
with real uris are examined. When the I<DONE> state is reached processing is
finished.
There is a special state named I<LOOKUPFILE>. It is only used for subrequests
that don't have an URI. For such requests the URI translation phase of the
request cycle is skipped. Hence a I<PerlTransHandler> would never be called.
Such requests are results of calling C<$r-E<gt>lookup_file> for example.
To catch also such requests install C<Apache2::Translation> both as
I<PerlTransHandler> as well as I<PerlMapToStorageHandler>. Then if such a
subrequest occures the handler enters the I<LOOKLUPFILE> state instead of
I<PREPROC>. From I<LOOKLUPFILE> it normally shifts to I<PROC> unless it
executes a C<Restart> action. In that case it shifts to I<PREPROC>.
You have to set C<$MATCHED_URI> to some initial value if you want to hop
through the I<PROC> phase. A still empty C<$MATCHED_URI> shifts from I<PROC>
immediately to I<DONE>.
B<Note>: The I<LOOKUPFILE> stuff is still somewhat experimental.
You can control the current state by means of the C<State>, C<Done> and
C<Restart> actions.
=head2 B<Blocks and Lists of Blocks>
Above, we have defined a B<block> as all records with the same
C<key>, C<uri> and C<block>. The actions within a block are ordered by
the C<order> field.
A B<list of blocks> is then an ordered list of all blocks with the same
C<key> and C<uri>. The order is given by the C<block> number.
=head2 B<Actions>
An action starts with a key word optionally followed by a colon and
some arguments. The key words are case insensitive.
lib/Apache2/Translation.pod view on Meta::CPAN
In short this action tries to figure out what C<string> means and calls it
as C<modperl> handler.
In detail it installs a C<Apache2::Translation::response> as
C<PerlResponseHandler>. When called the handler evaluates C<string> which
results either in a subroutine name, a package name, a subroutine reference
or an object or class that implements the C<handler> method. If a package
name is given it must implement a C<handler> subroutine.
If the given package is not yet loaded it is C<require>ed.
Then the resulting subroutine or method is called and C<$r> is passed.
Further, a C<PerlMapToStorageHandler> is installed that skips the handling
of C<Directory> containers and C<.htaccess> files. If not set, this
handler also sets C<path_info>. Assumed,
#uri blk ord action
/some/path 0 0 PerlHandler: ...
and a request comes in for C</some/path/foo/bar>. Then C<path_info> is set
to C</foo/bar>.
=item B<Config: list_of_strings_or_arrays>
=item B<FixupConfig: list_of_strings_or_arrays>
Surprisingly, these are the most complex actions of all.
C<Config> adds Apache configuration directives to the request in the
I<Map To Storage> phase B<before> the default C<MapToStorage> handler. Think of
it as a kind of C<.htaccess>. C<FixupConfig> does the same in the I<Fixup>
phase. While C<Config> is used quite often C<FixupConfig> is seldom required.
It is used mainly to mend configurations that are spoiled by the default
C<MapToStorage> handler.
Arguments to both actions are strings or arrays of one or two elements:
Config: 'AuthName "secret"',
['AuthType Basic'],
['ProxyPassReverse http://...', '/path']
To understand the different meaning, you have to know about how Apache
applies its configuration to a request. Hence, let's digress a little.
Each Apache directive is used in certain contexts. Some for example
can occur only in server config context, that means outside any C<Directory>,
C<Location> or even C<VirtualHost> container. C<Listen> or C<PidFile> are
examples. Other directives insist on being placed in a container.
Also, the point in time when a directive takes effect differs for different
directives. C<PidFile> is clearly applied during server startup before
any request is processed. Hence, our C<Config> action cannot apply C<PidFile>.
It's simply too late. C<AllowOverride> is applied to single requests.
But since it affects the processing of C<.htaccess> files it must be applied
before that processing takes place. To make things even more confusing some
directives take effect at several points in time. Consider
Options FollowSymLinks ExecCGI
C<FollowSymLinks> is applied when Apache looks up a file in the file system,
while C<ExecCGI> influences the way the response is generated ages later.
Apache solves this complexity by computing a configuration for each single
request. As a starting point it uses the server default configuration. That
is the configuration outside any C<Location> or C<Directory> for a
virtual host. This basic configuration is assigned to the request just
between the I<Uri Translation Phase> and I<Map to Storage>. At the very
end of I<Map to Storage> Apache's core I<Map to Storage> handler incorporates
matching C<Directory> containers and C<.htaccess> files into the request's
current configuration. C<Location> containers are merged after
I<Map to Storage> is finished.
Our C<Config> action is applied early in I<Map to Storage>. That means it
affects the way Apache maps the request file name computed to the file
system, because that comes later. But it also means, your
static configuration (config file based) overrides our C<Config> actions.
This limitation can be partly overcome using C<FixupConfig> instead of
C<Config>.
Now, what does the various syntaxes mean? The simplest one:
#uri blk ord action
/uri 0 0 Config: 'ProxyPassReverse http://my.backend.org'
is very close to
<Location /uri>
ProxyPassReverse http://my.backend.org
</Location>
Only, it is applied before any C<Directory> container takes effect.
Note, the uri-argument to the C<Location> container is the value of
C<$MATCHED_URI>, see below. This is also valid if the C<Config> action
is used from a C<Call>ed block.
The location uri is sometimes important. C<ProxyPassReverse>, for
example, uses the path given to the location container for its own purpose.
All other forms of C<Config> are not influenced by C<$MATCHED_URI>.
These two:
Config: ['ProxyPassReverse http://my.backend.org']
Config: ['ProxyPassReverse /path http://my.backend.org', '']
are equivalent to
<Location />
ProxyPassReverse http://my.backend.org
</Location>
Note, the location container uri differs.
The first one of them is also the only form of C<Config> available with
mod_perl before 2.0.3.
The next one:
Config: ['ProxyPassReverse http://my.backend.org', '/path']
( run in 1.633 second using v1.01-cache-2.11-cpan-39bf76dae61 )