-: 0:Source:modperl_handler.c -: 0:Object:modperl_handler.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:#ifdef USE_ITHREADS -: 19:static -: 20:char *modperl_coderef2text(pTHX_ apr_pool_t *p, CV *cv) 6: 21:{ 6: 22: dSP; 6: 23: int count; 6: 24: SV *bdeparse; 6: 25: char *text; -: 26: -: 27: /* B::Deparse >= 0.61 needed for blessed code references. -: 28: * 0.6 works fine for non-blessed code refs. -: 29: * notice that B::Deparse is not CPAN-updatable. -: 30: * 0.61 is available starting from 5.8.0 -: 31: */ 6: 32: load_module(PERL_LOADMOD_NOIMPORT, -: 33: newSVpvn("B::Deparse", 10), -: 34: newSVnv(SvOBJECT((SV*)cv) ? 0.61 : 0.60)); -: 35: 6: 36: ENTER; 6: 37: SAVETMPS; -: 38: -: 39: /* create the B::Deparse object */ 6: 40: PUSHMARK(sp); 6: 41: XPUSHs(sv_2mortal(newSVpvn("B::Deparse", 10))); 6: 42: PUTBACK; 6: 43: count = call_method("new", G_SCALAR); 6: 44: SPAGAIN; 6: 45: if (count != 1) { #####: 46: Perl_croak(aTHX_ "Unexpected return value from B::Deparse::new\n"); -: 47: } 6: 48: if (SvTRUE(ERRSV)) { #####: 49: Perl_croak(aTHX_ "error: %s", SvPVX(ERRSV)); -: 50: } 6: 51: bdeparse = POPs; -: 52: 6: 53: PUSHMARK(sp); 6: 54: XPUSHs(bdeparse); 6: 55: XPUSHs(sv_2mortal(newRV_inc((SV*)cv))); 6: 56: PUTBACK; 6: 57: count = call_method("coderef2text", G_SCALAR); 6: 58: SPAGAIN; 6: 59: if (count != 1) { #####: 60: Perl_croak(aTHX_ "Unexpected return value from " -: 61: "B::Deparse::coderef2text\n"); -: 62: } 6: 63: if (SvTRUE(ERRSV)) { #####: 64: Perl_croak(aTHX_ "error: %s", SvPVX(ERRSV)); -: 65: } -: 66: -: 67: { 6: 68: STRLEN n_a; 6: 69: text = apr_pstrcat(p, "sub ", POPpx, NULL); -: 70: } -: 71: 6: 72: PUTBACK; -: 73: 6: 74: FREETMPS; 6: 75: LEAVE; -: 76: 6: 77: return text; -: 78:} -: 79:#endif -: 80: -: 81:modperl_handler_t *modperl_handler_new(apr_pool_t *p, const char *name) 1967: 82:{ 1967: 83: modperl_handler_t *handler = 3934: 84: (modperl_handler_t *)apr_pcalloc(p, sizeof(*handler)); -: 85: 1967: 86: switch (*name) { -: 87: case '+': #####: 88: ++name; #####: 89: MpHandlerAUTOLOAD_On(handler); #####: 90: break; -: 91: case '-': #####: 92: ++name; -: 93: /* XXX: currently a noop; should disable autoload of given handler -: 94: * if PerlOptions +AutoLoad is configured -: 95: * see: modperl_hash_handlers in modperl_mgv.c -: 96: */ #####: 97: MpHandlerAUTOLOAD_Off(handler); -: 98: break; -: 99: } -: 100: 1967: 101: handler->cv = NULL; 1967: 102: handler->name = name; 1967: 103: MP_TRACE_h(MP_FUNC, "[%s] new handler %s\n", -: 104: modperl_pid_tid(p), handler->name); -: 105: 1967: 106: return handler; -: 107:} -: 108: -: 109: -: 110:static -: 111:modperl_handler_t *modperl_handler_new_anon(pTHX_ apr_pool_t *p, CV *cv) 6: 112:{ 6: 113: modperl_handler_t *handler = 12: 114: (modperl_handler_t *)apr_pcalloc(p, sizeof(*handler)); 6: 115: MpHandlerPARSED_On(handler); 6: 116: MpHandlerANON_On(handler); -: 117: -: 118:#ifdef USE_ITHREADS -: 119: /* XXX: perhaps we can optimize this further. At the moment when -: 120: * perl w/ ithreads is used, we always deparse the anon subs -: 121: * before storing them and then eval them each time they are -: 122: * used. This is because we don't know whether the same perl that -: 123: * compiled the anonymous sub is used to run it. -: 124: * -: 125: * A possible optimization is to cache the CV and use that cached -: 126: * value w/ or w/o deparsing at all if: -: 127: * -: 128: * - the mpm is non-threaded mpm and no +Clone/+Parent is used -: 129: * (i.e. no perl pools) (no deparsing is needed at all) -: 130: * -: 131: * - the interpreter that has supplied the anon cv is the same -: 132: * interpreter that is executing that cv (requires storing aTHX -: 133: * in the handler's struct) (need to deparse in case the -: 134: * interpreter gets switched) -: 135: * -: 136: * - other cases? -: 137: */ 6: 138: handler->cv = NULL; 6: 139: handler->name = modperl_coderef2text(aTHX_ p, cv); 6: 140: MP_TRACE_h(MP_FUNC, "[%s] new deparsed anon handler:\n%s\n", -: 141: modperl_pid_tid(p), handler->name); -: 142:#else -: 143: /* it's safe to cache and later use the cv, since the same perl -: 144: * interpeter is always used */ -: 145: handler->cv = cv; -: 146: handler->name = NULL; -: 147: MP_TRACE_h(MP_FUNC, "[%s] new cached cv anon handler\n", -: 148: modperl_pid_tid(p)); -: 149:#endif -: 150: 6: 151: return handler; -: 152:} -: 153: -: 154:MP_INLINE -: 155:const char *modperl_handler_name(modperl_handler_t *handler) #####: 156:{ -: 157: /* a handler containing an anonymous sub doesn't have a normal sub -: 158: * name */ #####: 159: return handler->name ? handler->name : "anonymous sub"; -: 160:} -: 161: -: 162: -: 163:int modperl_handler_resolve(pTHX_ modperl_handler_t **handp, -: 164: apr_pool_t *p, server_rec *s) 2050: 165:{ 2050: 166: int duped=0; 2050: 167: modperl_handler_t *handler = *handp; -: 168: -: 169:#ifdef USE_ITHREADS 2050: 170: if (p && !MpHandlerPARSED(handler) && !MpHandlerDYNAMIC(handler)) { -: 171: /* -: 172: * cannot update the handler structure at request time without -: 173: * locking, so just copy it -: 174: */ 582: 175: handler = *handp = modperl_handler_dup(p, handler); 582: 176: duped = 1; -: 177: } -: 178:#endif -: 179: 2050: 180: MP_TRACE_h_do(MpHandler_dump_flags(handler, handler->name)); -: 181: 2050: 182: if (!MpHandlerPARSED(handler)) { 596: 183: apr_pool_t *rp = duped ? p : s->process->pconf; 596: 184: MpHandlerAUTOLOAD_On(handler); -: 185: 596: 186: MP_TRACE_h(MP_FUNC, -: 187: "[%s %s] handler %s was not compiled at startup, " -: 188: "attempting to resolve using %s pool 0x%lx\n", -: 189: modperl_pid_tid(p), -: 190: modperl_server_desc(s, p), -: 191: handler->name, -: 192: duped ? "current" : "server conf", -: 193: (unsigned long)rp); -: 194: 596: 195: if (!modperl_mgv_resolve(aTHX_ handler, rp, handler->name, FALSE)) { 1: 196: ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, -: 197: "failed to resolve handler `%s'", -: 198: handler->name); 1: 199: return HTTP_INTERNAL_SERVER_ERROR; -: 200: } -: 201: } -: 202: 2049: 203: return OK; -: 204:} -: 205: -: 206:modperl_handler_t *modperl_handler_dup(apr_pool_t *p, -: 207: modperl_handler_t *h) 583: 208:{ 583: 209: MP_TRACE_h(MP_FUNC, "dup handler %s\n", h->name); 583: 210: return modperl_handler_new(p, h->name); -: 211:} -: 212: -: 213:int modperl_handler_equal(modperl_handler_t *h1, modperl_handler_t *h2) #####: 214:{ #####: 215: if (h1->mgv_cv && h2->mgv_cv) { #####: 216: return modperl_mgv_equal(h1->mgv_cv, h2->mgv_cv); -: 217: } #####: 218: return strEQ(h1->name, h2->name); -: 219:} -: 220: -: 221:MpAV *modperl_handler_array_merge(apr_pool_t *p, MpAV *base_a, MpAV *add_a) 22: 222:{ 22: 223: int i, j; 22: 224: modperl_handler_t **base_h, **add_h, **mrg_h; 22: 225: MpAV *mrg_a; -: 226: 22: 227: if (!add_a) { 20: 228: return base_a; -: 229: } -: 230: 2: 231: if (!base_a) { 2: 232: return add_a; -: 233: } -: 234: #####: 235: mrg_a = apr_array_copy(p, base_a); -: 236: #####: 237: mrg_h = (modperl_handler_t **)mrg_a->elts; #####: 238: base_h = (modperl_handler_t **)base_a->elts; #####: 239: add_h = (modperl_handler_t **)add_a->elts; -: 240: #####: 241: for (i=0; inelts; i++) { #####: 242: for (j=0; jnelts; j++) { #####: 243: if (modperl_handler_equal(base_h[i], add_h[j])) { #####: 244: MP_TRACE_d(MP_FUNC, "both base and new config contain %s\n", -: 245: add_h[j]->name); -: 246: } -: 247: else { #####: 248: modperl_handler_array_push(mrg_a, add_h[j]); #####: 249: MP_TRACE_d(MP_FUNC, "base does not contain %s\n", -: 250: add_h[j]->name); -: 251: } -: 252: } -: 253: } -: 254: #####: 255: return mrg_a; -: 256:} -: 257: -: 258:void modperl_handler_make_args(pTHX_ AV **avp, ...) 1686: 259:{ 1686: 260: va_list args; -: 261: 1686: 262: if (!*avp) { 1686: 263: *avp = newAV(); /* XXX: cache an intialized AV* per-request */ -: 264: } -: 265: 1686: 266: va_start(args, avp); -: 267: 5852: 268: for (;;) { 3769: 269: char *classname = va_arg(args, char *); 3769: 270: void *ptr; 3769: 271: SV *sv; -: 272: 3769: 273: if (classname == NULL) { 2083: 274: break; -: 275: } -: 276: 2083: 277: ptr = va_arg(args, void *); -: 278: 2083: 279: switch (*classname) { -: 280: case 'A': 2083: 281: if (strEQ(classname, "APR::Table")) { 32: 282: sv = modperl_hash_tie(aTHX_ classname, Nullsv, ptr); 32: 283: break; -: 284: } -: 285: case 'I': 2051: 286: if (strEQ(classname, "IV")) { #####: 287: sv = ptr ? newSViv((IV)ptr) : &PL_sv_undef; #####: 288: break; -: 289: } -: 290: case 'P': 2051: 291: if (strEQ(classname, "PV")) { #####: 292: sv = ptr ? newSVpv((char *)ptr, 0) : &PL_sv_undef; #####: 293: break; -: 294: } -: 295: case 'H': 2051: 296: if (strEQ(classname, "HV")) { #####: 297: sv = newRV_noinc((SV*)ptr); #####: 298: break; -: 299: } -: 300: default: 2051: 301: sv = modperl_ptr2obj(aTHX_ classname, ptr); 2083: 302: break; -: 303: } -: 304: 2083: 305: av_push(*avp, sv); -: 306: } -: 307: -: 308: va_end(args); -: 309:} -: 310: -: 311:#define set_desc(dtype) \ -: 312: if (desc) *desc = modperl_handler_desc_##dtype(idx) -: 313: -: 314:#define check_modify(dtype) \ -: 315:if ((action > MP_HANDLER_ACTION_GET) && rcfg) { \ -: 316: dTHX; \ -: 317: Perl_croak(aTHX_ "too late to modify %s handlers", \ -: 318: modperl_handler_desc_##dtype(idx)); \ -: 319:} -: 320: -: 321:/* -: 322: * generic function to lookup handlers for use in modperl_callback(), -: 323: * $r->{push,set,get}_handlers, $s->{push,set,get}_handlers -: 324: * $s->push/set at startup time are the same as configuring Perl*Handlers -: 325: * $r->push/set at request time will create entries in r->request_config -: 326: * push will first merge with configured handlers, unless an entry -: 327: * in r->request_config already exists. in this case, push or set has -: 328: * already been called for the given handler, -: 329: * r->request_config entries then override those in r->per_dir_config -: 330: */ -: 331: -: 332:MpAV **modperl_handler_lookup_handlers(modperl_config_dir_t *dcfg, -: 333: modperl_config_srv_t *scfg, -: 334: modperl_config_req_t *rcfg, -: 335: apr_pool_t *p, -: 336: int type, int idx, -: 337: modperl_handler_action_e action, -: 338: const char **desc) 6351: 339:{ 6351: 340: MpAV **avp = NULL, **ravp = NULL; -: 341: 6351: 342: switch (type) { -: 343: case MP_HANDLER_TYPE_PER_DIR: 3096: 344: avp = &dcfg->handlers_per_dir[idx]; 3096: 345: if (rcfg) { 3096: 346: ravp = &rcfg->handlers_per_dir[idx]; -: 347: } 3096: 348: set_desc(per_dir); 2940: 349: break; -: 350: case MP_HANDLER_TYPE_PER_SRV: 2407: 351: avp = &scfg->handlers_per_srv[idx]; 2407: 352: if (rcfg) { 2407: 353: ravp = &rcfg->handlers_per_srv[idx]; -: 354: } 2407: 355: set_desc(per_srv); 1314: 356: break; -: 357: case MP_HANDLER_TYPE_PRE_CONNECTION: 409: 358: avp = &scfg->handlers_pre_connection[idx]; 409: 359: check_modify(pre_connection); 409: 360: set_desc(pre_connection); 407: 361: break; -: 362: case MP_HANDLER_TYPE_CONNECTION: 405: 363: avp = &scfg->handlers_connection[idx]; 405: 364: check_modify(connection); 405: 365: set_desc(connection); 405: 366: break; -: 367: case MP_HANDLER_TYPE_FILES: 24: 368: avp = &scfg->handlers_files[idx]; 24: 369: check_modify(files); 24: 370: set_desc(files); 16: 371: break; -: 372: case MP_HANDLER_TYPE_PROCESS: 10: 373: avp = &scfg->handlers_process[idx]; 10: 374: check_modify(files); 10: 375: set_desc(process); -: 376: break; -: 377: }; -: 378: 6351: 379: if (!avp) { -: 380: /* should never happen */ -: 381:#if 0 -: 382: fprintf(stderr, "PANIC: no such handler type: %d\n", type); -: 383:#endif #####: 384: return NULL; -: 385: } -: 386: 6351: 387: switch (action) { -: 388: case MP_HANDLER_ACTION_GET: -: 389: /* just a lookup */ 11: 390: break; -: 391: case MP_HANDLER_ACTION_PUSH: 11: 392: if (ravp && !*ravp) { 6: 393: if (*avp) { -: 394: /* merge with existing configured handlers */ 5: 395: *ravp = apr_array_copy(p, *avp); -: 396: } -: 397: else { -: 398: /* no request handlers have been previously pushed or set */ 1: 399: *ravp = modperl_handler_array_new(p); -: 400: } -: 401: } 5: 402: else if (!*avp) { -: 403: /* directly modify the configuration at startup time */ #####: 404: *avp = modperl_handler_array_new(p); -: 405: } #####: 406: break; -: 407: case MP_HANDLER_ACTION_SET: 5: 408: if (ravp) { 5: 409: if (*ravp) { -: 410: /* wipe out existing pushed/set request handlers */ 2: 411: (*ravp)->nelts = 0; -: 412: } -: 413: else { -: 414: /* no request handlers have been previously pushed or set */ 3: 415: *ravp = modperl_handler_array_new(p); -: 416: } -: 417: } #####: 418: else if (*avp) { -: 419: /* wipe out existing configuration, only at startup time */ #####: 420: (*avp)->nelts = 0; -: 421: } -: 422: else { -: 423: /* no configured handlers for this phase */ #####: 424: *avp = modperl_handler_array_new(p); -: 425: } -: 426: break; -: 427: } -: 428: 6351: 429: return (ravp && *ravp) ? ravp : avp; -: 430:} -: 431: -: 432:MpAV **modperl_handler_get_handlers(request_rec *r, conn_rec *c, server_rec *s, -: 433: apr_pool_t *p, const char *name, -: 434: modperl_handler_action_e action) 17: 435:{ 17: 436: MP_dSCFG(s); 17: 437: MP_dDCFG; 17: 438: MP_dRCFG; -: 439: 17: 440: int idx, type; -: 441: 17: 442: if (!r) { -: 443: /* so $s->{push,set}_handlers can configured request-time handlers */ #####: 444: dcfg = modperl_config_dir_get_defaults(s); -: 445: } -: 446: 17: 447: if ((idx = modperl_handler_lookup(name, &type)) == DECLINED) { #####: 448: return FALSE; -: 449: } -: 450: 17: 451: return modperl_handler_lookup_handlers(dcfg, scfg, rcfg, p, -: 452: type, idx, -: 453: action, NULL); -: 454:} -: 455: -: 456:modperl_handler_t *modperl_handler_new_from_sv(pTHX_ apr_pool_t *p, SV *sv) 39: 457:{ 39: 458: char *name = NULL; 39: 459: GV *gv; -: 460: 39: 461: if (SvROK(sv)) { 36: 462: sv = SvRV(sv); -: 463: } -: 464: 39: 465: switch (SvTYPE(sv)) { -: 466: case SVt_PV: 2: 467: name = SvPVX(sv); 2: 468: return modperl_handler_new(p, apr_pstrdup(p, name)); 36: 469: break; -: 470: case SVt_PVCV: 36: 471: if (CvANON((CV*)sv)) { 6: 472: return modperl_handler_new_anon(aTHX_ p, (CV*)sv); -: 473: } 30: 474: if (!(gv = CvGV((CV*)sv))) { #####: 475: Perl_croak(aTHX_ "can't resolve the code reference"); -: 476: } 30: 477: name = apr_pstrcat(p, HvNAME(GvSTASH(gv)), "::", GvNAME(gv), NULL); 30: 478: return modperl_handler_new(p, apr_pstrdup(p, name)); 1: 479: break; -: 480: }; -: 481: 1: 482: return NULL; -: 483:} -: 484: -: 485:int modperl_handler_push_handlers(pTHX_ apr_pool_t *p, -: 486: MpAV *handlers, SV *sv) 22: 487:{ 22: 488: modperl_handler_t *handler = modperl_handler_new_from_sv(aTHX_ p, sv); -: 489: 22: 490: if (handler) { 21: 491: modperl_handler_array_push(handlers, handler); 21: 492: return TRUE; -: 493: } -: 494: 1: 495: MP_TRACE_h(MP_FUNC, "unable to push_handler 0x%lx\n", -: 496: (unsigned long)sv); -: 497: 1: 498: return FALSE; -: 499:} -: 500: -: 501:/* convert array header of modperl_handlers_t's to AV ref of CV refs */ -: 502:SV *modperl_handler_perl_get_handlers(pTHX_ MpAV **handp, apr_pool_t *p) 1: 503:{ 1: 504: AV *av = newAV(); 1: 505: int i; 1: 506: modperl_handler_t **handlers; -: 507: 1: 508: if (!(handp && *handp)) { #####: 509: return &PL_sv_undef; -: 510: } -: 511: 1: 512: av_extend(av, (*handp)->nelts - 1); -: 513: 1: 514: handlers = (modperl_handler_t **)(*handp)->elts; -: 515: 3: 516: for (i=0; i<(*handp)->nelts; i++) { 2: 517: modperl_handler_t *handler = NULL; 2: 518: GV *gv; -: 519: 2: 520: if (MpHandlerPARSED(handlers[i])) { 1: 521: handler = handlers[i]; -: 522: } -: 523: else { -: 524:#ifdef USE_ITHREADS 1: 525: if (!MpHandlerDYNAMIC(handlers[i])) { 1: 526: handler = modperl_handler_dup(p, handlers[i]); -: 527: } -: 528:#endif 1: 529: if (!handler) { #####: 530: handler = handlers[i]; -: 531: } -: 532: 1: 533: if (!modperl_mgv_resolve(aTHX_ handler, p, handler->name, TRUE)) { #####: 534: MP_TRACE_h(MP_FUNC, "failed to resolve handler %s\n", -: 535: handler->name); -: 536: } -: 537: -: 538: } -: 539: 2: 540: if (handler->mgv_cv) { 2: 541: if ((gv = modperl_mgv_lookup(aTHX_ handler->mgv_cv))) { 2: 542: CV *cv = modperl_mgv_cv(gv); 2: 543: av_push(av, newRV_inc((SV*)cv)); -: 544: } -: 545: } -: 546: else { #####: 547: av_push(av, newSVpv(handler->name, 0)); -: 548: } -: 549: } -: 550: 1: 551: return newRV_noinc((SV*)av); -: 552:} -: 553: -: 554:#define push_sv_handler \ -: 555: if ((modperl_handler_push_handlers(aTHX_ p, *handlers, sv))) { \ -: 556: MpHandlerDYNAMIC_On(modperl_handler_array_last(*handlers)); \ -: 557: } -: 558: -: 559:/* allow push/set of single cv ref or array ref of cv refs */ -: 560:int modperl_handler_perl_add_handlers(pTHX_ -: 561: request_rec *r, -: 562: conn_rec *c, -: 563: server_rec *s, -: 564: apr_pool_t *p, -: 565: const char *name, -: 566: SV *sv, -: 567: modperl_handler_action_e action) 16: 568:{ 16: 569: I32 i; 16: 570: AV *av = Nullav; 16: 571: MpAV **handlers = -: 572: modperl_handler_get_handlers(r, c, s, 16: 573: p, name, action); -: 574: 16: 575: if (!(handlers && *handlers)) { #####: 576: return FALSE; -: 577: } -: 578: 16: 579: if (SvROK(sv) && (SvTYPE(SvRV(sv)) == SVt_PVAV)) { 5: 580: av = (AV*)SvRV(sv); -: 581: 16: 582: for (i=0; i <= AvFILL(av); i++) { 11: 583: sv = *av_fetch(av, i, FALSE); 11: 584: push_sv_handler; -: 585: } -: 586: } -: 587: else { 11: 588: push_sv_handler; -: 589: } -: 590: 16: 591: return TRUE; -: 592:}