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