-: 0:Source:modperl_mgv.c -: 0:Object:modperl_mgv.bb -: 1:/* Copyright 2001-2004 The Apache Software Foundation -: 2: * -: 3: * Licensed under the Apache License, Version 2.0 (the "License"); -: 4: * you may not use this file except in compliance with the License. -: 5: * You may obtain a copy of the License at -: 6: * -: 7: * http://www.apache.org/licenses/LICENSE-2.0 -: 8: * -: 9: * Unless required by applicable law or agreed to in writing, software -: 10: * distributed under the License is distributed on an "AS IS" BASIS, -: 11: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -: 12: * See the License for the specific language governing permissions and -: 13: * limitations under the License. -: 14: */ -: 15: -: 16:#include "mod_perl.h" -: 17: -: 18:/* -: 19: * mgv = ModPerl Glob Value || Mostly Glob Value -: 20: * as close to GV as we can get without actually using a GV -: 21: * need config structures to be free of Perl structures -: 22: */ -: 23: -: 24:#define modperl_mgv_new_w_name(mgv, p, n, copy) \ -: 25:mgv = modperl_mgv_new(p); \ -: 26:mgv->len = strlen(n); \ -: 27:mgv->name = (copy ? apr_pstrndup(p, n, mgv->len) : n) -: 28: -: 29:#define modperl_mgv_new_name(mgv, p, n) \ -: 30:modperl_mgv_new_w_name(mgv, p, n, 1) -: 31: -: 32:#define modperl_mgv_new_namen(mgv, p, n) \ -: 33:modperl_mgv_new_w_name(mgv, p, n, 0) -: 34: -: 35:int modperl_mgv_equal(modperl_mgv_t *mgv1, -: 36: modperl_mgv_t *mgv2) #####: 37:{ #####: 38: for (; mgv1 && mgv2; mgv1=mgv1->next, mgv2=mgv2->next) { #####: 39: if (mgv1->hash != mgv2->hash) { #####: 40: return FALSE; -: 41: } #####: 42: if (mgv1->len != mgv2->len) { #####: 43: return FALSE; -: 44: } #####: 45: if (memNE(mgv1->name, mgv2->name, mgv1->len)) { #####: 46: return FALSE; -: 47: } -: 48: } -: 49: #####: 50: return TRUE; -: 51:} -: 52: -: 53:modperl_mgv_t *modperl_mgv_new(apr_pool_t *p) 4360: 54:{ 4360: 55: return (modperl_mgv_t *)apr_pcalloc(p, sizeof(modperl_mgv_t)); -: 56:} -: 57: -: 58:#define modperl_mgv_get_next(mgv) \ -: 59: if (mgv->name) { \ -: 60: mgv->next = modperl_mgv_new(p); \ -: 61: mgv = mgv->next; \ -: 62: } -: 63: -: 64:#define modperl_mgv_hash(mgv) \ -: 65: PERL_HASH(mgv->hash, mgv->name, mgv->len) -: 66: /* MP_TRACE_h(MP_FUNC, "%s...hash=%ld\n", mgv->name, mgv->hash) */ -: 67: -: 68:modperl_mgv_t *modperl_mgv_compile(pTHX_ apr_pool_t *p, -: 69: register const char *name) 2816: 70:{ 2816: 71: register const char *namend; 2816: 72: I32 len; 2816: 73: modperl_mgv_t *symbol = modperl_mgv_new(p); 2816: 74: modperl_mgv_t *mgv = symbol; -: 75: -: 76: /* @mgv = split '::', $name */ 43626: 77: for (namend = name; *namend; namend++) { 40810: 78: if (*namend == ':' && namend[1] == ':') { 1452: 79: if ((len = (namend - name)) > 0) { 1452: 80: modperl_mgv_get_next(mgv); 1452: 81: mgv->name = apr_palloc(p, len+3); 1452: 82: Copy(name, mgv->name, len, char); 1452: 83: mgv->name[len++] = ':'; 1452: 84: mgv->name[len++] = ':'; 1452: 85: mgv->name[len] = '\0'; 1452: 86: mgv->len = len; 1452: 87: modperl_mgv_hash(mgv); -: 88: } 1452: 89: name = namend + 2; -: 90: } -: 91: } -: 92: 2816: 93: modperl_mgv_get_next(mgv); -: 94: 2816: 95: mgv->len = namend - name; 2816: 96: mgv->name = apr_pstrndup(p, name, mgv->len); 2816: 97: modperl_mgv_hash(mgv); -: 98: 2816: 99: return symbol; -: 100:} -: 101: -: 102:void modperl_mgv_append(pTHX_ apr_pool_t *p, modperl_mgv_t *symbol, -: 103: const char *name) 1392: 104:{ 1392: 105: modperl_mgv_t *mgv = symbol; -: 106: 1392: 107: while (mgv->next) { 1392: 108: mgv = mgv->next; -: 109: } -: 110: 1392: 111: mgv->name = apr_pstrcat(p, mgv->name, "::", NULL); 1392: 112: mgv->len += 2; 1392: 113: modperl_mgv_hash(mgv); -: 114: 1392: 115: mgv->next = modperl_mgv_compile(aTHX_ p, name); -: 116:} -: 117: -: 118:/* faster replacement for gv_fetchpv() */ -: 119:GV *modperl_mgv_lookup(pTHX_ modperl_mgv_t *symbol) 2220: 120:{ 2220: 121: HV *stash = PL_defstash; 2220: 122: modperl_mgv_t *mgv; -: 123: 2220: 124: if (!symbol->hash) { -: 125: /* special case for MyClass->handler */ 117: 126: return (GV*)sv_2mortal(newSVpvn(symbol->name, symbol->len)); -: 127: } -: 128: 6290: 129: for (mgv = symbol; mgv; mgv = mgv->next) { 6290: 130: HE *he = hv_fetch_he(stash, mgv->name, mgv->len, mgv->hash); 6290: 131: if (he) { 6283: 132: if (mgv->next) { 2096: 133: stash = GvHV((GV *)HeVAL(he)); -: 134: } -: 135: else { 2096: 136: return (GV *)HeVAL(he); -: 137: } -: 138: } -: 139: else { 7: 140: return Nullgv; -: 141: } -: 142: } -: 143: #####: 144: return Nullgv; -: 145:} -: 146: -: 147:#ifdef USE_ITHREADS -: 148:MP_INLINE GV *modperl_mgv_lookup_autoload(pTHX_ modperl_mgv_t *symbol, -: 149: server_rec *s, apr_pool_t *p) 2043: 150:{ 2043: 151: MP_dSCFG(s); 2043: 152: GV *gv = modperl_mgv_lookup(aTHX_ symbol); -: 153: 2043: 154: if (gv || !MpSrvPARENT(scfg)) { 2036: 155: return gv; -: 156: } -: 157: -: 158: /* -: 159: * this VirtualHost has its own parent interpreter -: 160: * must require the module again with this server's THX -: 161: */ 7: 162: modperl_mgv_require_module(aTHX_ symbol, s, p); -: 163: 7: 164: return modperl_mgv_lookup(aTHX_ symbol); -: 165:} -: 166:#else -: 167:MP_INLINE GV *modperl_mgv_lookup_autoload(pTHX_ modperl_mgv_t *symbol, -: 168: server_rec *s, apr_pool_t *p) -: 169:{ -: 170: return modperl_mgv_lookup(aTHX_ symbol); -: 171:} -: 172:#endif -: 173: -: 174: -: 175:static void package2filename(apr_pool_t *p, const char *package, -: 176: char **filename, int *len) 641: 177:{ 641: 178: const char *s; 641: 179: char *d; -: 180: 641: 181: *filename = apr_palloc(p, (strlen(package)+4)*sizeof(char)); -: 182: 11708: 183: for (s = package, d = *filename; *s; s++, d++) { 11067: 184: if (*s == ':' && s[1] == ':') { 641: 185: *d = '/'; 641: 186: s++; -: 187: } -: 188: else { 10426: 189: *d = *s; -: 190: } -: 191: } 641: 192: *d++ = '.'; 641: 193: *d++ = 'p'; 641: 194: *d++ = 'm'; 641: 195: *d = '\0'; -: 196: 641: 197: *len = d - *filename; -: 198:} -: 199: -: 200:/* currently used for complex filters attributes parsing */ -: 201:/* XXX: may want to generalize it for any handlers */ -: 202:#define MODPERL_MGV_DEEP_RESOLVE(handler, p) \ -: 203: if (handler->attrs & MP_FILTER_HAS_INIT_HANDLER) { \ -: 204: modperl_filter_resolve_init_handler(aTHX_ handler, p); \ -: 205: } -: 206: -: 207:int modperl_mgv_resolve(pTHX_ modperl_handler_t *handler, -: 208: apr_pool_t *p, const char *name, int logfailure) 11718: 209:{ 11718: 210: CV *cv; 11718: 211: GV *gv; 11718: 212: HV *stash = Nullhv; 11718: 213: char *handler_name = "handler"; 11718: 214: char *tmp; -: 215: 11718: 216: if (MpHandlerANON(handler)) { -: 217: /* already resolved anonymous handler */ 1: 218: return 1; -: 219: } -: 220: 11717: 221: if (strnEQ(name, "sub ", 4)) { #####: 222: MP_TRACE_h(MP_FUNC, "handler is anonymous\n"); #####: 223: MpHandlerANON_On(handler); #####: 224: MpHandlerPARSED_On(handler); #####: 225: return 1; -: 226: } -: 227: 11717: 228: if ((tmp = strstr((char *)name, "->"))) { 101: 229: int package_len = strlen(name) - strlen(tmp); 101: 230: char *package = apr_pstrndup(p, name, package_len); -: 231: 101: 232: name = package; 101: 233: handler_name = &tmp[2]; -: 234: 101: 235: MpHandlerMETHOD_On(handler); -: 236: 101: 237: if (*package == '$') { 4: 238: GV *gv; 4: 239: SV *obj; -: 240: 4: 241: handler->mgv_obj = modperl_mgv_compile(aTHX_ p, package + 1); 4: 242: gv = modperl_mgv_lookup(aTHX_ handler->mgv_obj); 4: 243: obj = gv ? GvSV(gv) : Nullsv; -: 244: 4: 245: if (SvTRUE(obj)) { 4: 246: if (SvROK(obj) && sv_isobject(obj)) { 4: 247: stash = SvSTASH(SvRV(obj)); 4: 248: MpHandlerOBJECT_On(handler); 4: 249: MP_TRACE_h(MP_FUNC, "handler object %s isa %s\n", -: 250: package, HvNAME(stash)); -: 251: } -: 252: else { #####: 253: MP_TRACE_h(MP_FUNC, "%s is not an object, pv=%s\n", -: 254: package, SvPV_nolen(obj)); #####: 255: return 0; -: 256: } -: 257: } -: 258: else { #####: 259: MP_TRACE_h(MP_FUNC, "failed to thaw %s\n", package); #####: 260: return 0; -: 261: } -: 262: } -: 263: 4: 264: if (!stash) { 97: 265: if ((stash = gv_stashpvn(package, package_len, FALSE))) { 8: 266: MP_TRACE_h(MP_FUNC, "handler method %s isa %s\n", -: 267: name, HvNAME(stash)); -: 268: } -: 269: } -: 270: } -: 271: else { 11616: 272: if ((cv = get_cv(name, FALSE))) { 567: 273: handler->attrs = (U32)MP_CODE_ATTRS(cv); 567: 274: handler->mgv_cv = -: 275: modperl_mgv_compile(aTHX_ p, HvNAME(GvSTASH(CvGV(cv)))); 567: 276: modperl_mgv_append(aTHX_ p, handler->mgv_cv, GvNAME(CvGV(cv))); 567: 277: MpHandlerPARSED_On(handler); 567: 278: MODPERL_MGV_DEEP_RESOLVE(handler, p); 567: 279: return 1; -: 280: } -: 281: } -: 282: 8: 283: if (!stash && MpHandlerAUTOLOAD(handler)) { 641: 284: int len; 641: 285: char *filename; 641: 286: SV **svp; -: 287: 641: 288: package2filename(p, name, &filename, &len); 641: 289: svp = hv_fetch(GvHVn(PL_incgv), filename, len, 0); -: 290: 641: 291: if (!(svp && *svp != &PL_sv_undef)) { /* not in %INC */ 148: 292: MP_TRACE_h(MP_FUNC, -: 293: "package %s not in %INC, attempting to load '%s'\n", -: 294: name, filename); -: 295: 148: 296: if (modperl_require_module(aTHX_ name, logfailure)) { 147: 297: MP_TRACE_h(MP_FUNC, "loaded %s package\n", name); -: 298: } -: 299: else { 1: 300: if (logfailure) { -: 301: /* the caller doesn't handle the error checking */ #####: 302: Perl_croak(aTHX_ "failed to load %s package\n", name); -: 303: } -: 304: else { -: 305: /* the caller handles the error checking */ 1: 306: MP_TRACE_h(MP_FUNC, "failied to load %s package\n", name); 1: 307: return 0; -: 308: } -: 309: } -: 310: } -: 311: else { 493: 312: MP_TRACE_h(MP_FUNC, "package %s seems to be loaded\n" -: 313: " $INC{'%s')='%s';\n", -: 314: name, filename, SvPV_nolen(*svp)); -: 315: } -: 316: } -: 317: -: 318: /* try to lookup the stash only after loading the module, to avoid -: 319: * the case where a stash is autovivified by a user before the -: 320: * module was loaded, preventing from loading the module -: 321: */ 11137: 322: if (!(stash || (stash = gv_stashpv(name, FALSE)))) { 10324: 323: MP_TRACE_h(MP_FUNC, "%s's stash is not found\n", name); 10324: 324: return 0; -: 325: } -: 326: 825: 327: if ((gv = gv_fetchmethod(stash, handler_name)) && (cv = GvCV(gv))) { 825: 328: if (CvFLAGS(cv) & CVf_METHOD) { /* sub foo : method {}; */ 95: 329: MpHandlerMETHOD_On(handler); -: 330: } -: 331: 825: 332: if (MpHandlerMETHOD(handler) && !handler->mgv_obj) { 92: 333: modperl_mgv_new_name(handler->mgv_obj, p, HvNAME(stash)); -: 334: } -: 335: 825: 336: handler->attrs = (U32)MP_CODE_ATTRS(cv); -: 337: /* note: this is the real function after @ISA lookup */ 825: 338: handler->mgv_cv = modperl_mgv_compile(aTHX_ p, HvNAME(GvSTASH(gv))); 825: 339: modperl_mgv_append(aTHX_ p, handler->mgv_cv, handler_name); -: 340: 825: 341: MpHandlerPARSED_On(handler); 825: 342: MP_TRACE_h(MP_FUNC, "[%s] found `%s' in class `%s' as a %s\n", -: 343: modperl_pid_tid(p), -: 344: handler_name, HvNAME(stash), -: 345: MpHandlerMETHOD(handler) ? "method" : "function"); 825: 346: MODPERL_MGV_DEEP_RESOLVE(handler, p); 825: 347: return 1; -: 348: } -: 349: -: 350: /* at least modperl_hash_handlers needs to verify that an -: 351: * autoloaded-marked handler needs to be loaded, since it doesn't -: 352: * check success failure, and handlers marked to be autoloaded are -: 353: * the same as PerlModule and the failure should be fatal */ #####: 354: if (MpHandlerAUTOLOAD(handler)) { #####: 355: Perl_croak(aTHX_ "failed to resolve handler %s\n", name); -: 356: } -: 357: -: 358:#ifdef MP_TRACE -: 359: /* complain only if the class was actually loaded/created */ #####: 360: if (stash) { #####: 361: MP_TRACE_h(MP_FUNC, "`%s' not found in class `%s'\n", -: 362: handler_name, name); -: 363: } -: 364:#endif -: 365: #####: 366: return 0; -: 367:} -: 368: -: 369:modperl_mgv_t *modperl_mgv_last(modperl_mgv_t *symbol) #####: 370:{ #####: 371: while (symbol->next) { #####: 372: symbol = symbol->next; -: 373: } -: 374: #####: 375: return symbol; -: 376:} -: 377: -: 378:char *modperl_mgv_last_name(modperl_mgv_t *symbol) #####: 379:{ #####: 380: symbol = modperl_mgv_last(symbol); #####: 381: return symbol->name; -: 382:} -: 383: -: 384:char *modperl_mgv_as_string(pTHX_ modperl_mgv_t *symbol, -: 385: apr_pool_t *p, int package) 19: 386:{ 19: 387: char *string, *ptr; 19: 388: modperl_mgv_t *mgv; 19: 389: int len = 0; -: 390: 57: 391: for (mgv = symbol; (package ? mgv->next : mgv); mgv = mgv->next) { 38: 392: len += mgv->len; -: 393: } -: 394: 19: 395: ptr = string = apr_palloc(p, len+1); -: 396: 57: 397: for (mgv = symbol; (package ? mgv->next : mgv); mgv = mgv->next) { 38: 398: Copy(mgv->name, ptr, mgv->len, char); 38: 399: ptr += mgv->len; -: 400: } -: 401: 19: 402: if (package) { 19: 403: *(ptr-2) = '\0'; /* trim trailing :: */ -: 404: } -: 405: else { #####: 406: *ptr = '\0'; -: 407: } -: 408: 19: 409: return string; -: 410:} -: 411: -: 412:#ifdef USE_ITHREADS -: 413:int modperl_mgv_require_module(pTHX_ modperl_mgv_t *symbol, -: 414: server_rec *s, apr_pool_t *p) 7: 415:{ 7: 416: char *package = 7: 417: modperl_mgv_as_string(aTHX_ symbol, p, 1); -: 418: 7: 419: if (modperl_require_module(aTHX_ package, TRUE)) { 7: 420: MP_TRACE_h(MP_FUNC, "reloaded %s for server %s\n", -: 421: package, modperl_server_desc(s, p)); 7: 422: return TRUE; -: 423: } -: 424: #####: 425: return FALSE; -: 426:} -: 427:#endif -: 428: -: 429:/* precompute the hash(es) for handler names, preload handlers -: 430: * configured to be autoloaded */ -: 431:static void modperl_hash_handlers(pTHX_ apr_pool_t *p, server_rec *s, -: 432: MpAV *entry, void *data) 162084: 433:{ 162084: 434: MP_dSCFG(s); 162084: 435: int i; 162084: 436: modperl_handler_t **handlers; -: 437: 162084: 438: if (!entry) { 19896: 439: return; -: 440: } -: 441: 19896: 442: handlers = (modperl_handler_t **)entry->elts; -: 443: 29620: 444: for (i=0; i < entry->nelts; i++) { 21280: 445: modperl_handler_t *handler = handlers[i]; -: 446: 21280: 447: if (MpHandlerFAKE(handler)) { -: 448: /* do nothing with fake handlers */ -: 449: } 20840: 450: else if (MpHandlerPARSED(handler)) { -: 451:#ifdef USE_ITHREADS 9724: 452: if ((MpSrvPARENT(scfg) && MpSrvAUTOLOAD(scfg)) -: 453: && !modperl_mgv_lookup(aTHX_ handler->mgv_cv)) { -: 454: /* -: 455: * this VirtualHost has its own parent interpreter -: 456: * must require the module again with this server's THX -: 457: */ #####: 458: modperl_mgv_require_module(aTHX_ handler->mgv_cv, -: 459: s, p); -: 460: } -: 461:#endif 9724: 462: MP_TRACE_h(MP_FUNC, "%s already resolved in server %s\n", -: 463: handler->name, modperl_server_desc(s, p)); -: 464: } -: 465: else { 11116: 466: if (MpSrvAUTOLOAD(scfg)) { #####: 467: MpHandlerAUTOLOAD_On(handler); -: 468: } -: 469: 11116: 470: modperl_mgv_resolve(aTHX_ handler, p, handler->name, TRUE); -: 471: } -: 472: } -: 473:} -: 474: -: 475:static int modperl_hash_handlers_dir(apr_pool_t *p, server_rec *s, -: 476: void *cfg, char *d, void *data) 15300: 477:{ 15300: 478: int i; 15300: 479: modperl_config_dir_t *dir_cfg = (modperl_config_dir_t *)cfg; -: 480:#ifdef USE_ITHREADS 15300: 481: MP_dSCFG(s); 15300: 482: MP_dSCFG_dTHX; -: 483:#endif -: 484: 15300: 485: if (!dir_cfg) { 14668: 486: return 1; -: 487: } -: 488: 176016: 489: for (i=0; i < MP_HANDLER_NUM_PER_DIR; i++) { 161348: 490: modperl_hash_handlers(aTHX_ p, s, dir_cfg->handlers_per_dir[i], data); -: 491: } -: 492: 15300: 493: return 1; -: 494:} -: 495: -: 496:static int modperl_hash_handlers_srv(apr_pool_t *p, server_rec *s, -: 497: void *cfg, void *data) 92: 498:{ 92: 499: int i; 92: 500: modperl_config_srv_t *scfg = (modperl_config_srv_t *)cfg; 92: 501: MP_dSCFG_dTHX; -: 502: 368: 503: for (i=0; i < MP_HANDLER_NUM_PER_SRV; i++) { 276: 504: modperl_hash_handlers(aTHX_ p, s, -: 505: scfg->handlers_per_srv[i], data); -: 506: } -: 507: 276: 508: for (i=0; i < MP_HANDLER_NUM_PROCESS; i++) { 184: 509: modperl_hash_handlers(aTHX_ p, s, -: 510: scfg->handlers_process[i], data); -: 511: } -: 512: 184: 513: for (i=0; i < MP_HANDLER_NUM_CONNECTION; i++) { 92: 514: modperl_hash_handlers(aTHX_ p, s, -: 515: scfg->handlers_connection[i], data); -: 516: } -: 517: 276: 518: for (i=0; i < MP_HANDLER_NUM_FILES; i++) { 184: 519: modperl_hash_handlers(aTHX_ p, s, -: 520: scfg->handlers_files[i], data); -: 521: } -: 522: 92: 523: return 1; -: 524:} -: 525: -: 526:void modperl_mgv_hash_handlers(apr_pool_t *p, server_rec *s) 8: 527:{ 8: 528: ap_pcw_walk_config(p, s, &perl_module, NULL, -: 529: modperl_hash_handlers_dir, -: 530: modperl_hash_handlers_srv); -: 531:}