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 {