geoff       2004/09/20 11:14:48

  Modified:    .        Changes
               src/modules/perl mod_perl.h modperl_cmd.c modperl_config.c
                        modperl_types.h
               t/response/TestModperl merge.pm
  Log:
  get PerlSetVar and PerlAddVar multi-level merges to (finally) work
  properly.
  Submitted by: [EMAIL PROTECTED]
  Reviewed by:  geoff
  
  Revision  Changes    Path
  1.489     +3 -0      modperl-2.0/Changes
  
  Index: Changes
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/Changes,v
  retrieving revision 1.488
  retrieving revision 1.489
  diff -u -r1.488 -r1.489
  --- Changes   18 Sep 2004 22:17:59 -0000      1.488
  +++ Changes   20 Sep 2004 18:14:47 -0000      1.489
  @@ -12,6 +12,9 @@
   
   =item 1.99_17-dev
   
  +get PerlSetVar and PerlAddVar multi-level merges to (finally) work
  +properly.  [Rici Lake <rici ricilake.net>]
  +
   MP_AP_BUILD configure option removed. Now implicit when MP_USE_STATIC
   is specified [Gozer]
   
  
  
  
  1.70      +4 -3      modperl-2.0/src/modules/perl/mod_perl.h
  
  Index: mod_perl.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/mod_perl.h,v
  retrieving revision 1.69
  retrieving revision 1.70
  diff -u -r1.69 -r1.70
  --- mod_perl.h        18 Sep 2004 04:33:34 -0000      1.69
  +++ mod_perl.h        20 Sep 2004 18:14:47 -0000      1.70
  @@ -130,9 +130,10 @@
   
   #define MgTypeExt(mg) (mg->mg_type == '~')
   
  -typedef void MP_FUNC_T(modperl_table_modify_t) (apr_table_t *,
  -                                                const char *,
  -                                                const char *);
  +typedef void MP_FUNC_T(modperl_var_modify_t) (apr_table_t *,
  +                                              apr_table_t *,
  +                                              const char *,
  +                                              const char *);
   
   /* we need to hook a few internal things before APR_HOOK_REALLY_FIRST */
   #define MODPERL_HOOK_REALLY_REALLY_FIRST (-20)
  
  
  
  1.66      +29 -38    modperl-2.0/src/modules/perl/modperl_cmd.c
  
  Index: modperl_cmd.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_cmd.c,v
  retrieving revision 1.65
  retrieving revision 1.66
  diff -u -r1.65 -r1.66
  --- modperl_cmd.c     9 Sep 2004 22:16:37 -0000       1.65
  +++ modperl_cmd.c     20 Sep 2004 18:14:48 -0000      1.66
  @@ -266,64 +266,55 @@
       }
   }
   
  -static MP_CMD_SRV_DECLARE2(handle_vars)
  +static void modperl_cmd_addvar_func(apr_table_t *configvars,
  +                                    apr_table_t *setvars,
  +                                    const char *key, const char *val)
   {
  -    MP_dSCFG(parms->server);
  -    modperl_config_dir_t *dcfg = (modperl_config_dir_t *)mconfig;
  -    const char *name = parms->cmd->name;
  +    apr_table_addn(configvars, key, val);
  +}
   
  -    /* PerlSetVar and PerlAddVar logic.  here's the deal...
  -     *
  -     * cfg->configvars holds the final PerlSetVar/PerlAddVar configuration
  -     * for a given server or directory.  however, getting to that point
  -     * is kind of tricky, due to the add-style nature of PerlAddVar.
  -     *
  -     * the solution is to use cfg->setvars to hold PerlSetVar entries
  -     * and cfg->addvars to hold PerlAddVar entries, each serving as a
  -     * placeholder for when we need to know what's what in the merge routines.
  -     *
  -     * however, for the initial pass, apr_table_setn and apr_table_addn
  -     * will properly build the configvars table, which will be visible to
  -     * startup scripts trying to access per-server configurations.
  -     *
  -     * the end result is that we need to populate all three tables in order
  -     * to keep things straight later on see merge_table_config_vars in
  -     * modperl_config.c
  -     */
  -    modperl_table_modify_t func =
  -        strEQ(name, "PerlSetVar") ? apr_table_setn : apr_table_addn;
  +/*  Conceptually, setvar is { unsetvar; addvar; } */
   
  -    apr_table_t *table =
  -        strEQ(name, "PerlSetVar") ? dcfg->setvars : dcfg->addvars;
  +static void modperl_cmd_setvar_func(apr_table_t *configvars,
  +                                    apr_table_t *setvars,
  +                                    const char * key, const char *val)
  +{
  +    apr_table_setn(setvars, key, val);
  +    apr_table_setn(configvars, key, val);
  +}
   
  -    func(table, arg1, arg2);
  -    func(dcfg->configvars, arg1, arg2);
  +static const char *modperl_cmd_modvar(modperl_var_modify_t varfunc,
  +                                      cmd_parms *parms,
  +                                      modperl_config_dir_t *dcfg,
  +                                      const char *arg1, const char *arg2)
  +{
  +    varfunc(dcfg->configvars, dcfg->setvars, arg1, arg2);
   
       MP_TRACE_d(MP_FUNC, "%s DIR: arg1 = %s, arg2 = %s\n",
  -               name, arg1, arg2);
  +               parms->cmd->name, arg1, arg2);
   
       /* make available via Apache->server->dir_config */
       if (!parms->path) {
  -        table = strEQ(name, "PerlSetVar") ? scfg->setvars : scfg->addvars;
  -
  -        func(table, arg1, arg2);
  -        func(scfg->configvars, arg1, arg2);
  +        MP_dSCFG(parms->server);
  +        varfunc(scfg->configvars, scfg->setvars, arg1, arg2);
   
           MP_TRACE_d(MP_FUNC, "%s SRV: arg1 = %s, arg2 = %s\n",
  -                   name, arg1, arg2);
  +                   parms->cmd->name, arg1, arg2);
       }
   
       return NULL;
   }
   
  -MP_CMD_SRV_DECLARE2(set_var)
  +MP_CMD_SRV_DECLARE2(add_var)
   {
  -    return modperl_cmd_handle_vars(parms, mconfig, arg1, arg2);
  +    modperl_config_dir_t *dcfg = (modperl_config_dir_t *)mconfig;
  +    return modperl_cmd_modvar(modperl_cmd_addvar_func, parms, dcfg, arg1, arg2);
   }
   
  -MP_CMD_SRV_DECLARE2(add_var)
  +MP_CMD_SRV_DECLARE2(set_var)
   {
  -    return modperl_cmd_handle_vars(parms, mconfig, arg1, arg2);
  +    modperl_config_dir_t *dcfg = (modperl_config_dir_t *)mconfig;
  +    return modperl_cmd_modvar(modperl_cmd_setvar_func, parms, dcfg, arg1, arg2);
   }
   
   MP_CMD_SRV_DECLARE2(set_env)
  
  
  
  1.83      +25 -63    modperl-2.0/src/modules/perl/modperl_config.c
  
  Index: modperl_config.c
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_config.c,v
  retrieving revision 1.82
  retrieving revision 1.83
  diff -u -r1.82 -r1.83
  --- modperl_config.c  18 Sep 2004 04:33:34 -0000      1.82
  +++ modperl_config.c  20 Sep 2004 18:14:48 -0000      1.83
  @@ -43,6 +43,11 @@
        * note that this is equivalent to apr_table_overlap except a new
        * table is generated, which is required (otherwise we would clobber
        * the existing parent or child configurations)
  +     *
  +     * note that this is *not* equivalent to apr_table_overlap, although
  +     * I think it should be, because apr_table_overlap seems to clear
  +     * its first argument when the tables have different pools. I think
  +     * this is wrong -- rici
        */
       apr_table_t *merge = apr_table_overlay(p, base, add);
   
  @@ -59,54 +64,29 @@
   #define merge_table_overlap_item(item) \
       mrg->item = modperl_table_overlap(p, base->item, add->item)
   
  -static apr_table_t *merge_table_config_vars(apr_pool_t *p,
  -                                            apr_table_t *configvars,
  -                                            apr_table_t *set,
  -                                            apr_table_t *add)
  +static apr_table_t *merge_config_add_vars(apr_pool_t *p,
  +                                          const apr_table_t *base,
  +                                          const apr_table_t *unset,
  +                                          const apr_table_t *add)
   {
  -    apr_table_t *base = apr_table_copy(p, configvars);
  -    apr_table_t *merged_config_vars;
  +    apr_table_t *temp = apr_table_copy(p, base);
   
       const apr_array_header_t *arr;
       apr_table_entry_t *entries;
       int i;
   
  -    /* configvars already contains a properly merged PerlSetVar/PerlAddVar
  -     * configuration for the base (parent), so all we need to do is merge
  -     * the add (child) configuration into it properly.
  -     *
  -     * any PerlSetVar settings in the add (child) config need to reset
  -     * existing entries in the base (parent) config, or generate a
  -     * new entry where none existed previously.  PerlAddVar settings
  -     * are merged into that.
  -     *
  -     * unfortunately, there is no set of apr functions to do this for us - 
  -     * apr_compress_table would be ok, except it always merges mulit-valued
  -     * keys into one, regardless of the APR_OVERLAP_TABLES flag.  that is,
  -     * regardless of whether newer entries are set or merged into existing
  -     * entries, the entire table is _always_ compressed.  this is no good -
  -     * we need separate entries for existing keys, not a single (compressed)
  -     * entry.
  -     *
  -     * fortunately, the logic here is simple.  first, (re)set the base (parent)
  -     * table where a PerlSetVar entry exists in the add (child) configuration.
  -     * then, just overlay the PerlAddVar configuration into it.
  -     */
  -
  -    arr = apr_table_elts(set);
  +    /* for each key in unset do apr_table_unset(temp, key); */
  +    arr = apr_table_elts(unset);
       entries  = (apr_table_entry_t *)arr->elts;
   
       /* hopefully this is faster than using apr_table_do  */
       for (i = 0; i < arr->nelts; i++) {
  -        apr_table_setn(base, entries[i].key, entries[i].val);
  +        if (entries[i].key) {
  +            apr_table_unset(temp, entries[i].key);
  +        }
       }
  -
  -    /* at this point, all the PerlSetVar merging has happened.  add in the 
  -     * add (child) PerlAddVar entries and we're done
  -     */
  -    merged_config_vars = apr_table_overlay(p, base, add);
  -      
  -    return merged_config_vars;
  +     
  +    return apr_table_overlay(p, temp, add);
   }
   
   #define merge_handlers(merge_flag, array) \
  @@ -141,18 +121,10 @@
       merge_table_overlap_item(SetEnv);
   
       /* this is where we merge PerlSetVar and PerlAddVar together */
  -    mrg->configvars = merge_table_config_vars(p,
  -                                              base->configvars,
  -                                              add->setvars, add->addvars);
  -
  -    /* note we don't care about merging dcfg->setvars or dcfg->addvars
  -     * specifically - what is important to merge is dfcg->configvars.
  -     * but we need to keep track of the entries for this config, so
  -     * the merged values are simply the values for the add (current)
  -     * configuration.
  -     */
  -    mrg->setvars = add->setvars;
  -    mrg->addvars = add->addvars;
  +    mrg->configvars = merge_config_add_vars(p,
  +                                            base->configvars,
  +                                            add->setvars, add->configvars);
  +    merge_table_overlap_item(setvars);
   
       /* XXX: check if Perl*Handler is disabled */
       for (i=0; i < MP_HANDLER_NUM_PER_DIR; i++) {
  @@ -187,7 +159,6 @@
       scfg->argv = apr_array_make(p, 2, sizeof(char *));
   
       scfg->setvars = apr_table_make(p, 2);
  -    scfg->addvars = apr_table_make(p, 2);
       scfg->configvars = apr_table_make(p, 2);
   
       scfg->PassEnv = apr_table_make(p, 2);
  @@ -223,7 +194,6 @@
       dcfg->flags = modperl_options_new(p, MpDirType);
   
       dcfg->setvars = apr_table_make(p, 2);
  -    dcfg->addvars = apr_table_make(p, 2);
       dcfg->configvars = apr_table_make(p, 2);
   
       dcfg->SetEnv = apr_table_make(p, 2);
  @@ -320,18 +290,10 @@
       merge_table_overlap_item(PassEnv);
    
       /* this is where we merge PerlSetVar and PerlAddVar together */
  -    mrg->configvars = merge_table_config_vars(p,
  -                                              base->configvars,
  -                                              add->setvars, add->addvars);
  -
  -    /* note we don't care about merging dcfg->setvars or dcfg->addvars
  -     * specifically - what is important to merge is dfcg->configvars.
  -     * but we need to keep track of the entries for this config, so
  -     * the merged values are simply the values for the add (current)
  -     * configuration.
  -     */
  -    mrg->setvars = add->setvars;
  -    mrg->addvars = add->addvars;
  +    mrg->configvars = merge_config_add_vars(p,
  +                                            base->configvars,
  +                                            add->setvars, add->configvars);
  +    merge_table_overlap_item(setvars);
   
       merge_item(server);
   
  
  
  
  1.78      +0 -2      modperl-2.0/src/modules/perl/modperl_types.h
  
  Index: modperl_types.h
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_types.h,v
  retrieving revision 1.77
  retrieving revision 1.78
  diff -u -r1.77 -r1.78
  --- modperl_types.h   18 Sep 2004 04:33:34 -0000      1.77
  +++ modperl_types.h   20 Sep 2004 18:14:48 -0000      1.78
  @@ -127,7 +127,6 @@
   
   typedef struct {
       MpHV *setvars;
  -    MpHV *addvars;
       MpHV *configvars;
       MpHV *SetEnv;
       MpHV *PassEnv;
  @@ -159,7 +158,6 @@
       MpAV *handlers_per_dir[MP_HANDLER_NUM_PER_DIR];
       MpHV *SetEnv;
       MpHV *setvars;
  -    MpHV *addvars;
       MpHV *configvars;
       modperl_options_t *flags;
   #ifdef USE_ITHREADS
  
  
  
  1.8       +0 -3      modperl-2.0/t/response/TestModperl/merge.pm
  
  Index: merge.pm
  ===================================================================
  RCS file: /home/cvs/modperl-2.0/t/response/TestModperl/merge.pm,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- merge.pm  9 Jul 2004 18:53:01 -0000       1.7
  +++ merge.pm  20 Sep 2004 18:14:48 -0000      1.8
  @@ -88,9 +88,6 @@
   
       if ($uri =~ m/(merge3)/) {
           $hash = $1;
  -
  -        # skip .htaccess merges for now - they are still broken
  -        plan tests => 10, under_construction;
       } elsif ($uri =~ m/(merge2)/) {
           $hash = $1;
       } else {
  
  
  

Reply via email to