Annotation of embedaddon/nginx/src/http/modules/perl/ngx_http_perl_module.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (C) Igor Sysoev
! 4: * Copyright (C) Nginx, Inc.
! 5: */
! 6:
! 7:
! 8: #include <ngx_config.h>
! 9: #include <ngx_core.h>
! 10: #include <ngx_http.h>
! 11: #include <ngx_http_perl_module.h>
! 12:
! 13:
! 14: typedef struct {
! 15: PerlInterpreter *perl;
! 16: HV *nginx;
! 17: ngx_array_t *modules;
! 18: ngx_array_t *requires;
! 19: } ngx_http_perl_main_conf_t;
! 20:
! 21:
! 22: typedef struct {
! 23: SV *sub;
! 24: ngx_str_t handler;
! 25: } ngx_http_perl_loc_conf_t;
! 26:
! 27:
! 28: typedef struct {
! 29: SV *sub;
! 30: ngx_str_t handler;
! 31: } ngx_http_perl_variable_t;
! 32:
! 33:
! 34: #if (NGX_HTTP_SSI)
! 35: static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r,
! 36: ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params);
! 37: #endif
! 38:
! 39: static char *ngx_http_perl_init_interpreter(ngx_conf_t *cf,
! 40: ngx_http_perl_main_conf_t *pmcf);
! 41: static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf,
! 42: ngx_http_perl_main_conf_t *pmcf);
! 43: static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires,
! 44: ngx_log_t *log);
! 45: static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
! 46: HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv);
! 47: static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv);
! 48:
! 49: static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf);
! 50: static void *ngx_http_perl_create_main_conf(ngx_conf_t *cf);
! 51: static char *ngx_http_perl_init_main_conf(ngx_conf_t *cf, void *conf);
! 52: static void *ngx_http_perl_create_loc_conf(ngx_conf_t *cf);
! 53: static char *ngx_http_perl_merge_loc_conf(ngx_conf_t *cf, void *parent,
! 54: void *child);
! 55: static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
! 56: static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
! 57:
! 58: #if (NGX_HAVE_PERL_MULTIPLICITY)
! 59: static void ngx_http_perl_cleanup_perl(void *data);
! 60: #endif
! 61:
! 62: static ngx_int_t ngx_http_perl_init_worker(ngx_cycle_t *cycle);
! 63: static void ngx_http_perl_exit(ngx_cycle_t *cycle);
! 64:
! 65:
! 66: static ngx_command_t ngx_http_perl_commands[] = {
! 67:
! 68: { ngx_string("perl_modules"),
! 69: NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
! 70: ngx_conf_set_str_array_slot,
! 71: NGX_HTTP_MAIN_CONF_OFFSET,
! 72: offsetof(ngx_http_perl_main_conf_t, modules),
! 73: NULL },
! 74:
! 75: { ngx_string("perl_require"),
! 76: NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
! 77: ngx_conf_set_str_array_slot,
! 78: NGX_HTTP_MAIN_CONF_OFFSET,
! 79: offsetof(ngx_http_perl_main_conf_t, requires),
! 80: NULL },
! 81:
! 82: { ngx_string("perl"),
! 83: NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
! 84: ngx_http_perl,
! 85: NGX_HTTP_LOC_CONF_OFFSET,
! 86: 0,
! 87: NULL },
! 88:
! 89: { ngx_string("perl_set"),
! 90: NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
! 91: ngx_http_perl_set,
! 92: NGX_HTTP_LOC_CONF_OFFSET,
! 93: 0,
! 94: NULL },
! 95:
! 96: ngx_null_command
! 97: };
! 98:
! 99:
! 100: static ngx_http_module_t ngx_http_perl_module_ctx = {
! 101: ngx_http_perl_preconfiguration, /* preconfiguration */
! 102: NULL, /* postconfiguration */
! 103:
! 104: ngx_http_perl_create_main_conf, /* create main configuration */
! 105: ngx_http_perl_init_main_conf, /* init main configuration */
! 106:
! 107: NULL, /* create server configuration */
! 108: NULL, /* merge server configuration */
! 109:
! 110: ngx_http_perl_create_loc_conf, /* create location configuration */
! 111: ngx_http_perl_merge_loc_conf /* merge location configuration */
! 112: };
! 113:
! 114:
! 115: ngx_module_t ngx_http_perl_module = {
! 116: NGX_MODULE_V1,
! 117: &ngx_http_perl_module_ctx, /* module context */
! 118: ngx_http_perl_commands, /* module directives */
! 119: NGX_HTTP_MODULE, /* module type */
! 120: NULL, /* init master */
! 121: NULL, /* init module */
! 122: ngx_http_perl_init_worker, /* init process */
! 123: NULL, /* init thread */
! 124: NULL, /* exit thread */
! 125: NULL, /* exit process */
! 126: ngx_http_perl_exit, /* exit master */
! 127: NGX_MODULE_V1_PADDING
! 128: };
! 129:
! 130:
! 131: #if (NGX_HTTP_SSI)
! 132:
! 133: #define NGX_HTTP_PERL_SSI_SUB 0
! 134: #define NGX_HTTP_PERL_SSI_ARG 1
! 135:
! 136:
! 137: static ngx_http_ssi_param_t ngx_http_perl_ssi_params[] = {
! 138: { ngx_string("sub"), NGX_HTTP_PERL_SSI_SUB, 1, 0 },
! 139: { ngx_string("arg"), NGX_HTTP_PERL_SSI_ARG, 0, 1 },
! 140: { ngx_null_string, 0, 0, 0 }
! 141: };
! 142:
! 143: static ngx_http_ssi_command_t ngx_http_perl_ssi_command = {
! 144: ngx_string("perl"), ngx_http_perl_ssi, ngx_http_perl_ssi_params, 0, 0, 1
! 145: };
! 146:
! 147: #endif
! 148:
! 149:
! 150: static ngx_str_t ngx_null_name = ngx_null_string;
! 151: static HV *nginx_stash;
! 152:
! 153: #if (NGX_HAVE_PERL_MULTIPLICITY)
! 154: static ngx_uint_t ngx_perl_term;
! 155: #else
! 156: static PerlInterpreter *perl;
! 157: #endif
! 158:
! 159:
! 160: static void
! 161: ngx_http_perl_xs_init(pTHX)
! 162: {
! 163: newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__);
! 164:
! 165: nginx_stash = gv_stashpv("nginx", TRUE);
! 166: }
! 167:
! 168:
! 169: static ngx_int_t
! 170: ngx_http_perl_handler(ngx_http_request_t *r)
! 171: {
! 172: r->main->count++;
! 173:
! 174: ngx_http_perl_handle_request(r);
! 175:
! 176: return NGX_DONE;
! 177: }
! 178:
! 179:
! 180: void
! 181: ngx_http_perl_handle_request(ngx_http_request_t *r)
! 182: {
! 183: SV *sub;
! 184: ngx_int_t rc;
! 185: ngx_str_t uri, args, *handler;
! 186: ngx_http_perl_ctx_t *ctx;
! 187: ngx_http_perl_loc_conf_t *plcf;
! 188: ngx_http_perl_main_conf_t *pmcf;
! 189:
! 190: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler");
! 191:
! 192: ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
! 193:
! 194: if (ctx == NULL) {
! 195: ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
! 196: if (ctx == NULL) {
! 197: ngx_http_finalize_request(r, NGX_ERROR);
! 198: return;
! 199: }
! 200:
! 201: ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
! 202: }
! 203:
! 204: pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
! 205:
! 206: {
! 207:
! 208: dTHXa(pmcf->perl);
! 209: PERL_SET_CONTEXT(pmcf->perl);
! 210:
! 211: if (ctx->next == NULL) {
! 212: plcf = ngx_http_get_module_loc_conf(r, ngx_http_perl_module);
! 213: sub = plcf->sub;
! 214: handler = &plcf->handler;
! 215:
! 216: } else {
! 217: sub = ctx->next;
! 218: handler = &ngx_null_name;
! 219: ctx->next = NULL;
! 220: }
! 221:
! 222: rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler,
! 223: NULL);
! 224:
! 225: }
! 226:
! 227: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 228: "perl handler done: %i", rc);
! 229:
! 230: if (rc == NGX_DONE) {
! 231: ngx_http_finalize_request(r, rc);
! 232: return;
! 233: }
! 234:
! 235: if (rc > 600) {
! 236: rc = NGX_OK;
! 237: }
! 238:
! 239: if (ctx->redirect_uri.len) {
! 240: uri = ctx->redirect_uri;
! 241: args = ctx->redirect_args;
! 242:
! 243: } else {
! 244: uri.len = 0;
! 245: }
! 246:
! 247: ctx->filename.data = NULL;
! 248: ctx->redirect_uri.len = 0;
! 249:
! 250: if (ctx->done || ctx->next) {
! 251: ngx_http_finalize_request(r, NGX_DONE);
! 252: return;
! 253: }
! 254:
! 255: if (uri.len) {
! 256: ngx_http_internal_redirect(r, &uri, &args);
! 257: ngx_http_finalize_request(r, NGX_DONE);
! 258: return;
! 259: }
! 260:
! 261: if (rc == NGX_OK || rc == NGX_HTTP_OK) {
! 262: ngx_http_send_special(r, NGX_HTTP_LAST);
! 263: ctx->done = 1;
! 264: }
! 265:
! 266: ngx_http_finalize_request(r, rc);
! 267: }
! 268:
! 269:
! 270: void
! 271: ngx_http_perl_sleep_handler(ngx_http_request_t *r)
! 272: {
! 273: ngx_event_t *wev;
! 274:
! 275: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 276: "perl sleep handler");
! 277:
! 278: wev = r->connection->write;
! 279:
! 280: if (wev->timedout) {
! 281: wev->timedout = 0;
! 282: ngx_http_perl_handle_request(r);
! 283: return;
! 284: }
! 285:
! 286: if (ngx_handle_write_event(wev, 0) != NGX_OK) {
! 287: ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
! 288: }
! 289: }
! 290:
! 291:
! 292: static ngx_int_t
! 293: ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
! 294: uintptr_t data)
! 295: {
! 296: ngx_http_perl_variable_t *pv = (ngx_http_perl_variable_t *) data;
! 297:
! 298: ngx_int_t rc;
! 299: ngx_str_t value;
! 300: ngx_http_perl_ctx_t *ctx;
! 301: ngx_http_perl_main_conf_t *pmcf;
! 302:
! 303: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 304: "perl variable handler");
! 305:
! 306: ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
! 307:
! 308: if (ctx == NULL) {
! 309: ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
! 310: if (ctx == NULL) {
! 311: return NGX_ERROR;
! 312: }
! 313:
! 314: ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
! 315: }
! 316:
! 317: pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
! 318:
! 319: value.data = NULL;
! 320:
! 321: {
! 322:
! 323: dTHXa(pmcf->perl);
! 324: PERL_SET_CONTEXT(pmcf->perl);
! 325:
! 326: rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL,
! 327: &pv->handler, &value);
! 328:
! 329: }
! 330:
! 331: if (value.data) {
! 332: v->len = value.len;
! 333: v->valid = 1;
! 334: v->no_cacheable = 0;
! 335: v->not_found = 0;
! 336: v->data = value.data;
! 337:
! 338: } else {
! 339: v->not_found = 1;
! 340: }
! 341:
! 342: ctx->filename.data = NULL;
! 343: ctx->redirect_uri.len = 0;
! 344:
! 345: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 346: "perl variable done");
! 347:
! 348: return rc;
! 349: }
! 350:
! 351:
! 352: #if (NGX_HTTP_SSI)
! 353:
! 354: static ngx_int_t
! 355: ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx,
! 356: ngx_str_t **params)
! 357: {
! 358: SV *sv, **asv;
! 359: ngx_int_t rc;
! 360: ngx_str_t *handler, **args;
! 361: ngx_uint_t i;
! 362: ngx_http_perl_ctx_t *ctx;
! 363: ngx_http_perl_main_conf_t *pmcf;
! 364:
! 365: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 366: "perl ssi handler");
! 367:
! 368: ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
! 369:
! 370: if (ctx == NULL) {
! 371: ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
! 372: if (ctx == NULL) {
! 373: return NGX_ERROR;
! 374: }
! 375:
! 376: ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
! 377: }
! 378:
! 379: pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
! 380:
! 381: ctx->ssi = ssi_ctx;
! 382:
! 383: handler = params[NGX_HTTP_PERL_SSI_SUB];
! 384: handler->data[handler->len] = '\0';
! 385:
! 386: {
! 387:
! 388: dTHXa(pmcf->perl);
! 389: PERL_SET_CONTEXT(pmcf->perl);
! 390:
! 391: #if 0
! 392:
! 393: /* the code is disabled to force the precompiled perl code using only */
! 394:
! 395: ngx_http_perl_eval_anon_sub(aTHX_ handler, &sv);
! 396:
! 397: if (sv == &PL_sv_undef) {
! 398: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 399: "eval_pv(\"%V\") failed", handler);
! 400: return NGX_ERROR;
! 401: }
! 402:
! 403: if (sv == NULL) {
! 404: sv = newSVpvn((char *) handler->data, handler->len);
! 405: }
! 406:
! 407: #endif
! 408:
! 409: sv = newSVpvn((char *) handler->data, handler->len);
! 410:
! 411: args = ¶ms[NGX_HTTP_PERL_SSI_ARG];
! 412:
! 413: if (args) {
! 414:
! 415: for (i = 0; args[i]; i++) { /* void */ }
! 416:
! 417: asv = ngx_pcalloc(r->pool, (i + 1) * sizeof(SV *));
! 418:
! 419: if (asv == NULL) {
! 420: SvREFCNT_dec(sv);
! 421: return NGX_ERROR;
! 422: }
! 423:
! 424: asv[0] = (SV *) i;
! 425:
! 426: for (i = 0; args[i]; i++) {
! 427: asv[i + 1] = newSVpvn((char *) args[i]->data, args[i]->len);
! 428: }
! 429:
! 430: } else {
! 431: asv = NULL;
! 432: }
! 433:
! 434: rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler,
! 435: NULL);
! 436:
! 437: SvREFCNT_dec(sv);
! 438:
! 439: }
! 440:
! 441: ctx->filename.data = NULL;
! 442: ctx->redirect_uri.len = 0;
! 443: ctx->ssi = NULL;
! 444:
! 445: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl ssi done");
! 446:
! 447: return rc;
! 448: }
! 449:
! 450: #endif
! 451:
! 452:
! 453: static char *
! 454: ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf)
! 455: {
! 456: ngx_str_t *m;
! 457: ngx_uint_t i;
! 458: #if (NGX_HAVE_PERL_MULTIPLICITY)
! 459: ngx_pool_cleanup_t *cln;
! 460:
! 461: cln = ngx_pool_cleanup_add(cf->pool, 0);
! 462: if (cln == NULL) {
! 463: return NGX_CONF_ERROR;
! 464: }
! 465:
! 466: #endif
! 467:
! 468: #ifdef NGX_PERL_MODULES
! 469: if (pmcf->modules == NGX_CONF_UNSET_PTR) {
! 470:
! 471: pmcf->modules = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t));
! 472: if (pmcf->modules == NULL) {
! 473: return NGX_CONF_ERROR;
! 474: }
! 475:
! 476: m = ngx_array_push(pmcf->modules);
! 477: if (m == NULL) {
! 478: return NGX_CONF_ERROR;
! 479: }
! 480:
! 481: ngx_str_set(m, NGX_PERL_MODULES);
! 482: }
! 483: #endif
! 484:
! 485: if (pmcf->modules != NGX_CONF_UNSET_PTR) {
! 486: m = pmcf->modules->elts;
! 487: for (i = 0; i < pmcf->modules->nelts; i++) {
! 488: if (ngx_conf_full_name(cf->cycle, &m[i], 0) != NGX_OK) {
! 489: return NGX_CONF_ERROR;
! 490: }
! 491: }
! 492: }
! 493:
! 494: #if !(NGX_HAVE_PERL_MULTIPLICITY)
! 495:
! 496: if (perl) {
! 497:
! 498: if (ngx_set_environment(cf->cycle, NULL) == NULL) {
! 499: return NGX_CONF_ERROR;
! 500: }
! 501:
! 502: if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log)
! 503: != NGX_OK)
! 504: {
! 505: return NGX_CONF_ERROR;
! 506: }
! 507:
! 508: pmcf->perl = perl;
! 509: pmcf->nginx = nginx_stash;
! 510:
! 511: return NGX_CONF_OK;
! 512: }
! 513:
! 514: #endif
! 515:
! 516: if (nginx_stash == NULL) {
! 517: PERL_SYS_INIT(&ngx_argc, &ngx_argv);
! 518: }
! 519:
! 520: pmcf->perl = ngx_http_perl_create_interpreter(cf, pmcf);
! 521:
! 522: if (pmcf->perl == NULL) {
! 523: return NGX_CONF_ERROR;
! 524: }
! 525:
! 526: pmcf->nginx = nginx_stash;
! 527:
! 528: #if (NGX_HAVE_PERL_MULTIPLICITY)
! 529:
! 530: cln->handler = ngx_http_perl_cleanup_perl;
! 531: cln->data = pmcf->perl;
! 532:
! 533: #else
! 534:
! 535: perl = pmcf->perl;
! 536:
! 537: #endif
! 538:
! 539: return NGX_CONF_OK;
! 540: }
! 541:
! 542:
! 543: static PerlInterpreter *
! 544: ngx_http_perl_create_interpreter(ngx_conf_t *cf,
! 545: ngx_http_perl_main_conf_t *pmcf)
! 546: {
! 547: int n;
! 548: STRLEN len;
! 549: SV *sv;
! 550: char *ver, **embedding;
! 551: ngx_str_t *m;
! 552: ngx_uint_t i;
! 553: PerlInterpreter *perl;
! 554:
! 555: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter");
! 556:
! 557: if (ngx_set_environment(cf->cycle, NULL) == NULL) {
! 558: return NULL;
! 559: }
! 560:
! 561: perl = perl_alloc();
! 562: if (perl == NULL) {
! 563: ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_alloc() failed");
! 564: return NULL;
! 565: }
! 566:
! 567: {
! 568:
! 569: dTHXa(perl);
! 570: PERL_SET_CONTEXT(perl);
! 571:
! 572: perl_construct(perl);
! 573:
! 574: #ifdef PERL_EXIT_DESTRUCT_END
! 575: PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
! 576: #endif
! 577:
! 578: n = (pmcf->modules != NGX_CONF_UNSET_PTR) ? pmcf->modules->nelts * 2 : 0;
! 579:
! 580: embedding = ngx_palloc(cf->pool, (4 + n) * sizeof(char *));
! 581: if (embedding == NULL) {
! 582: goto fail;
! 583: }
! 584:
! 585: embedding[0] = "";
! 586:
! 587: if (n++) {
! 588: m = pmcf->modules->elts;
! 589: for (i = 0; i < pmcf->modules->nelts; i++) {
! 590: embedding[2 * i + 1] = "-I";
! 591: embedding[2 * i + 2] = (char *) m[i].data;
! 592: }
! 593: }
! 594:
! 595: embedding[n++] = "-Mnginx";
! 596: embedding[n++] = "-e";
! 597: embedding[n++] = "0";
! 598:
! 599: n = perl_parse(perl, ngx_http_perl_xs_init, n, embedding, NULL);
! 600:
! 601: if (n != 0) {
! 602: ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_parse() failed: %d", n);
! 603: goto fail;
! 604: }
! 605:
! 606: sv = get_sv("nginx::VERSION", FALSE);
! 607: ver = SvPV(sv, len);
! 608:
! 609: if (ngx_strcmp(ver, NGINX_VERSION) != 0) {
! 610: ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
! 611: "version " NGINX_VERSION " of nginx.pm is required, "
! 612: "but %s was found", ver);
! 613: goto fail;
! 614: }
! 615:
! 616: if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log) != NGX_OK) {
! 617: goto fail;
! 618: }
! 619:
! 620: }
! 621:
! 622: return perl;
! 623:
! 624: fail:
! 625:
! 626: (void) perl_destruct(perl);
! 627:
! 628: perl_free(perl);
! 629:
! 630: return NULL;
! 631: }
! 632:
! 633:
! 634: static ngx_int_t
! 635: ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log)
! 636: {
! 637: u_char *err;
! 638: STRLEN len;
! 639: ngx_str_t *script;
! 640: ngx_uint_t i;
! 641:
! 642: if (requires == NGX_CONF_UNSET_PTR) {
! 643: return NGX_OK;
! 644: }
! 645:
! 646: script = requires->elts;
! 647: for (i = 0; i < requires->nelts; i++) {
! 648:
! 649: require_pv((char *) script[i].data);
! 650:
! 651: if (SvTRUE(ERRSV)) {
! 652:
! 653: err = (u_char *) SvPV(ERRSV, len);
! 654: while (--len && (err[len] == CR || err[len] == LF)) { /* void */ }
! 655:
! 656: ngx_log_error(NGX_LOG_EMERG, log, 0,
! 657: "require_pv(\"%s\") failed: \"%*s\"",
! 658: script[i].data, len + 1, err);
! 659:
! 660: return NGX_ERROR;
! 661: }
! 662: }
! 663:
! 664: return NGX_OK;
! 665: }
! 666:
! 667:
! 668: static ngx_int_t
! 669: ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub,
! 670: SV **args, ngx_str_t *handler, ngx_str_t *rv)
! 671: {
! 672: SV *sv;
! 673: int n, status;
! 674: char *line;
! 675: u_char *err;
! 676: STRLEN len, n_a;
! 677: ngx_uint_t i;
! 678: ngx_connection_t *c;
! 679:
! 680: dSP;
! 681:
! 682: status = 0;
! 683:
! 684: ENTER;
! 685: SAVETMPS;
! 686:
! 687: PUSHMARK(sp);
! 688:
! 689: sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx));
! 690: XPUSHs(sv);
! 691:
! 692: if (args) {
! 693: EXTEND(sp, (intptr_t) args[0]);
! 694:
! 695: for (i = 1; i <= (ngx_uint_t) args[0]; i++) {
! 696: PUSHs(sv_2mortal(args[i]));
! 697: }
! 698: }
! 699:
! 700: PUTBACK;
! 701:
! 702: c = r->connection;
! 703:
! 704: n = call_sv(sub, G_EVAL);
! 705:
! 706: SPAGAIN;
! 707:
! 708: if (n) {
! 709: if (rv == NULL) {
! 710: status = POPi;
! 711:
! 712: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
! 713: "call_sv: %d", status);
! 714:
! 715: } else {
! 716: line = SvPVx(POPs, n_a);
! 717: rv->len = n_a;
! 718:
! 719: rv->data = ngx_pnalloc(r->pool, n_a);
! 720: if (rv->data == NULL) {
! 721: return NGX_ERROR;
! 722: }
! 723:
! 724: ngx_memcpy(rv->data, line, n_a);
! 725: }
! 726: }
! 727:
! 728: PUTBACK;
! 729:
! 730: FREETMPS;
! 731: LEAVE;
! 732:
! 733: /* check $@ */
! 734:
! 735: if (SvTRUE(ERRSV)) {
! 736:
! 737: err = (u_char *) SvPV(ERRSV, len);
! 738: while (--len && (err[len] == CR || err[len] == LF)) { /* void */ }
! 739:
! 740: ngx_log_error(NGX_LOG_ERR, c->log, 0,
! 741: "call_sv(\"%V\") failed: \"%*s\"", handler, len + 1, err);
! 742:
! 743: if (rv) {
! 744: return NGX_ERROR;
! 745: }
! 746:
! 747: return NGX_HTTP_INTERNAL_SERVER_ERROR;
! 748: }
! 749:
! 750: if (n != 1) {
! 751: ngx_log_error(NGX_LOG_ALERT, c->log, 0,
! 752: "call_sv(\"%V\") returned %d results", handler, n);
! 753: status = NGX_OK;
! 754: }
! 755:
! 756: if (rv) {
! 757: return NGX_OK;
! 758: }
! 759:
! 760: return (ngx_int_t) status;
! 761: }
! 762:
! 763:
! 764: static void
! 765: ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv)
! 766: {
! 767: u_char *p;
! 768:
! 769: for (p = handler->data; *p; p++) {
! 770: if (*p != ' ' && *p != '\t' && *p != CR && *p != LF) {
! 771: break;
! 772: }
! 773: }
! 774:
! 775: if (ngx_strncmp(p, "sub ", 4) == 0
! 776: || ngx_strncmp(p, "sub{", 4) == 0
! 777: || ngx_strncmp(p, "use ", 4) == 0)
! 778: {
! 779: *sv = eval_pv((char *) p, FALSE);
! 780:
! 781: /* eval_pv() does not set ERRSV on failure */
! 782:
! 783: return;
! 784: }
! 785:
! 786: *sv = NULL;
! 787: }
! 788:
! 789:
! 790: static void *
! 791: ngx_http_perl_create_main_conf(ngx_conf_t *cf)
! 792: {
! 793: ngx_http_perl_main_conf_t *pmcf;
! 794:
! 795: pmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_main_conf_t));
! 796: if (pmcf == NULL) {
! 797: return NULL;
! 798: }
! 799:
! 800: pmcf->modules = NGX_CONF_UNSET_PTR;
! 801: pmcf->requires = NGX_CONF_UNSET_PTR;
! 802:
! 803: return pmcf;
! 804: }
! 805:
! 806:
! 807: static char *
! 808: ngx_http_perl_init_main_conf(ngx_conf_t *cf, void *conf)
! 809: {
! 810: ngx_http_perl_main_conf_t *pmcf = conf;
! 811:
! 812: if (pmcf->perl == NULL) {
! 813: if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
! 814: return NGX_CONF_ERROR;
! 815: }
! 816: }
! 817:
! 818: return NGX_CONF_OK;
! 819: }
! 820:
! 821:
! 822: #if (NGX_HAVE_PERL_MULTIPLICITY)
! 823:
! 824: static void
! 825: ngx_http_perl_cleanup_perl(void *data)
! 826: {
! 827: PerlInterpreter *perl = data;
! 828:
! 829: PERL_SET_CONTEXT(perl);
! 830:
! 831: (void) perl_destruct(perl);
! 832:
! 833: perl_free(perl);
! 834:
! 835: if (ngx_perl_term) {
! 836: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "perl term");
! 837:
! 838: PERL_SYS_TERM();
! 839: }
! 840: }
! 841:
! 842: #endif
! 843:
! 844:
! 845: static ngx_int_t
! 846: ngx_http_perl_preconfiguration(ngx_conf_t *cf)
! 847: {
! 848: #if (NGX_HTTP_SSI)
! 849: ngx_int_t rc;
! 850: ngx_http_ssi_main_conf_t *smcf;
! 851:
! 852: smcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_ssi_filter_module);
! 853:
! 854: rc = ngx_hash_add_key(&smcf->commands, &ngx_http_perl_ssi_command.name,
! 855: &ngx_http_perl_ssi_command, NGX_HASH_READONLY_KEY);
! 856:
! 857: if (rc != NGX_OK) {
! 858: if (rc == NGX_BUSY) {
! 859: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 860: "conflicting SSI command \"%V\"",
! 861: &ngx_http_perl_ssi_command.name);
! 862: }
! 863:
! 864: return NGX_ERROR;
! 865: }
! 866: #endif
! 867:
! 868: return NGX_OK;
! 869: }
! 870:
! 871:
! 872: static void *
! 873: ngx_http_perl_create_loc_conf(ngx_conf_t *cf)
! 874: {
! 875: ngx_http_perl_loc_conf_t *plcf;
! 876:
! 877: plcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_loc_conf_t));
! 878: if (plcf == NULL) {
! 879: return NULL;
! 880: }
! 881:
! 882: /*
! 883: * set by ngx_pcalloc():
! 884: *
! 885: * plcf->handler = { 0, NULL };
! 886: */
! 887:
! 888: return plcf;
! 889: }
! 890:
! 891:
! 892: static char *
! 893: ngx_http_perl_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
! 894: {
! 895: ngx_http_perl_loc_conf_t *prev = parent;
! 896: ngx_http_perl_loc_conf_t *conf = child;
! 897:
! 898: if (conf->sub == NULL) {
! 899: conf->sub = prev->sub;
! 900: conf->handler = prev->handler;
! 901: }
! 902:
! 903: return NGX_CONF_OK;
! 904: }
! 905:
! 906:
! 907: static char *
! 908: ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 909: {
! 910: ngx_http_perl_loc_conf_t *plcf = conf;
! 911:
! 912: ngx_str_t *value;
! 913: ngx_http_core_loc_conf_t *clcf;
! 914: ngx_http_perl_main_conf_t *pmcf;
! 915:
! 916: value = cf->args->elts;
! 917:
! 918: if (plcf->handler.data) {
! 919: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 920: "duplicate perl handler \"%V\"", &value[1]);
! 921: return NGX_CONF_ERROR;
! 922: }
! 923:
! 924: pmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_perl_module);
! 925:
! 926: if (pmcf->perl == NULL) {
! 927: if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
! 928: return NGX_CONF_ERROR;
! 929: }
! 930: }
! 931:
! 932: plcf->handler = value[1];
! 933:
! 934: {
! 935:
! 936: dTHXa(pmcf->perl);
! 937: PERL_SET_CONTEXT(pmcf->perl);
! 938:
! 939: ngx_http_perl_eval_anon_sub(aTHX_ &value[1], &plcf->sub);
! 940:
! 941: if (plcf->sub == &PL_sv_undef) {
! 942: ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
! 943: "eval_pv(\"%V\") failed", &value[1]);
! 944: return NGX_CONF_ERROR;
! 945: }
! 946:
! 947: if (plcf->sub == NULL) {
! 948: plcf->sub = newSVpvn((char *) value[1].data, value[1].len);
! 949: }
! 950:
! 951: }
! 952:
! 953: clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
! 954: clcf->handler = ngx_http_perl_handler;
! 955:
! 956: return NGX_CONF_OK;
! 957: }
! 958:
! 959:
! 960: static char *
! 961: ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 962: {
! 963: ngx_int_t index;
! 964: ngx_str_t *value;
! 965: ngx_http_variable_t *v;
! 966: ngx_http_perl_variable_t *pv;
! 967: ngx_http_perl_main_conf_t *pmcf;
! 968:
! 969: value = cf->args->elts;
! 970:
! 971: if (value[1].data[0] != '$') {
! 972: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
! 973: "invalid variable name \"%V\"", &value[1]);
! 974: return NGX_CONF_ERROR;
! 975: }
! 976:
! 977: value[1].len--;
! 978: value[1].data++;
! 979:
! 980: v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE);
! 981: if (v == NULL) {
! 982: return NGX_CONF_ERROR;
! 983: }
! 984:
! 985: pv = ngx_palloc(cf->pool, sizeof(ngx_http_perl_variable_t));
! 986: if (pv == NULL) {
! 987: return NGX_CONF_ERROR;
! 988: }
! 989:
! 990: index = ngx_http_get_variable_index(cf, &value[1]);
! 991: if (index == NGX_ERROR) {
! 992: return NGX_CONF_ERROR;
! 993: }
! 994:
! 995: pmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_perl_module);
! 996:
! 997: if (pmcf->perl == NULL) {
! 998: if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
! 999: return NGX_CONF_ERROR;
! 1000: }
! 1001: }
! 1002:
! 1003: pv->handler = value[2];
! 1004:
! 1005: {
! 1006:
! 1007: dTHXa(pmcf->perl);
! 1008: PERL_SET_CONTEXT(pmcf->perl);
! 1009:
! 1010: ngx_http_perl_eval_anon_sub(aTHX_ &value[2], &pv->sub);
! 1011:
! 1012: if (pv->sub == &PL_sv_undef) {
! 1013: ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
! 1014: "eval_pv(\"%V\") failed", &value[2]);
! 1015: return NGX_CONF_ERROR;
! 1016: }
! 1017:
! 1018: if (pv->sub == NULL) {
! 1019: pv->sub = newSVpvn((char *) value[2].data, value[2].len);
! 1020: }
! 1021:
! 1022: }
! 1023:
! 1024: v->get_handler = ngx_http_perl_variable;
! 1025: v->data = (uintptr_t) pv;
! 1026:
! 1027: return NGX_CONF_OK;
! 1028: }
! 1029:
! 1030:
! 1031: static ngx_int_t
! 1032: ngx_http_perl_init_worker(ngx_cycle_t *cycle)
! 1033: {
! 1034: ngx_http_perl_main_conf_t *pmcf;
! 1035:
! 1036: pmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_perl_module);
! 1037:
! 1038: if (pmcf) {
! 1039: dTHXa(pmcf->perl);
! 1040: PERL_SET_CONTEXT(pmcf->perl);
! 1041:
! 1042: /* set worker's $$ */
! 1043:
! 1044: sv_setiv(GvSV(gv_fetchpv("$", TRUE, SVt_PV)), (I32) ngx_pid);
! 1045: }
! 1046:
! 1047: return NGX_OK;
! 1048: }
! 1049:
! 1050:
! 1051: static void
! 1052: ngx_http_perl_exit(ngx_cycle_t *cycle)
! 1053: {
! 1054: #if (NGX_HAVE_PERL_MULTIPLICITY)
! 1055:
! 1056: /*
! 1057: * the master exit hook is run before global pool cleanup,
! 1058: * therefore just set flag here
! 1059: */
! 1060:
! 1061: ngx_perl_term = 1;
! 1062:
! 1063: #else
! 1064:
! 1065: if (nginx_stash) {
! 1066: ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, "perl term");
! 1067:
! 1068: (void) perl_destruct(perl);
! 1069:
! 1070: perl_free(perl);
! 1071:
! 1072: PERL_SYS_TERM();
! 1073: }
! 1074:
! 1075: #endif
! 1076: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>