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]

Reply via email to