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 = &params[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>