stas 2002/12/12 02:17:27
Modified: src/docs/2.0/user/config custom.pod
Log:
got the big example working (core fixes were pending), now need to add
explainations
Revision Changes Path
1.2 +316 -0 modperl-docs/src/docs/2.0/user/config/custom.pod
Index: custom.pod
===================================================================
RCS file: /home/cvs/modperl-docs/src/docs/2.0/user/config/custom.pod,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- custom.pod 9 Dec 2002 16:47:06 -0000 1.1
+++ custom.pod 12 Dec 2002 10:17:27 -0000 1.2
@@ -728,6 +728,322 @@
NotifyErrorEmail email_address
+=head1 Examples
+
+=head2 Merging at Work
+
+In the following example we are going to demonstrate in details how
+merging works, by showing various merging technique.
+
+
+
+ package MyApache::CustomDirectives;
+
+ use strict;
+ use warnings FATAL => 'all', NONFATAL => 'redefine';
+
+ use Apache::CmdParms ();
+ use Apache::Module ();
+ use Apache::ServerUtil ();
+
+ use Apache::Const -compile => qw(OK);
+
+ our @APACHE_MODULE_COMMANDS = (
+ { name => 'MyPlus' },
+ { name => 'MyList' },
+ { name => 'MyAppend' },
+ { name => 'MyOverride' },
+ );
+
+ sub MyPlus { set_val('MyPlus', @_) }
+ sub MyAppend { set_val('MyAppend', @_) }
+ sub MyOverride { set_val('MyOverride', @_) }
+ sub MyList { push_val('MyList', @_) }
+
+ sub DIR_MERGE { merge(@_) }
+ sub SERVER_MERGE { merge(@_) }
+
+ sub set_val {
+ my($key, $self, $parms, $arg) = @_;
+ $self->{$key} = $arg;
+ unless ($parms->path) {
+ my $srv_cfg = Apache::Module->get_config($self, $parms->server);
+ $srv_cfg->{$key} = $arg;
+ }
+ }
+
+ sub push_val {
+ my($key, $self, $parms, $arg) = @_;
+ push @{ $self->{$key} }, $arg;
+ unless ($parms->path) {
+ my $srv_cfg = Apache::Module->get_config($self, $parms->server);
+ push @{ $srv_cfg->{$key} }, $arg;
+ }
+ }
+
+ sub merge {
+ my($base, $add) = @_;
+
+ my %mrg = ();
+ for my $key (keys %$base, %$add) {
+ next if exists $mrg{$key};
+ if ($key eq 'MyPlus') {
+ $mrg{$key} = ($base->{$key}||0) + ($add->{$key}||0);
+ }
+ elsif ($key eq 'MyList') {
+ push @{ $mrg{$key} },
+ @{ $base->{$key}||[] }, @{ $add->{$key}||[] };
+ }
+ elsif ($key eq 'MyAppend') {
+ $mrg{$key} = join " ", grep defined, $base->{$key},
$add->{$key};
+ }
+ else {
+ # override mode
+ $mrg{$key} = $base->{$key} if exists $base->{$key};
+ $mrg{$key} = $add->{$key} if exists $add->{$key};
+ }
+ }
+
+ return bless \%mrg, ref($base);
+ }
+
+
+ 1;
+ __END__
+
+
+ PerlLoadModule MyApache::CustomDirectives
+ MyPlus 5
+ MyList "MainServer"
+ MyAppend "MainServer"
+ MyOverride "MainServer"
+ Listen 8081
+ <VirtualHost _default_:8081>
+ MyPlus 2
+ MyList "VHost"
+ MyAppend "VHost"
+ MyOverride "VHost"
+ <Location /custom_directives_test>
+ MyPlus 3
+ MyList "Dir"
+ MyAppend "Dir"
+ MyOverride "Dir"
+ SetHandler modperl
+ PerlResponseHandler MyApache::CustomDirectivesTest
+ </Location>
+ <Location /custom_directives_test/subdir>
+ MyPlus 1
+ MyList "SubDir"
+ MyAppend "SubDir"
+ MyOverride "SubDir"
+ </Location>
+ </VirtualHost>
+ <Location /custom_directives_test>
+ SetHandler modperl
+ PerlResponseHandler MyApache::CustomDirectivesTest
+ </Location>
+
+ package MyApache::CustomDirectivesTest;
+
+ use strict;
+ use warnings FATAL => 'all', NONFATAL => 'redefine';
+
+ use Apache::RequestRec ();
+ use Apache::RequestIO ();
+ use Apache::Server ();
+ use Apache::ServerUtil ();
+ use Apache::Module ();
+
+ use Apache::Const -compile => qw(OK);
+
+ sub get_config {
+ Apache::Module->get_config('MyApache::CustomDirectives', @_);
+ }
+
+ sub handler {
+ my($r) = @_;
+ my %secs = ();
+
+ $r->content_type('text/plain');
+
+ my $s = $r->server;
+ my $dir_cfg = get_config($s, $r->per_dir_config);
+ my $srv_cfg = get_config($s);
+
+ if ($s->is_virtual) {
+ $secs{"1: Main Server"} = get_config(Apache->server);
+ $secs{"2: Virtual Host"} = $srv_cfg;
+ $secs{"3: Location"} = $dir_cfg;
+ }
+ else {
+ $secs{"1: Main Server"} = $srv_cfg;
+ $secs{"2: Location"} = $dir_cfg;
+ }
+
+ $r->printf("Processing by %s.\n",
+ $s->is_virtual ? "virtual host" : "main server");
+
+ for my $sec (sort keys %secs) {
+ $r->print("\nSection $sec\n");
+ for my $k (sort keys %{ $secs{$sec}||{} }) {
+ my $v = exists $secs{$sec}->{$k} ? $secs{$sec}->{$k} : 'UNSET';
+ $v = '[' . (join ", ", map {qq{"$_"}} @$v) . ']'
+ if ref($v) eq 'ARRAY';
+ $r->printf("%-10s : %s\n", $k, $v);
+ }
+ }
+
+ return Apache::OK;
+ }
+
+ 1;
+ __END__
+
+
+
+
+ % GET http://localhost:8002/custom_directives_test/
+
+ Processing by main server.
+
+ Section 1: Main Server
+ MyAppend : MainServer
+ MyList : ["MainServer"]
+ MyOverride : MainServer
+ MyPlus : 5
+
+ Section 2: Location
+ MyAppend : MainServer
+ MyList : ["MainServer"]
+ MyOverride : MainServer
+ MyPlus : 5
+
+
+
+ % GET http://localhost:8081/custom_directives_test/
+
+ Processing by virtual host.
+
+ Section 1: Main Server
+ MyAppend : MainServer
+ MyList : ["MainServer"]
+ MyOverride : MainServer
+ MyPlus : 5
+
+ Section 2: Virtual Host
+ MyAppend : MainServer VHost
+ MyList : ["MainServer", "VHost"]
+ MyOverride : VHost
+ MyPlus : 7
+
+ Section 3: Location
+ MyAppend : MainServer VHost Dir
+ MyList : ["MainServer", "VHost", "Dir"]
+ MyOverride : Dir
+ MyPlus : 10
+
+ % GET http://localhost:8081/custom_directives_test/subdir/
+
+ Processing by virtual host.
+
+ Section 1: Main Server
+ MyAppend : MainServer
+ MyList : ["MainServer"]
+ MyOverride : MainServer
+ MyPlus : 5
+
+ Section 2: Virtual Host
+ MyAppend : MainServer VHost
+ MyList : ["MainServer", "VHost"]
+ MyOverride : VHost
+ MyPlus : 7
+
+ Section 3: Location
+ MyAppend : MainServer VHost Dir SubDir
+ MyList : ["MainServer", "VHost", "Dir", "SubDir"]
+ MyOverride : SubDir
+ MyPlus : 11
+
+
+
+
+=head3 Merging Entries Whose Values Are References
+
+When merging entries whose values are references and not scalars, it's
+important to make a deep copy and not a shallow copy, when the
+references gets copied. In our example we merged two references to
+lists, by explicitly extracting the values of each list:
+
+ push @{ $mrg{$key} },
+ @{ $base->{$key}||[] }, @{ $add->{$key}||[] };
+
+While seemingly the following snippet is doing the same:
+
+ $mrg{$key} = $base->{$key};
+ push @{ $mrg{$key} }, @{ $add->{$key}||[] };
+
+it won't do what you expect if the same merge (with the same C<$base>
+and C<$add> arguments) is called more than once, which is the case in
+certain cases. What happens in the latter implementation, is that the
+first line makes both C<$mrg{$key}> and C<$base-E<gt>{$key}> point to
+the same reference. When the second line expands the C<@{ $mrg{$key}
+}>, it also affects C<@{ $base-E<gt>{$key} }>. Therefore when the same
+merge is called second time, the C<$base> argument is not the same
+anymore.
+
+Certainly we could workaround this problem in the mod_perl core, by
+freezing the arguments before the merge call and restoring them
+afterwards, but this will incur a performance hit. One simply has to
+remember that the arguments and the references they point to, should
+stay unmodified through the function call, and then the right code can
+be supplied.
+
+=head3 Merging Order Consequences
+
+Sometimes the merging logic can be influenced by the order of merging.
+It's desirable that the logic will work properly regardless of the
+merging order.
+
+In Apache 1.3 the merging was happening in the following order:
+
+ (((base_srv -> vhost) -> section) -> subsection)
+
+Whereas as of this writing Apache 2.0 performs:
+
+ ((base_srv -> vhost) -> (section -> subsection))
+
+A product of subsections merge (which happen during the request) is
+merged with the product of the server and vhost merge (which happens
+at the startup time). This change was done to improve the
+configuration merging performance.
+
+So for example, if you implement a directive C<MyExp> which performs
+the exponential: C<$mrg=$base**$add>, and let's say there directive is
+used four times in I<httpd.conf>:
+
+ MyExp 5
+ <VirtualHost _default_:8001>
+ MyExp 4
+ <Location /section>
+ MyExp 3
+ </Location>
+ <Location /section/subsection>
+ MyExp 2
+ </Location>
+
+The merged configuration for a request
+I<http://localhost/:8001/section/subsection> will see:
+
+ (5 ** 4) ** (3 ** 2) = 1.45519152283669e+25
+
+under Apache 2.0, whereas under Apache 1.3 the result would be:
+
+ ( (5 ** 4) ** 3) ** 2 = 5.96046447753906e+16
+
+which is not quite the same.
+
+Chances are that your merging rules work identically, regardless of
+the merging order. But you should be aware of this behavior.
=head1 Maintainers
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]