Annotation of embedaddon/nginx/src/http/modules/perl/ngx_http_perl_module.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * Copyright (C) Igor Sysoev
        !             4:  * Copyright (C) Nginx, Inc.
        !             5:  */
        !             6: 
        !             7: 
        !             8: #include <ngx_config.h>
        !             9: #include <ngx_core.h>
        !            10: #include <ngx_http.h>
        !            11: #include <ngx_http_perl_module.h>
        !            12: 
        !            13: 
        !            14: typedef struct {
        !            15:     PerlInterpreter   *perl;
        !            16:     HV                *nginx;
        !            17:     ngx_array_t       *modules;
        !            18:     ngx_array_t       *requires;
        !            19: } ngx_http_perl_main_conf_t;
        !            20: 
        !            21: 
        !            22: typedef struct {
        !            23:     SV                *sub;
        !            24:     ngx_str_t          handler;
        !            25: } ngx_http_perl_loc_conf_t;
        !            26: 
        !            27: 
        !            28: typedef struct {
        !            29:     SV                *sub;
        !            30:     ngx_str_t          handler;
        !            31: } ngx_http_perl_variable_t;
        !            32: 
        !            33: 
        !            34: #if (NGX_HTTP_SSI)
        !            35: static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r,
        !            36:     ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params);
        !            37: #endif
        !            38: 
        !            39: static char *ngx_http_perl_init_interpreter(ngx_conf_t *cf,
        !            40:     ngx_http_perl_main_conf_t *pmcf);
        !            41: static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf,
        !            42:     ngx_http_perl_main_conf_t *pmcf);
        !            43: static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires,
        !            44:     ngx_log_t *log);
        !            45: static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
        !            46:     HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv);
        !            47: static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv);
        !            48: 
        !            49: static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf);
        !            50: static void *ngx_http_perl_create_main_conf(ngx_conf_t *cf);
        !            51: static char *ngx_http_perl_init_main_conf(ngx_conf_t *cf, void *conf);
        !            52: static void *ngx_http_perl_create_loc_conf(ngx_conf_t *cf);
        !            53: static char *ngx_http_perl_merge_loc_conf(ngx_conf_t *cf, void *parent,
        !            54:     void *child);
        !            55: static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
        !            56: static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
        !            57: 
        !            58: #if (NGX_HAVE_PERL_MULTIPLICITY)
        !            59: static void ngx_http_perl_cleanup_perl(void *data);
        !            60: #endif
        !            61: 
        !            62: static ngx_int_t ngx_http_perl_init_worker(ngx_cycle_t *cycle);
        !            63: static void ngx_http_perl_exit(ngx_cycle_t *cycle);
        !            64: 
        !            65: 
        !            66: static ngx_command_t  ngx_http_perl_commands[] = {
        !            67: 
        !            68:     { ngx_string("perl_modules"),
        !            69:       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
        !            70:       ngx_conf_set_str_array_slot,
        !            71:       NGX_HTTP_MAIN_CONF_OFFSET,
        !            72:       offsetof(ngx_http_perl_main_conf_t, modules),
        !            73:       NULL },
        !            74: 
        !            75:     { ngx_string("perl_require"),
        !            76:       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
        !            77:       ngx_conf_set_str_array_slot,
        !            78:       NGX_HTTP_MAIN_CONF_OFFSET,
        !            79:       offsetof(ngx_http_perl_main_conf_t, requires),
        !            80:       NULL },
        !            81: 
        !            82:     { ngx_string("perl"),
        !            83:       NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
        !            84:       ngx_http_perl,
        !            85:       NGX_HTTP_LOC_CONF_OFFSET,
        !            86:       0,
        !            87:       NULL },
        !            88: 
        !            89:     { ngx_string("perl_set"),
        !            90:       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
        !            91:       ngx_http_perl_set,
        !            92:       NGX_HTTP_LOC_CONF_OFFSET,
        !            93:       0,
        !            94:       NULL },
        !            95: 
        !            96:       ngx_null_command
        !            97: };
        !            98: 
        !            99: 
        !           100: static ngx_http_module_t  ngx_http_perl_module_ctx = {
        !           101:     ngx_http_perl_preconfiguration,        /* preconfiguration */
        !           102:     NULL,                                  /* postconfiguration */
        !           103: 
        !           104:     ngx_http_perl_create_main_conf,        /* create main configuration */
        !           105:     ngx_http_perl_init_main_conf,          /* init main configuration */
        !           106: 
        !           107:     NULL,                                  /* create server configuration */
        !           108:     NULL,                                  /* merge server configuration */
        !           109: 
        !           110:     ngx_http_perl_create_loc_conf,         /* create location configuration */
        !           111:     ngx_http_perl_merge_loc_conf           /* merge location configuration */
        !           112: };
        !           113: 
        !           114: 
        !           115: ngx_module_t  ngx_http_perl_module = {
        !           116:     NGX_MODULE_V1,
        !           117:     &ngx_http_perl_module_ctx,             /* module context */
        !           118:     ngx_http_perl_commands,                /* module directives */
        !           119:     NGX_HTTP_MODULE,                       /* module type */
        !           120:     NULL,                                  /* init master */
        !           121:     NULL,                                  /* init module */
        !           122:     ngx_http_perl_init_worker,             /* init process */
        !           123:     NULL,                                  /* init thread */
        !           124:     NULL,                                  /* exit thread */
        !           125:     NULL,                                  /* exit process */
        !           126:     ngx_http_perl_exit,                    /* exit master */
        !           127:     NGX_MODULE_V1_PADDING
        !           128: };
        !           129: 
        !           130: 
        !           131: #if (NGX_HTTP_SSI)
        !           132: 
        !           133: #define NGX_HTTP_PERL_SSI_SUB  0
        !           134: #define NGX_HTTP_PERL_SSI_ARG  1
        !           135: 
        !           136: 
        !           137: static ngx_http_ssi_param_t  ngx_http_perl_ssi_params[] = {
        !           138:     { ngx_string("sub"), NGX_HTTP_PERL_SSI_SUB, 1, 0 },
        !           139:     { ngx_string("arg"), NGX_HTTP_PERL_SSI_ARG, 0, 1 },
        !           140:     { ngx_null_string, 0, 0, 0 }
        !           141: };
        !           142: 
        !           143: static ngx_http_ssi_command_t  ngx_http_perl_ssi_command = {
        !           144:     ngx_string("perl"), ngx_http_perl_ssi, ngx_http_perl_ssi_params, 0, 0, 1
        !           145: };
        !           146: 
        !           147: #endif
        !           148: 
        !           149: 
        !           150: static ngx_str_t         ngx_null_name = ngx_null_string;
        !           151: static HV               *nginx_stash;
        !           152: 
        !           153: #if (NGX_HAVE_PERL_MULTIPLICITY)
        !           154: static ngx_uint_t        ngx_perl_term;
        !           155: #else
        !           156: static PerlInterpreter  *perl;
        !           157: #endif
        !           158: 
        !           159: 
        !           160: static void
        !           161: ngx_http_perl_xs_init(pTHX)
        !           162: {
        !           163:     newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__);
        !           164: 
        !           165:     nginx_stash = gv_stashpv("nginx", TRUE);
        !           166: }
        !           167: 
        !           168: 
        !           169: static ngx_int_t
        !           170: ngx_http_perl_handler(ngx_http_request_t *r)
        !           171: {
        !           172:     r->main->count++;
        !           173: 
        !           174:     ngx_http_perl_handle_request(r);
        !           175: 
        !           176:     return NGX_DONE;
        !           177: }
        !           178: 
        !           179: 
        !           180: void
        !           181: ngx_http_perl_handle_request(ngx_http_request_t *r)
        !           182: {
        !           183:     SV                         *sub;
        !           184:     ngx_int_t                   rc;
        !           185:     ngx_str_t                   uri, args, *handler;
        !           186:     ngx_http_perl_ctx_t        *ctx;
        !           187:     ngx_http_perl_loc_conf_t   *plcf;
        !           188:     ngx_http_perl_main_conf_t  *pmcf;
        !           189: 
        !           190:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler");
        !           191: 
        !           192:     ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
        !           193: 
        !           194:     if (ctx == NULL) {
        !           195:         ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
        !           196:         if (ctx == NULL) {
        !           197:             ngx_http_finalize_request(r, NGX_ERROR);
        !           198:             return;
        !           199:         }
        !           200: 
        !           201:         ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
        !           202:     }
        !           203: 
        !           204:     pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
        !           205: 
        !           206:     {
        !           207: 
        !           208:     dTHXa(pmcf->perl);
        !           209:     PERL_SET_CONTEXT(pmcf->perl);
        !           210: 
        !           211:     if (ctx->next == NULL) {
        !           212:         plcf = ngx_http_get_module_loc_conf(r, ngx_http_perl_module);
        !           213:         sub = plcf->sub;
        !           214:         handler = &plcf->handler;
        !           215: 
        !           216:     } else {
        !           217:         sub = ctx->next;
        !           218:         handler = &ngx_null_name;
        !           219:         ctx->next = NULL;
        !           220:     }
        !           221: 
        !           222:     rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler,
        !           223:                                     NULL);
        !           224: 
        !           225:     }
        !           226: 
        !           227:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
        !           228:                    "perl handler done: %i", rc);
        !           229: 
        !           230:     if (rc == NGX_DONE) {
        !           231:         ngx_http_finalize_request(r, rc);
        !           232:         return;
        !           233:     }
        !           234: 
        !           235:     if (rc > 600) {
        !           236:         rc = NGX_OK;
        !           237:     }
        !           238: 
        !           239:     if (ctx->redirect_uri.len) {
        !           240:         uri = ctx->redirect_uri;
        !           241:         args = ctx->redirect_args;
        !           242: 
        !           243:     } else {
        !           244:         uri.len = 0;
        !           245:     }
        !           246: 
        !           247:     ctx->filename.data = NULL;
        !           248:     ctx->redirect_uri.len = 0;
        !           249: 
        !           250:     if (ctx->done || ctx->next) {
        !           251:         ngx_http_finalize_request(r, NGX_DONE);
        !           252:         return;
        !           253:     }
        !           254: 
        !           255:     if (uri.len) {
        !           256:         ngx_http_internal_redirect(r, &uri, &args);
        !           257:         ngx_http_finalize_request(r, NGX_DONE);
        !           258:         return;
        !           259:     }
        !           260: 
        !           261:     if (rc == NGX_OK || rc == NGX_HTTP_OK) {
        !           262:         ngx_http_send_special(r, NGX_HTTP_LAST);
        !           263:         ctx->done = 1;
        !           264:     }
        !           265: 
        !           266:     ngx_http_finalize_request(r, rc);
        !           267: }
        !           268: 
        !           269: 
        !           270: void
        !           271: ngx_http_perl_sleep_handler(ngx_http_request_t *r)
        !           272: {
        !           273:     ngx_event_t  *wev;
        !           274: 
        !           275:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
        !           276:                    "perl sleep handler");
        !           277: 
        !           278:     wev = r->connection->write;
        !           279: 
        !           280:     if (wev->timedout) {
        !           281:         wev->timedout = 0;
        !           282:         ngx_http_perl_handle_request(r);
        !           283:         return;
        !           284:     }
        !           285: 
        !           286:     if (ngx_handle_write_event(wev, 0) != NGX_OK) {
        !           287:         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
        !           288:     }
        !           289: }
        !           290: 
        !           291: 
        !           292: static ngx_int_t
        !           293: ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
        !           294:     uintptr_t data)
        !           295: {
        !           296:     ngx_http_perl_variable_t *pv = (ngx_http_perl_variable_t *) data;
        !           297: 
        !           298:     ngx_int_t                   rc;
        !           299:     ngx_str_t                   value;
        !           300:     ngx_http_perl_ctx_t        *ctx;
        !           301:     ngx_http_perl_main_conf_t  *pmcf;
        !           302: 
        !           303:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
        !           304:                    "perl variable handler");
        !           305: 
        !           306:     ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
        !           307: 
        !           308:     if (ctx == NULL) {
        !           309:         ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
        !           310:         if (ctx == NULL) {
        !           311:             return NGX_ERROR;
        !           312:         }
        !           313: 
        !           314:         ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
        !           315:     }
        !           316: 
        !           317:     pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
        !           318: 
        !           319:     value.data = NULL;
        !           320: 
        !           321:     {
        !           322: 
        !           323:     dTHXa(pmcf->perl);
        !           324:     PERL_SET_CONTEXT(pmcf->perl);
        !           325: 
        !           326:     rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL,
        !           327:                                     &pv->handler, &value);
        !           328: 
        !           329:     }
        !           330: 
        !           331:     if (value.data) {
        !           332:         v->len = value.len;
        !           333:         v->valid = 1;
        !           334:         v->no_cacheable = 0;
        !           335:         v->not_found = 0;
        !           336:         v->data = value.data;
        !           337: 
        !           338:     } else {
        !           339:         v->not_found = 1;
        !           340:     }
        !           341: 
        !           342:     ctx->filename.data = NULL;
        !           343:     ctx->redirect_uri.len = 0;
        !           344: 
        !           345:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
        !           346:                    "perl variable done");
        !           347: 
        !           348:     return rc;
        !           349: }
        !           350: 
        !           351: 
        !           352: #if (NGX_HTTP_SSI)
        !           353: 
        !           354: static ngx_int_t
        !           355: ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx,
        !           356:     ngx_str_t **params)
        !           357: {
        !           358:     SV                         *sv, **asv;
        !           359:     ngx_int_t                   rc;
        !           360:     ngx_str_t                  *handler, **args;
        !           361:     ngx_uint_t                  i;
        !           362:     ngx_http_perl_ctx_t        *ctx;
        !           363:     ngx_http_perl_main_conf_t  *pmcf;
        !           364: 
        !           365:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
        !           366:                    "perl ssi handler");
        !           367: 
        !           368:     ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
        !           369: 
        !           370:     if (ctx == NULL) {
        !           371:         ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
        !           372:         if (ctx == NULL) {
        !           373:             return NGX_ERROR;
        !           374:         }
        !           375: 
        !           376:         ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
        !           377:     }
        !           378: 
        !           379:     pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
        !           380: 
        !           381:     ctx->ssi = ssi_ctx;
        !           382: 
        !           383:     handler = params[NGX_HTTP_PERL_SSI_SUB];
        !           384:     handler->data[handler->len] = '\0';
        !           385: 
        !           386:     {
        !           387: 
        !           388:     dTHXa(pmcf->perl);
        !           389:     PERL_SET_CONTEXT(pmcf->perl);
        !           390: 
        !           391: #if 0
        !           392: 
        !           393:     /* the code is disabled to force the precompiled perl code using only */
        !           394: 
        !           395:     ngx_http_perl_eval_anon_sub(aTHX_ handler, &sv);
        !           396: 
        !           397:     if (sv == &PL_sv_undef) {
        !           398:         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
        !           399:                       "eval_pv(\"%V\") failed", handler);
        !           400:         return NGX_ERROR;
        !           401:     }
        !           402: 
        !           403:     if (sv == NULL) {
        !           404:         sv = newSVpvn((char *) handler->data, handler->len);
        !           405:     }
        !           406: 
        !           407: #endif
        !           408: 
        !           409:     sv = newSVpvn((char *) handler->data, handler->len);
        !           410: 
        !           411:     args = &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>