blob: b11320dad6643f5e4a96a0a7ea2ffc6e1b2643b9 [file] [log] [blame]
Igor Sysoev9bf11aa2006-01-16 14:56:53 +00001
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
13typedef struct {
Igor Sysoev9bf11aa2006-01-16 14:56:53 +000014 PerlInterpreter *perl;
Igor Sysoev36d520d2006-11-26 15:35:02 +000015 HV *nginx;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +000016 ngx_str_t modules;
17 ngx_array_t requires;
18} ngx_http_perl_main_conf_t;
19
20
21typedef struct {
22 SV *sub;
23 ngx_str_t handler;
24} ngx_http_perl_loc_conf_t;
25
26
27typedef struct {
28 SV *sub;
29 ngx_str_t handler;
30} ngx_http_perl_variable_t;
31
32
Igor Sysoevafd7ec52006-05-29 17:28:12 +000033typedef struct {
34 SV *sv;
35 PerlInterpreter *perl;
36} ngx_http_perl_cleanup_t;
37
38
Igor Sysoevcce886c2006-02-22 19:41:39 +000039#if (NGX_HTTP_SSI)
Igor Sysoev9bf11aa2006-01-16 14:56:53 +000040static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r,
41 ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params);
Igor Sysoevcce886c2006-02-22 19:41:39 +000042#endif
43
Igor Sysoeve7733242006-12-12 20:59:24 +000044static void ngx_http_perl_sleep_handler(ngx_http_request_t *r);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +000045static char *ngx_http_perl_init_interpreter(ngx_conf_t *cf,
46 ngx_http_perl_main_conf_t *pmcf);
Igor Sysoev8885f872007-01-20 19:26:48 +000047static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf,
48 ngx_http_perl_main_conf_t *pmcf);
Igor Sysoevafd7ec52006-05-29 17:28:12 +000049static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires,
Igor Sysoev3338cfd2006-05-11 14:43:47 +000050 ngx_log_t *log);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +000051static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
Igor Sysoev36d520d2006-11-26 15:35:02 +000052 HV *nginx, SV *sub, ngx_str_t **args, ngx_str_t *handler, ngx_str_t *rv);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +000053static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv);
54
55static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf);
56static void *ngx_http_perl_create_main_conf(ngx_conf_t *cf);
57static char *ngx_http_perl_init_main_conf(ngx_conf_t *cf, void *conf);
58static void *ngx_http_perl_create_loc_conf(ngx_conf_t *cf);
59static char *ngx_http_perl_merge_loc_conf(ngx_conf_t *cf, void *parent,
60 void *child);
61static char *ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd,
62 void *conf);
63static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
64static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +000065
Igor Sysoevf9b7db52006-11-26 14:35:27 +000066#if (NGX_HAVE_PERL_MULTIPLICITY)
67static void ngx_http_perl_cleanup_perl(void *data);
68#endif
Igor Sysoev9bf11aa2006-01-16 14:56:53 +000069
70
71static ngx_command_t ngx_http_perl_commands[] = {
72
73 { ngx_string("perl_modules"),
74 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
75 ngx_conf_set_str_slot,
76 NGX_HTTP_MAIN_CONF_OFFSET,
77 offsetof(ngx_http_perl_main_conf_t, modules),
78 NULL },
79
80 { ngx_string("perl_require"),
81 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
82 ngx_http_perl_require,
83 NGX_HTTP_MAIN_CONF_OFFSET,
84 0,
85 NULL },
86
Igor Sysoev9bf11aa2006-01-16 14:56:53 +000087 { ngx_string("perl"),
Igor Sysoev55269a72006-12-14 22:13:33 +000088 NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
Igor Sysoev9bf11aa2006-01-16 14:56:53 +000089 ngx_http_perl,
90 NGX_HTTP_LOC_CONF_OFFSET,
91 0,
92 NULL },
93
94 { ngx_string("perl_set"),
95 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
96 ngx_http_perl_set,
97 NGX_HTTP_LOC_CONF_OFFSET,
98 0,
99 NULL },
100
101 ngx_null_command
102};
103
104
105static ngx_http_module_t ngx_http_perl_module_ctx = {
106 ngx_http_perl_preconfiguration, /* preconfiguration */
107 NULL, /* postconfiguration */
108
109 ngx_http_perl_create_main_conf, /* create main configuration */
110 ngx_http_perl_init_main_conf, /* init main configuration */
111
112 NULL, /* create server configuration */
113 NULL, /* merge server configuration */
114
115 ngx_http_perl_create_loc_conf, /* create location configuration */
116 ngx_http_perl_merge_loc_conf /* merge location configuration */
117};
118
119
120ngx_module_t ngx_http_perl_module = {
121 NGX_MODULE_V1,
122 &ngx_http_perl_module_ctx, /* module context */
123 ngx_http_perl_commands, /* module directives */
124 NGX_HTTP_MODULE, /* module type */
125 NULL, /* init master */
126 NULL, /* init module */
127 NULL, /* init process */
128 NULL, /* init thread */
129 NULL, /* exit thread */
130 NULL, /* exit process */
131 NULL, /* exit master */
132 NGX_MODULE_V1_PADDING
133};
134
135
Igor Sysoevcce886c2006-02-22 19:41:39 +0000136#if (NGX_HTTP_SSI)
137
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000138#define NGX_HTTP_PERL_SSI_SUB 0
139#define NGX_HTTP_PERL_SSI_ARG 1
140
141
142static ngx_http_ssi_param_t ngx_http_perl_ssi_params[] = {
143 { ngx_string("sub"), NGX_HTTP_PERL_SSI_SUB, 1, 0 },
144 { ngx_string("arg"), NGX_HTTP_PERL_SSI_ARG, 0, 1 },
145 { ngx_null_string, 0, 0, 0 }
146};
147
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000148static ngx_http_ssi_command_t ngx_http_perl_ssi_command = {
Igor Sysoev8f125582006-07-28 15:16:17 +0000149 ngx_string("perl"), ngx_http_perl_ssi, ngx_http_perl_ssi_params, 0, 0, 1
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000150};
151
Igor Sysoevcce886c2006-02-22 19:41:39 +0000152#endif
153
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000154
Igor Sysoevda173ab2006-08-30 10:39:17 +0000155static ngx_str_t ngx_null_name = ngx_null_string;
156
157
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000158static HV *nginx_stash;
159
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000160static void
161ngx_http_perl_xs_init(pTHX)
162{
163 newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000164
165 nginx_stash = gv_stashpv("nginx", TRUE);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000166}
167
168
169static ngx_int_t
170ngx_http_perl_handler(ngx_http_request_t *r)
171{
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000172 /* TODO: Win32 */
173 if (r->zero_in_uri) {
174 return NGX_HTTP_NOT_FOUND;
175 }
176
Igor Sysoevda173ab2006-08-30 10:39:17 +0000177 ngx_http_perl_handle_request(r);
178
179 return NGX_DONE;
Igor Sysoev6d16e1e2006-04-05 13:40:54 +0000180}
181
182
Igor Sysoevda173ab2006-08-30 10:39:17 +0000183void
Igor Sysoev6d16e1e2006-04-05 13:40:54 +0000184ngx_http_perl_handle_request(ngx_http_request_t *r)
185{
Igor Sysoevda173ab2006-08-30 10:39:17 +0000186 SV *sub;
Igor Sysoev6d16e1e2006-04-05 13:40:54 +0000187 ngx_int_t rc;
Igor Sysoevda173ab2006-08-30 10:39:17 +0000188 ngx_str_t uri, args, *handler;
Igor Sysoev6d16e1e2006-04-05 13:40:54 +0000189 ngx_http_perl_ctx_t *ctx;
190 ngx_http_perl_loc_conf_t *plcf;
191 ngx_http_perl_main_conf_t *pmcf;
192
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000193 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler");
194
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000195 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
196
197 if (ctx == NULL) {
198 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
199 if (ctx == NULL) {
Igor Sysoevda173ab2006-08-30 10:39:17 +0000200 ngx_http_finalize_request(r, NGX_ERROR);
Igor Sysoev6043c802007-01-12 20:26:39 +0000201 return;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000202 }
203
204 ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
205 }
206
207 pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
208
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000209 {
210
Igor Sysoevf9b7db52006-11-26 14:35:27 +0000211 dTHXa(pmcf->perl);
Igor Sysoev36d520d2006-11-26 15:35:02 +0000212 PERL_SET_CONTEXT(pmcf->perl);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000213
Igor Sysoevda173ab2006-08-30 10:39:17 +0000214 if (ctx->next == NULL) {
215 plcf = ngx_http_get_module_loc_conf(r, ngx_http_perl_module);
216 sub = plcf->sub;
217 handler = &plcf->handler;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000218
Igor Sysoevda173ab2006-08-30 10:39:17 +0000219 } else {
220 sub = ctx->next;
221 handler = &ngx_null_name;
222 ctx->next = NULL;
223 }
224
Igor Sysoev36d520d2006-11-26 15:35:02 +0000225 rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler,
226 NULL);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000227
228 }
229
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000230 if (rc > 600) {
231 rc = NGX_OK;
232 }
233
234 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
235 "perl handler done: %i", rc);
236
237 if (ctx->redirect_uri.len) {
238 uri = ctx->redirect_uri;
239 args = ctx->redirect_args;
Igor Sysoev6d16e1e2006-04-05 13:40:54 +0000240
241 } else {
242 uri.len = 0;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000243 }
244
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000245 ctx->filename.data = NULL;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000246 ctx->redirect_uri.len = 0;
247
Igor Sysoeve7733242006-12-12 20:59:24 +0000248 if (ctx->sleep) {
249 ngx_add_timer(r->connection->write, (ngx_msec_t) ctx->sleep);
250 r->write_event_handler = ngx_http_perl_sleep_handler;
251 ctx->sleep = 0;
252 }
253
Igor Sysoevda173ab2006-08-30 10:39:17 +0000254 if (ctx->done || ctx->next) {
255 return;
256 }
257
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000258 if (uri.len) {
Igor Sysoev6d16e1e2006-04-05 13:40:54 +0000259 ngx_http_internal_redirect(r, &uri, &args);
260 return;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000261 }
262
263 if (rc == NGX_OK || rc == NGX_HTTP_OK) {
Igor Sysoev6d16e1e2006-04-05 13:40:54 +0000264 ngx_http_send_special(r, NGX_HTTP_LAST);
Igor Sysoevda173ab2006-08-30 10:39:17 +0000265 ctx->done = 1;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000266 }
267
Igor Sysoev6d16e1e2006-04-05 13:40:54 +0000268 ngx_http_finalize_request(r, rc);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000269}
270
271
Igor Sysoeve7733242006-12-12 20:59:24 +0000272static void
273ngx_http_perl_sleep_handler(ngx_http_request_t *r)
274{
Igor Sysoevdf88a812006-12-13 12:30:57 +0000275 ngx_event_t *wev;
276
Igor Sysoeve7733242006-12-12 20:59:24 +0000277 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
278 "perl sleep handler");
279
Igor Sysoevdf88a812006-12-13 12:30:57 +0000280 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_ERROR) {
289 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
290 }
Igor Sysoeve7733242006-12-12 20:59:24 +0000291}
292
293
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000294static ngx_int_t
295ngx_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);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000317 }
318
Igor Sysoevf9b7db52006-11-26 14:35:27 +0000319 pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
320
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000321 value.data = NULL;
322
323 {
324
Igor Sysoevf9b7db52006-11-26 14:35:27 +0000325 dTHXa(pmcf->perl);
Igor Sysoev36d520d2006-11-26 15:35:02 +0000326 PERL_SET_CONTEXT(pmcf->perl);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000327
Igor Sysoev36d520d2006-11-26 15:35:02 +0000328 rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL,
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000329 &pv->handler, &value);
330
331 }
332
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000333 if (value.data) {
334 v->len = value.len;
335 v->valid = 1;
336 v->no_cachable = 0;
337 v->not_found = 0;
338 v->data = value.data;
339
340 } else {
341 v->not_found = 1;
342 }
343
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000344 ctx->filename.data = NULL;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000345 ctx->redirect_uri.len = 0;
346
Igor Sysoevac6e1c12006-11-25 23:27:34 +0000347 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
348 "perl variable done");
349
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000350 return rc;
351}
352
353
Igor Sysoevcce886c2006-02-22 19:41:39 +0000354#if (NGX_HTTP_SSI)
355
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000356static ngx_int_t
357ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx,
358 ngx_str_t **params)
359{
360 SV *sv;
361 ngx_int_t rc;
362 ngx_str_t *handler;
363 ngx_http_perl_ctx_t *ctx;
364 ngx_http_perl_main_conf_t *pmcf;
365
366 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
367 "perl ssi handler");
368
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000369 ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
370
371 if (ctx == NULL) {
372 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
373 if (ctx == NULL) {
374 return NGX_ERROR;
375 }
376
377 ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
378 }
379
Igor Sysoevf9b7db52006-11-26 14:35:27 +0000380 pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000381
382 ctx->ssi = ssi_ctx;
383
384 handler = params[NGX_HTTP_PERL_SSI_SUB];
385 handler->data[handler->len] = '\0';
386
387 {
388
Igor Sysoevf9b7db52006-11-26 14:35:27 +0000389 dTHXa(pmcf->perl);
Igor Sysoev36d520d2006-11-26 15:35:02 +0000390 PERL_SET_CONTEXT(pmcf->perl);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000391
Igor Sysoev6f134cc2006-05-23 14:54:58 +0000392#if 0
393
394 /* the code is disabled to force the precompiled perl code using only */
395
396 ngx_http_perl_eval_anon_sub(aTHX_ handler, &sv);
397
398 if (sv == &PL_sv_undef) {
399 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
400 "eval_pv(\"%V\") failed", handler);
401 return NGX_ERROR;
402 }
403
404 if (sv == NULL) {
405 sv = newSVpvn((char *) handler->data, handler->len);
406 }
407
408#endif
409
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000410 sv = newSVpvn((char *) handler->data, handler->len);
411
Igor Sysoev36d520d2006-11-26 15:35:02 +0000412 rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv,
413 &params[NGX_HTTP_PERL_SSI_ARG],
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000414 handler, NULL);
415
416 SvREFCNT_dec(sv);
417
418 }
419
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000420 ctx->filename.data = NULL;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000421 ctx->redirect_uri.len = 0;
422 ctx->ssi = NULL;
423
Igor Sysoevac6e1c12006-11-25 23:27:34 +0000424 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl ssi done");
425
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000426 return rc;
427}
428
Igor Sysoevcce886c2006-02-22 19:41:39 +0000429#endif
430
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000431
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000432static char *
433ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf)
434{
Igor Sysoevf9b7db52006-11-26 14:35:27 +0000435#if (NGX_HAVE_PERL_MULTIPLICITY)
Igor Sysoevafd7ec52006-05-29 17:28:12 +0000436 ngx_pool_cleanup_t *cln;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000437
438 cln = ngx_pool_cleanup_add(cf->pool, 0);
439 if (cln == NULL) {
440 return NGX_CONF_ERROR;
441 }
442
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000443#else
444 static PerlInterpreter *perl;
445#endif
446
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000447#ifdef NGX_PERL_MODULES
448 if (pmcf->modules.data == NULL) {
449 pmcf->modules.data = NGX_PERL_MODULES;
450 }
451#endif
452
Igor Sysoev4ecb4d72006-04-21 12:06:44 +0000453 if (pmcf->modules.data) {
454 if (ngx_conf_full_name(cf->cycle, &pmcf->modules) != NGX_OK) {
455 return NGX_CONF_ERROR;
456 }
Igor Sysoev6d16e1e2006-04-05 13:40:54 +0000457 }
458
Igor Sysoevf9b7db52006-11-26 14:35:27 +0000459#if !(NGX_HAVE_PERL_MULTIPLICITY)
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000460
461 if (perl) {
Igor Sysoeve5e4c002007-04-18 11:28:11 +0000462
463 if (ngx_set_environment(cf->cycle, NULL) == NULL) {
464 return NGX_CONF_ERROR;
465 }
466
Igor Sysoevafd7ec52006-05-29 17:28:12 +0000467 if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log)
468 != NGX_OK)
469 {
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000470 return NGX_CONF_ERROR;
471 }
472
473 pmcf->perl = perl;
Igor Sysoevde92bcc2007-04-18 09:23:35 +0000474 pmcf->nginx = nginx_stash;
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000475
476 return NGX_CONF_OK;
477 }
478
479#endif
480
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000481 PERL_SYS_INIT(&ngx_argc, &ngx_argv);
482
Igor Sysoev8885f872007-01-20 19:26:48 +0000483 pmcf->perl = ngx_http_perl_create_interpreter(cf, pmcf);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000484
485 if (pmcf->perl == NULL) {
486 PERL_SYS_TERM();
487 return NGX_CONF_ERROR;
488 }
489
Igor Sysoev36d520d2006-11-26 15:35:02 +0000490 pmcf->nginx = nginx_stash;
491
Igor Sysoevf9b7db52006-11-26 14:35:27 +0000492#if (NGX_HAVE_PERL_MULTIPLICITY)
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000493
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000494 cln->handler = ngx_http_perl_cleanup_perl;
495 cln->data = pmcf->perl;
496
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000497#else
498
499 perl = pmcf->perl;
500
501#endif
502
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000503 return NGX_CONF_OK;
504}
505
506
507static PerlInterpreter *
Igor Sysoev8885f872007-01-20 19:26:48 +0000508ngx_http_perl_create_interpreter(ngx_conf_t *cf,
509 ngx_http_perl_main_conf_t *pmcf)
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000510{
511 int n;
Igor Sysoev8a444aa2006-10-12 19:55:15 +0000512 STRLEN len;
513 SV *sv;
514 char *ver, *embedding[6];
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000515 PerlInterpreter *perl;
516
Igor Sysoev8885f872007-01-20 19:26:48 +0000517 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter");
518
519 if (ngx_set_environment(cf->cycle, NULL) == NULL) {
520 return NULL;
521 }
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000522
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000523 perl = perl_alloc();
524 if (perl == NULL) {
Igor Sysoev8885f872007-01-20 19:26:48 +0000525 ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_alloc() failed");
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000526 return NULL;
527 }
528
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000529 {
530
531 dTHXa(perl);
Igor Sysoev36d520d2006-11-26 15:35:02 +0000532 PERL_SET_CONTEXT(perl);
533
534 perl_construct(perl);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000535
536#ifdef PERL_EXIT_DESTRUCT_END
537 PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
538#endif
539
540 embedding[0] = "";
541
542 if (pmcf->modules.data) {
543 embedding[1] = "-I";
544 embedding[2] = (char *) pmcf->modules.data;
545 n = 3;
546
547 } else {
548 n = 1;
549 }
550
551 embedding[n++] = "-Mnginx";
552 embedding[n++] = "-e";
553 embedding[n++] = "0";
554
555 n = perl_parse(perl, ngx_http_perl_xs_init, n, embedding, NULL);
556
557 if (n != 0) {
Igor Sysoev8885f872007-01-20 19:26:48 +0000558 ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_parse() failed: %d", n);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000559 goto fail;
560 }
561
Igor Sysoev8a444aa2006-10-12 19:55:15 +0000562 sv = get_sv("nginx::VERSION", FALSE);
563 ver = SvPV(sv, len);
564
565 if (ngx_strcmp(ver, NGINX_VERSION) != 0) {
Igor Sysoev8885f872007-01-20 19:26:48 +0000566 ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
Igor Sysoev8a444aa2006-10-12 19:55:15 +0000567 "version " NGINX_VERSION " of nginx.pm is required, "
568 "but %s was found", ver);
569 goto fail;
570 }
571
Igor Sysoev8885f872007-01-20 19:26:48 +0000572 if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) != NGX_OK) {
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000573 goto fail;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000574 }
575
576 }
577
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000578 return perl;
579
580fail:
581
582 (void) perl_destruct(perl);
583
584 perl_free(perl);
585
586 return NULL;
587}
588
589
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000590static ngx_int_t
Igor Sysoevafd7ec52006-05-29 17:28:12 +0000591ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log)
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000592{
593 char **script;
594 STRLEN len;
595 ngx_str_t err;
596 ngx_uint_t i;
597
598 script = requires->elts;
599 for (i = 0; i < requires->nelts; i++) {
600
601 require_pv(script[i]);
602
603 if (SvTRUE(ERRSV)) {
604
605 err.data = (u_char *) SvPV(ERRSV, len);
606 for (len--; err.data[len] == LF || err.data[len] == CR; len--) {
607 /* void */
608 }
609 err.len = len + 1;
610
611 ngx_log_error(NGX_LOG_EMERG, log, 0,
612 "require_pv(\"%s\") failed: \"%V\"", script[i], &err);
613
614 return NGX_ERROR;
615 }
616 }
617
618 return NGX_OK;
619}
620
621
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000622static ngx_int_t
Igor Sysoev36d520d2006-11-26 15:35:02 +0000623ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub,
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000624 ngx_str_t **args, ngx_str_t *handler, ngx_str_t *rv)
625{
626 SV *sv;
627 int n, status;
628 char *line;
629 STRLEN len, n_a;
630 ngx_str_t err;
631 ngx_uint_t i;
632
633 dSP;
634
635 status = 0;
636
637 ENTER;
638 SAVETMPS;
639
640 PUSHMARK(sp);
641
Igor Sysoev36d520d2006-11-26 15:35:02 +0000642 sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx));
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000643 XPUSHs(sv);
644
645 if (args) {
646 for (i = 0; args[i]; i++) { /* void */ }
647
648 EXTEND(sp, (int) i);
649
650 for (i = 0; args[i]; i++) {
651 PUSHs(sv_2mortal(newSVpvn((char *) args[i]->data, args[i]->len)));
652 }
653 }
654
655 PUTBACK;
656
657 n = call_sv(sub, G_EVAL);
658
659 SPAGAIN;
660
661 if (n) {
662 if (rv == NULL) {
663 status = POPi;
664
665 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
666 "call_sv: %d", status);
667
668 } else {
Igor Sysoev13c68742006-03-10 12:51:52 +0000669 line = SvPVx(POPs, n_a);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000670 rv->len = n_a;
671
672 rv->data = ngx_palloc(r->pool, n_a);
673 if (rv->data == NULL) {
674 return NGX_ERROR;
675 }
676
677 ngx_memcpy(rv->data, line, n_a);
678 }
679 }
680
681 PUTBACK;
682
683 FREETMPS;
684 LEAVE;
685
686 /* check $@ */
687
688 if (SvTRUE(ERRSV)) {
689
690 err.data = (u_char *) SvPV(ERRSV, len);
691 for (len--; err.data[len] == LF || err.data[len] == CR; len--) {
692 /* void */
693 }
694 err.len = len + 1;
695
696 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
697 "call_sv(\"%V\") failed: \"%V\"",
698 handler, &err);
699
700 if (rv) {
701 return NGX_ERROR;
702 }
703
704 return NGX_HTTP_INTERNAL_SERVER_ERROR;
705 }
706
707 if (n != 1) {
708 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
709 "call_sv(\"%V\") returned %d results", handler, n);
710 status = NGX_OK;
711 }
712
713 if (rv) {
714 return NGX_OK;
715 }
716
717 return (ngx_int_t) status;
718}
719
720
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000721static void
722ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv)
723{
Igor Sysoev8fea8852006-03-15 09:53:04 +0000724 u_char *p;
725
726 for (p = handler->data; *p; p++) {
727 if (*p != ' ' && *p != '\t' && *p != CR && *p != LF) {
728 break;
729 }
730 }
731
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000732 if (ngx_strncmp(p, "sub ", 4) == 0 || ngx_strncmp(p, "use ", 4) == 0) {
Igor Sysoev8fea8852006-03-15 09:53:04 +0000733 *sv = eval_pv((char *) p, FALSE);
Igor Sysoev9a29d122006-11-26 16:56:41 +0000734
735 /* eval_pv() does not set ERRSV on failure */
736
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000737 return;
738 }
739
740 *sv = NULL;
741}
742
743
744static void *
745ngx_http_perl_create_main_conf(ngx_conf_t *cf)
746{
747 ngx_http_perl_main_conf_t *pmcf;
748
749 pmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_main_conf_t));
750 if (pmcf == NULL) {
751 return NGX_CONF_ERROR;
752 }
753
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000754 if (ngx_array_init(&pmcf->requires, cf->pool, 1, sizeof(u_char *))
755 != NGX_OK)
756 {
757 return NULL;
758 }
759
760 return pmcf;
761}
762
763
764static char *
765ngx_http_perl_init_main_conf(ngx_conf_t *cf, void *conf)
766{
767 ngx_http_perl_main_conf_t *pmcf = conf;
768
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000769 if (pmcf->perl == NULL) {
770 if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
771 return NGX_CONF_ERROR;
772 }
773 }
774
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000775 return NGX_CONF_OK;
776}
777
778
Igor Sysoevf9b7db52006-11-26 14:35:27 +0000779#if (NGX_HAVE_PERL_MULTIPLICITY)
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000780
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000781static void
782ngx_http_perl_cleanup_perl(void *data)
783{
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000784 PerlInterpreter *perl = data;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000785
Igor Sysoev36d520d2006-11-26 15:35:02 +0000786 PERL_SET_CONTEXT(perl);
787
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000788 (void) perl_destruct(perl);
789
790 perl_free(perl);
791
792 PERL_SYS_TERM();
793}
794
Igor Sysoev3338cfd2006-05-11 14:43:47 +0000795#endif
796
797
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000798static ngx_int_t
799ngx_http_perl_preconfiguration(ngx_conf_t *cf)
800{
Igor Sysoevcce886c2006-02-22 19:41:39 +0000801#if (NGX_HTTP_SSI)
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000802 ngx_int_t rc;
803 ngx_http_ssi_main_conf_t *smcf;
804
805 smcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_ssi_filter_module);
806
807 rc = ngx_hash_add_key(&smcf->commands, &ngx_http_perl_ssi_command.name,
808 &ngx_http_perl_ssi_command, NGX_HASH_READONLY_KEY);
809
810 if (rc != NGX_OK) {
811 if (rc == NGX_BUSY) {
812 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
813 "conflicting SSI command \"%V\"",
814 &ngx_http_perl_ssi_command.name);
815 }
816
817 return NGX_ERROR;
818 }
Igor Sysoevcce886c2006-02-22 19:41:39 +0000819#endif
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000820
821 return NGX_OK;
822}
823
824
825static void *
826ngx_http_perl_create_loc_conf(ngx_conf_t *cf)
827{
828 ngx_http_perl_loc_conf_t *plcf;
829
830 plcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_loc_conf_t));
831 if (plcf == NULL) {
832 return NGX_CONF_ERROR;
833 }
834
835 /*
836 * set by ngx_pcalloc():
837 *
838 * plcf->handler = { 0, NULL };
839 */
840
841 return plcf;
842}
843
844
845static char *
846ngx_http_perl_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
847{
848 ngx_http_perl_loc_conf_t *prev = parent;
849 ngx_http_perl_loc_conf_t *conf = child;
850
851 if (conf->sub == NULL) {
852 conf->sub = prev->sub;
853 conf->handler = prev->handler;
854 }
855
856 return NGX_CONF_OK;
857}
858
859
860static char *
861ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
862{
863 ngx_http_perl_main_conf_t *pmcf = conf;
864
865 u_char **p;
866 ngx_str_t *value;
867
868 value = cf->args->elts;
869
870 p = ngx_array_push(&pmcf->requires);
871
872 if (p == NULL) {
873 return NGX_CONF_ERROR;
874 }
875
876 *p = value[1].data;
877
878 return NGX_CONF_OK;
879}
880
881
882static char *
883ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
884{
885 ngx_http_perl_loc_conf_t *plcf = conf;
886
887 ngx_str_t *value;
888 ngx_http_core_loc_conf_t *clcf;
889 ngx_http_perl_main_conf_t *pmcf;
890
891 value = cf->args->elts;
892
893 if (plcf->handler.data) {
894 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
895 "duplicate perl handler \"%V\"", &value[1]);
896 return NGX_CONF_ERROR;
897 }
898
899 pmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_perl_module);
900
901 if (pmcf->perl == NULL) {
902 if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
903 return NGX_CONF_ERROR;
904 }
905 }
906
907 plcf->handler = value[1];
908
909 {
910
911 dTHXa(pmcf->perl);
Igor Sysoev36d520d2006-11-26 15:35:02 +0000912 PERL_SET_CONTEXT(pmcf->perl);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000913
914 ngx_http_perl_eval_anon_sub(aTHX_ &value[1], &plcf->sub);
915
916 if (plcf->sub == &PL_sv_undef) {
917 ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
918 "eval_pv(\"%V\") failed", &value[1]);
919 return NGX_CONF_ERROR;
920 }
921
922 if (plcf->sub == NULL) {
923 plcf->sub = newSVpvn((char *) value[1].data, value[1].len);
924 }
925
926 }
927
928 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
929 clcf->handler = ngx_http_perl_handler;
930
931 return NGX_CONF_OK;
932}
933
934
935static char *
936ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
937{
938 ngx_int_t index;
939 ngx_str_t *value;
940 ngx_http_variable_t *v;
941 ngx_http_perl_variable_t *pv;
942 ngx_http_perl_main_conf_t *pmcf;
943
944 value = cf->args->elts;
945
946 if (value[1].data[0] != '$') {
947 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
948 "invalid variable name \"%V\"", &value[1]);
949 return NGX_CONF_ERROR;
950 }
951
952 value[1].len--;
953 value[1].data++;
954
955 v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGABLE);
956 if (v == NULL) {
957 return NGX_CONF_ERROR;
958 }
959
960 pv = ngx_palloc(cf->pool, sizeof(ngx_http_perl_variable_t));
961 if (pv == NULL) {
962 return NGX_CONF_ERROR;
963 }
964
965 index = ngx_http_get_variable_index(cf, &value[1]);
966 if (index == NGX_ERROR) {
967 return NGX_CONF_ERROR;
968 }
969
970 pmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_perl_module);
971
972 if (pmcf->perl == NULL) {
973 if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
974 return NGX_CONF_ERROR;
975 }
976 }
977
978 pv->handler = value[2];
979
980 {
981
982 dTHXa(pmcf->perl);
Igor Sysoev36d520d2006-11-26 15:35:02 +0000983 PERL_SET_CONTEXT(pmcf->perl);
Igor Sysoev9bf11aa2006-01-16 14:56:53 +0000984
985 ngx_http_perl_eval_anon_sub(aTHX_ &value[2], &pv->sub);
986
987 if (pv->sub == &PL_sv_undef) {
988 ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
989 "eval_pv(\"%V\") failed", &value[2]);
990 return NGX_CONF_ERROR;
991 }
992
993 if (pv->sub == NULL) {
994 pv->sub = newSVpvn((char *) value[2].data, value[2].len);
995 }
996
997 }
998
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000999 v->get_handler = ngx_http_perl_variable;
Igor Sysoev9bf11aa2006-01-16 14:56:53 +00001000 v->data = (uintptr_t) pv;
1001
1002 return NGX_CONF_OK;
1003}