dougm 01/11/14 19:02:43 Modified: src/modules/perl mod_perl.c modperl_env.c modperl_env.h t/conf modperl_extra.pl t/modperl .cvsignore Log: more complete implementation of tie %ENV to r->subprocess_env Revision Changes Path 1.95 +2 -7 modperl-2.0/src/modules/perl/mod_perl.c Index: mod_perl.c =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/mod_perl.c,v retrieving revision 1.94 retrieving revision 1.95 diff -u -r1.94 -r1.95 --- mod_perl.c 2001/11/15 01:30:45 1.94 +++ mod_perl.c 2001/11/15 03:02:42 1.95 @@ -147,6 +147,8 @@ return; } + modperl_env_init(); + base_perl = modperl_startup(base_server, p); #ifdef USE_ITHREADS @@ -538,21 +540,14 @@ h_stdout = modperl_io_tie_stdout(aTHX_ r); h_stdin = modperl_io_tie_stdin(aTHX_ r); -#if 0 - /* current implementation of tie %ENV to $r->subprocess_env - * is not threadsafe - */ modperl_env_request_tie(aTHX_ r); -#endif retval = modperl_response_handler_run(r, FALSE); modperl_io_handle_untie(aTHX_ h_stdout); modperl_io_handle_untie(aTHX_ h_stdin); -#if 0 modperl_env_request_untie(aTHX_ r); -#endif modperl_perl_global_request_restore(aTHX_ r); 1.19 +150 -41 modperl-2.0/src/modules/perl/modperl_env.c Index: modperl_env.c =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_env.c,v retrieving revision 1.18 retrieving revision 1.19 diff -u -r1.18 -r1.19 --- modperl_env.c 2001/11/12 22:14:36 1.18 +++ modperl_env.c 2001/11/15 03:02:43 1.19 @@ -1,6 +1,7 @@ #include "mod_perl.h" #define EnvMgObj SvMAGIC((SV*)ENVHV)->mg_ptr +#define EnvMgLen SvMAGIC((SV*)ENVHV)->mg_len static MP_INLINE void modperl_env_hv_store(pTHX_ HV *hv, apr_table_entry_t *elt) @@ -87,7 +88,6 @@ const apr_array_header_t *array; apr_table_entry_t *elts; - if (MpReqSETUP_ENV(rcfg)) { return; } @@ -118,69 +118,178 @@ MpReqSETUP_ENV_On(rcfg); } -static int modperl_env_request_set(pTHX_ SV *sv, MAGIC *mg) +void modperl_env_request_tie(pTHX_ request_rec *r) { - const char *key, *val; - STRLEN klen, vlen; - request_rec *r = (request_rec *)EnvMgObj; + EnvMgObj = (char *)r; + EnvMgLen = -1; + +#ifdef MP_PERL_HV_GMAGICAL_AWARE + SvGMAGICAL_on((SV*)ENVHV); +#endif +} + +void modperl_env_request_untie(pTHX_ request_rec *r) +{ + EnvMgObj = NULL; + +#ifdef MP_PERL_HV_GMAGICAL_AWARE + SvGMAGICAL_off((SV*)ENVHV); +#endif +} + +/* to store the original virtual tables + * these are global, not per-interpreter + */ +static MGVTBL MP_PERL_vtbl_env; +static MGVTBL MP_PERL_vtbl_envelem; - key = (const char *)MgPV(mg,klen); - val = (const char *)SvPV(sv,vlen); +#define MP_PL_vtbl_call(name, meth) \ + MP_PERL_vtbl_##name.svt_##meth(aTHX_ sv, mg) - apr_table_set(r->subprocess_env, key, val); +#define MP_dENV_KEY \ + STRLEN klen; \ + const char *key = (const char *)MgPV(mg,klen) + +#define MP_dENV_VAL \ + STRLEN vlen; \ + const char *val = (const char *)SvPV(sv,vlen) - /*return magic_setenv(sv, mg);*/ +/* + * XXX: what we do here might change: + * - make it optional for %ENV to be tied to r->subprocess_env + * - make it possible to modify environ + * - we could allow modification of environ if mpm isn't threaded + * - we could allow modification of environ if variable isn't a CGI + * variable (still could cause problems) + */ +/* + * problems we are trying to solve: + * - environ is shared between threads + * + Perl does not serialize access to environ + * + even if it did, CGI variables cannot be shared between threads! + * problems we create by trying to solve above problems: + * - a forked process will not inherit the current %ENV + * - C libraries might rely on environ, e.g. DBD::Oracle + */ +static int modperl_env_magic_set_all(pTHX_ SV *sv, MAGIC *mg) +{ + request_rec *r = (request_rec *)EnvMgObj; + if (r) { + if (PL_localizing) { + /* local %ENV = (FOO => 'bar', BIZ => 'baz') */ + HE *entry; + STRLEN n_a; + + hv_iterinit((HV*)sv); + while ((entry = hv_iternext((HV*)sv))) { + I32 keylen; + apr_table_set(r->subprocess_env, + hv_iterkey(entry, &keylen), + SvPV(hv_iterval((HV*)sv, entry), n_a)); + } + } + } + else { + return MP_PL_vtbl_call(env, set); + } + return 0; } -#ifdef MP_PERL_HV_GMAGICAL_AWARE -static int modperl_env_request_get(pTHX_ SV *sv, MAGIC *mg) +static int modperl_env_magic_clear_all(pTHX_ SV *sv, MAGIC *mg) { - const char *key, *val; - STRLEN klen; request_rec *r = (request_rec *)EnvMgObj; - - key = (const char *)MgPV(mg,klen); - if ((val = apr_table_get(r->subprocess_env, key))) { - sv_setpv(sv, val); + if (r) { + apr_table_clear(r->subprocess_env); } else { - sv_setsv(sv, &PL_sv_undef); + return MP_PL_vtbl_call(env, clear); } return 0; } -#endif -/* - * XXX: PL_vtbl_* are global (not per-interpreter) - * so this method of tie-ing is not thread-safe - * overridding svt_get is only useful with 5.7.2+ and requires - * a smarter lookup than the current modperl_env_request_get - */ -void modperl_env_request_tie(pTHX_ request_rec *r) +static int modperl_env_magic_set(pTHX_ SV *sv, MAGIC *mg) { - EnvMgObj = (char *)r; + request_rec *r = (request_rec *)EnvMgObj; - PL_vtbl_envelem.svt_set = MEMBER_TO_FPTR(modperl_env_request_set); -#ifdef MP_PERL_HV_GMAGICAL_AWARE - SvGMAGICAL_on((SV*)ENVHV); - PL_vtbl_envelem.svt_get = MEMBER_TO_FPTR(modperl_env_request_get); -#endif + if (r) { + MP_dENV_KEY; + MP_dENV_VAL; + apr_table_set(r->subprocess_env, key, val); + } + else { + return MP_PL_vtbl_call(envelem, set); + } + + return 0; } -void modperl_env_request_untie(pTHX_ request_rec *r) +static int modperl_env_magic_clear(pTHX_ SV *sv, MAGIC *mg) { -#if 0 - /* XXX: not currently in use. if enabled Perl_magic_setenv - * is not available to win32 - */ - PL_vtbl_envelem.svt_set = MEMBER_TO_FPTR(Perl_magic_setenv); -#endif + request_rec *r = (request_rec *)EnvMgObj; + + if (r) { + MP_dENV_KEY; + apr_table_unset(r->subprocess_env, key); + } + else { + return MP_PL_vtbl_call(envelem, clear); + } + + return 0; +} + #ifdef MP_PERL_HV_GMAGICAL_AWARE - SvGMAGICAL_off((SV*)ENVHV); - PL_vtbl_envelem.svt_get = 0; +static int modperl_env_magic_get(pTHX_ SV *sv, MAGIC *mg) +{ + request_rec *r = (request_rec *)EnvMgObj; + + if (r) { + MP_dENV_KEY; + const char *val; + + if ((val = apr_table_get(r->subprocess_env, key))) { + sv_setpv(sv, val); + } + else { + sv_setsv(sv, &PL_sv_undef); + } + } + else { + /* there is no svt_get in PL_vtbl_envelem */ + } + + return 0; +} #endif + +/* override %ENV virtual tables with our own */ +static MGVTBL MP_vtbl_env = { + 0, + MEMBER_TO_FPTR(modperl_env_magic_set_all), + 0, + MEMBER_TO_FPTR(modperl_env_magic_clear_all), + 0 +}; + +static MGVTBL MP_vtbl_envelem = { + 0, + MEMBER_TO_FPTR(modperl_env_magic_set), + 0, + MEMBER_TO_FPTR(modperl_env_magic_clear), + 0 +}; + +void modperl_env_init(void) +{ + /* save originals */ + StructCopy(&PL_vtbl_env, &MP_PERL_vtbl_env, MGVTBL); + StructCopy(&PL_vtbl_envelem, &MP_PERL_vtbl_envelem, MGVTBL); + + /* replace with our versions */ + StructCopy(&MP_vtbl_env, &PL_vtbl_env, MGVTBL); + StructCopy(&MP_vtbl_envelem, &PL_vtbl_envelem, MGVTBL); } 1.10 +2 -0 modperl-2.0/src/modules/perl/modperl_env.h Index: modperl_env.h =================================================================== RCS file: /home/cvs/modperl-2.0/src/modules/perl/modperl_env.h,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- modperl_env.h 2001/10/13 19:11:32 1.9 +++ modperl_env.h 2001/11/15 03:02:43 1.10 @@ -23,4 +23,6 @@ void modperl_env_request_untie(pTHX_ request_rec *r); +void modperl_env_init(void); + #endif /* MODPERL_ENV_H */ 1.10 +3 -0 modperl-2.0/t/conf/modperl_extra.pl Index: modperl_extra.pl =================================================================== RCS file: /home/cvs/modperl-2.0/t/conf/modperl_extra.pl,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- modperl_extra.pl 2001/10/09 18:01:21 1.9 +++ modperl_extra.pl 2001/11/15 03:02:43 1.10 @@ -18,6 +18,9 @@ die '$ENV{MOD_PERL} not set!'; } +#see t/response/TestModperl/env.pm +$ENV{MODPERL_EXTRA_PL} = __FILE__; + my $ap_mods = scalar grep { /^Apache/ } keys %INC; my $apr_mods = scalar grep { /^APR/ } keys %INC; 1.7 +1 -0 modperl-2.0/t/modperl/.cvsignore Index: .cvsignore =================================================================== RCS file: /home/cvs/modperl-2.0/t/modperl/.cvsignore,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- .cvsignore 2001/11/13 18:35:08 1.6 +++ .cvsignore 2001/11/15 03:02:43 1.7 @@ -1,3 +1,4 @@ +env.t endav.t exit.t printf.t