Annotation of embedaddon/nginx/src/http/modules/perl/ngx_http_perl_module.c, revision 1.1.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>