src/http/modules/perl/ngx_http_perl_module.c - nginx-1.7.10

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>
  8. #include <ngx_http_perl_module.h>


  9. typedef struct {
  10.     PerlInterpreter   *perl;
  11.     HV                *nginx;
  12.     ngx_array_t       *modules;
  13.     ngx_array_t       *requires;
  14. } ngx_http_perl_main_conf_t;


  15. typedef struct {
  16.     SV                *sub;
  17.     ngx_str_t          handler;
  18. } ngx_http_perl_loc_conf_t;


  19. typedef struct {
  20.     SV                *sub;
  21.     ngx_str_t          handler;
  22. } ngx_http_perl_variable_t;


  23. #if (NGX_HTTP_SSI)
  24. static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r,
  25.     ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params);
  26. #endif

  27. static char *ngx_http_perl_init_interpreter(ngx_conf_t *cf,
  28.     ngx_http_perl_main_conf_t *pmcf);
  29. static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf,
  30.     ngx_http_perl_main_conf_t *pmcf);
  31. static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires,
  32.     ngx_log_t *log);
  33. static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
  34.     HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv);
  35. static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv);

  36. static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf);
  37. static void *ngx_http_perl_create_main_conf(ngx_conf_t *cf);
  38. static char *ngx_http_perl_init_main_conf(ngx_conf_t *cf, void *conf);
  39. static void *ngx_http_perl_create_loc_conf(ngx_conf_t *cf);
  40. static char *ngx_http_perl_merge_loc_conf(ngx_conf_t *cf, void *parent,
  41.     void *child);
  42. static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
  43. static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

  44. #if (NGX_HAVE_PERL_MULTIPLICITY)
  45. static void ngx_http_perl_cleanup_perl(void *data);
  46. #endif

  47. static ngx_int_t ngx_http_perl_init_worker(ngx_cycle_t *cycle);
  48. static void ngx_http_perl_exit(ngx_cycle_t *cycle);


  49. static ngx_command_t  ngx_http_perl_commands[] = {

  50.     { ngx_string("perl_modules"),
  51.       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
  52.       ngx_conf_set_str_array_slot,
  53.       NGX_HTTP_MAIN_CONF_OFFSET,
  54.       offsetof(ngx_http_perl_main_conf_t, modules),
  55.       NULL },

  56.     { ngx_string("perl_require"),
  57.       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
  58.       ngx_conf_set_str_array_slot,
  59.       NGX_HTTP_MAIN_CONF_OFFSET,
  60.       offsetof(ngx_http_perl_main_conf_t, requires),
  61.       NULL },

  62.     { ngx_string("perl"),
  63.       NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
  64.       ngx_http_perl,
  65.       NGX_HTTP_LOC_CONF_OFFSET,
  66.       0,
  67.       NULL },

  68.     { ngx_string("perl_set"),
  69.       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
  70.       ngx_http_perl_set,
  71.       NGX_HTTP_LOC_CONF_OFFSET,
  72.       0,
  73.       NULL },

  74.       ngx_null_command
  75. };


  76. static ngx_http_module_t  ngx_http_perl_module_ctx = {
  77.     ngx_http_perl_preconfiguration,        /* preconfiguration */
  78.     NULL,                                  /* postconfiguration */

  79.     ngx_http_perl_create_main_conf,        /* create main configuration */
  80.     ngx_http_perl_init_main_conf,          /* init main configuration */

  81.     NULL,                                  /* create server configuration */
  82.     NULL,                                  /* merge server configuration */

  83.     ngx_http_perl_create_loc_conf,         /* create location configuration */
  84.     ngx_http_perl_merge_loc_conf           /* merge location configuration */
  85. };


  86. ngx_module_t  ngx_http_perl_module = {
  87.     NGX_MODULE_V1,
  88.     &ngx_http_perl_module_ctx,             /* module context */
  89.     ngx_http_perl_commands,                /* module directives */
  90.     NGX_HTTP_MODULE,                       /* module type */
  91.     NULL,                                  /* init master */
  92.     NULL,                                  /* init module */
  93.     ngx_http_perl_init_worker,             /* init process */
  94.     NULL,                                  /* init thread */
  95.     NULL,                                  /* exit thread */
  96.     NULL,                                  /* exit process */
  97.     ngx_http_perl_exit,                    /* exit master */
  98.     NGX_MODULE_V1_PADDING
  99. };


  100. #if (NGX_HTTP_SSI)

  101. #define NGX_HTTP_PERL_SSI_SUB  0
  102. #define NGX_HTTP_PERL_SSI_ARG  1


  103. static ngx_http_ssi_param_t  ngx_http_perl_ssi_params[] = {
  104.     { ngx_string("sub"), NGX_HTTP_PERL_SSI_SUB, 1, 0 },
  105.     { ngx_string("arg"), NGX_HTTP_PERL_SSI_ARG, 0, 1 },
  106.     { ngx_null_string, 0, 0, 0 }
  107. };

  108. static ngx_http_ssi_command_t  ngx_http_perl_ssi_command = {
  109.     ngx_string("perl"), ngx_http_perl_ssi, ngx_http_perl_ssi_params, 0, 0, 1
  110. };

  111. #endif


  112. static ngx_str_t         ngx_null_name = ngx_null_string;
  113. static HV               *nginx_stash;

  114. #if (NGX_HAVE_PERL_MULTIPLICITY)
  115. static ngx_uint_t        ngx_perl_term;
  116. #else
  117. static PerlInterpreter  *perl;
  118. #endif


  119. static void
  120. ngx_http_perl_xs_init(pTHX)
  121. {
  122.     newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__);

  123.     nginx_stash = gv_stashpv("nginx", TRUE);
  124. }


  125. static ngx_int_t
  126. ngx_http_perl_handler(ngx_http_request_t *r)
  127. {
  128.     r->main->count++;

  129.     ngx_http_perl_handle_request(r);

  130.     return NGX_DONE;
  131. }


  132. void
  133. ngx_http_perl_handle_request(ngx_http_request_t *r)
  134. {
  135.     SV                         *sub;
  136.     ngx_int_t                   rc;
  137.     ngx_str_t                   uri, args, *handler;
  138.     ngx_http_perl_ctx_t        *ctx;
  139.     ngx_http_perl_loc_conf_t   *plcf;
  140.     ngx_http_perl_main_conf_t  *pmcf;

  141.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler");

  142.     ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);

  143.     if (ctx == NULL) {
  144.         ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
  145.         if (ctx == NULL) {
  146.             ngx_http_finalize_request(r, NGX_ERROR);
  147.             return;
  148.         }

  149.         ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
  150.     }

  151.     pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);

  152.     {

  153.     dTHXa(pmcf->perl);
  154.     PERL_SET_CONTEXT(pmcf->perl);

  155.     if (ctx->next == NULL) {
  156.         plcf = ngx_http_get_module_loc_conf(r, ngx_http_perl_module);
  157.         sub = plcf->sub;
  158.         handler = &plcf->handler;

  159.     } else {
  160.         sub = ctx->next;
  161.         handler = &ngx_null_name;
  162.         ctx->next = NULL;
  163.     }

  164.     rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler,
  165.                                     NULL);

  166.     }

  167.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  168.                    "perl handler done: %i", rc);

  169.     if (rc == NGX_DONE) {
  170.         ngx_http_finalize_request(r, rc);
  171.         return;
  172.     }

  173.     if (rc > 600) {
  174.         rc = NGX_OK;
  175.     }

  176.     if (ctx->redirect_uri.len) {
  177.         uri = ctx->redirect_uri;
  178.         args = ctx->redirect_args;

  179.     } else {
  180.         uri.len = 0;
  181.     }

  182.     ctx->filename.data = NULL;
  183.     ctx->redirect_uri.len = 0;

  184.     if (ctx->done || ctx->next) {
  185.         ngx_http_finalize_request(r, NGX_DONE);
  186.         return;
  187.     }

  188.     if (uri.len) {
  189.         ngx_http_internal_redirect(r, &uri, &args);
  190.         ngx_http_finalize_request(r, NGX_DONE);
  191.         return;
  192.     }

  193.     if (rc == NGX_OK || rc == NGX_HTTP_OK) {
  194.         ngx_http_send_special(r, NGX_HTTP_LAST);
  195.         ctx->done = 1;
  196.     }

  197.     ngx_http_finalize_request(r, rc);
  198. }


  199. void
  200. ngx_http_perl_sleep_handler(ngx_http_request_t *r)
  201. {
  202.     ngx_event_t  *wev;

  203.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  204.                    "perl sleep handler");

  205.     wev = r->connection->write;

  206.     if (wev->timedout) {
  207.         wev->timedout = 0;
  208.         ngx_http_perl_handle_request(r);
  209.         return;
  210.     }

  211.     if (ngx_handle_write_event(wev, 0) != NGX_OK) {
  212.         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
  213.     }
  214. }


  215. static ngx_int_t
  216. ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
  217.     uintptr_t data)
  218. {
  219.     ngx_http_perl_variable_t *pv = (ngx_http_perl_variable_t *) data;

  220.     ngx_int_t                   rc;
  221.     ngx_str_t                   value;
  222.     ngx_http_perl_ctx_t        *ctx;
  223.     ngx_http_perl_main_conf_t  *pmcf;

  224.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  225.                    "perl variable handler");

  226.     ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);

  227.     if (ctx == NULL) {
  228.         ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
  229.         if (ctx == NULL) {
  230.             return NGX_ERROR;
  231.         }

  232.         ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
  233.     }

  234.     pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);

  235.     value.data = NULL;

  236.     {

  237.     dTHXa(pmcf->perl);
  238.     PERL_SET_CONTEXT(pmcf->perl);

  239.     rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL,
  240.                                     &pv->handler, &value);

  241.     }

  242.     if (value.data) {
  243.         v->len = value.len;
  244.         v->valid = 1;
  245.         v->no_cacheable = 0;
  246.         v->not_found = 0;
  247.         v->data = value.data;

  248.     } else {
  249.         v->not_found = 1;
  250.     }

  251.     ctx->filename.data = NULL;
  252.     ctx->redirect_uri.len = 0;

  253.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  254.                    "perl variable done");

  255.     return rc;
  256. }


  257. #if (NGX_HTTP_SSI)

  258. static ngx_int_t
  259. ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx,
  260.     ngx_str_t **params)
  261. {
  262.     SV                         *sv, **asv;
  263.     ngx_int_t                   rc;
  264.     ngx_str_t                  *handler, **args;
  265.     ngx_uint_t                  i;
  266.     ngx_http_perl_ctx_t        *ctx;
  267.     ngx_http_perl_main_conf_t  *pmcf;

  268.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  269.                    "perl ssi handler");

  270.     ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);

  271.     if (ctx == NULL) {
  272.         ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t));
  273.         if (ctx == NULL) {
  274.             return NGX_ERROR;
  275.         }

  276.         ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
  277.     }

  278.     pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);

  279.     ctx->ssi = ssi_ctx;

  280.     handler = params[NGX_HTTP_PERL_SSI_SUB];
  281.     handler->data[handler->len] = '\0';

  282.     {

  283.     dTHXa(pmcf->perl);
  284.     PERL_SET_CONTEXT(pmcf->perl);

  285. #if 0

  286.     /* the code is disabled to force the precompiled perl code using only */

  287.     ngx_http_perl_eval_anon_sub(aTHX_ handler, &sv);

  288.     if (sv == &PL_sv_undef) {
  289.         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  290.                       "eval_pv(\"%V\") failed", handler);
  291.         return NGX_ERROR;
  292.     }

  293.     if (sv == NULL) {
  294.         sv = newSVpvn((char *) handler->data, handler->len);
  295.     }

  296. #endif

  297.     sv = newSVpvn((char *) handler->data, handler->len);

  298.     args = &params[NGX_HTTP_PERL_SSI_ARG];

  299.     if (args) {

  300.         for (i = 0; args[i]; i++) { /* void */ }

  301.         asv = ngx_pcalloc(r->pool, (i + 1) * sizeof(SV *));

  302.         if (asv == NULL) {
  303.             SvREFCNT_dec(sv);
  304.             return NGX_ERROR;
  305.         }

  306.         asv[0] = (SV *) (uintptr_t) i;

  307.         for (i = 0; args[i]; i++) {
  308.             asv[i + 1] = newSVpvn((char *) args[i]->data, args[i]->len);
  309.         }

  310.     } else {
  311.         asv = NULL;
  312.     }

  313.     rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler,
  314.                                     NULL);

  315.     SvREFCNT_dec(sv);

  316.     }

  317.     ctx->filename.data = NULL;
  318.     ctx->redirect_uri.len = 0;
  319.     ctx->ssi = NULL;

  320.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl ssi done");

  321.     return rc;
  322. }

  323. #endif


  324. static char *
  325. ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf)
  326. {
  327.     ngx_str_t           *m;
  328.     ngx_uint_t           i;
  329. #if (NGX_HAVE_PERL_MULTIPLICITY)
  330.     ngx_pool_cleanup_t  *cln;

  331.     cln = ngx_pool_cleanup_add(cf->pool, 0);
  332.     if (cln == NULL) {
  333.         return NGX_CONF_ERROR;
  334.     }

  335. #endif

  336. #ifdef NGX_PERL_MODULES
  337.     if (pmcf->modules == NGX_CONF_UNSET_PTR) {

  338.         pmcf->modules = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t));
  339.         if (pmcf->modules == NULL) {
  340.             return NGX_CONF_ERROR;
  341.         }

  342.         m = ngx_array_push(pmcf->modules);
  343.         if (m == NULL) {
  344.             return NGX_CONF_ERROR;
  345.         }

  346.         ngx_str_set(m, NGX_PERL_MODULES);
  347.     }
  348. #endif

  349.     if (pmcf->modules != NGX_CONF_UNSET_PTR) {
  350.         m = pmcf->modules->elts;
  351.         for (i = 0; i < pmcf->modules->nelts; i++) {
  352.             if (ngx_conf_full_name(cf->cycle, &m[i], 0) != NGX_OK) {
  353.                 return NGX_CONF_ERROR;
  354.             }
  355.         }
  356.     }

  357. #if !(NGX_HAVE_PERL_MULTIPLICITY)

  358.     if (perl) {

  359.         if (ngx_set_environment(cf->cycle, NULL) == NULL) {
  360.             return NGX_CONF_ERROR;
  361.         }

  362.         if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log)
  363.             != NGX_OK)
  364.         {
  365.             return NGX_CONF_ERROR;
  366.         }

  367.         pmcf->perl = perl;
  368.         pmcf->nginx = nginx_stash;

  369.         return NGX_CONF_OK;
  370.     }

  371. #endif

  372.     if (nginx_stash == NULL) {
  373.         PERL_SYS_INIT(&ngx_argc, &ngx_argv);
  374.     }

  375.     pmcf->perl = ngx_http_perl_create_interpreter(cf, pmcf);

  376.     if (pmcf->perl == NULL) {
  377.         return NGX_CONF_ERROR;
  378.     }

  379.     pmcf->nginx = nginx_stash;

  380. #if (NGX_HAVE_PERL_MULTIPLICITY)

  381.     cln->handler = ngx_http_perl_cleanup_perl;
  382.     cln->data = pmcf->perl;

  383. #else

  384.     perl = pmcf->perl;

  385. #endif

  386.     return NGX_CONF_OK;
  387. }


  388. static PerlInterpreter *
  389. ngx_http_perl_create_interpreter(ngx_conf_t *cf,
  390.     ngx_http_perl_main_conf_t *pmcf)
  391. {
  392.     int                n;
  393.     STRLEN             len;
  394.     SV                *sv;
  395.     char              *ver, **embedding;
  396.     ngx_str_t         *m;
  397.     ngx_uint_t         i;
  398.     PerlInterpreter   *perl;

  399.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter");

  400.     if (ngx_set_environment(cf->cycle, NULL) == NULL) {
  401.         return NULL;
  402.     }

  403.     perl = perl_alloc();
  404.     if (perl == NULL) {
  405.         ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_alloc() failed");
  406.         return NULL;
  407.     }

  408.     {

  409.     dTHXa(perl);
  410.     PERL_SET_CONTEXT(perl);

  411.     perl_construct(perl);

  412. #ifdef PERL_EXIT_DESTRUCT_END
  413.     PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
  414. #endif

  415.     n = (pmcf->modules != NGX_CONF_UNSET_PTR) ? pmcf->modules->nelts * 2 : 0;

  416.     embedding = ngx_palloc(cf->pool, (5 + n) * sizeof(char *));
  417.     if (embedding == NULL) {
  418.         goto fail;
  419.     }

  420.     embedding[0] = "";

  421.     if (n++) {
  422.         m = pmcf->modules->elts;
  423.         for (i = 0; i < pmcf->modules->nelts; i++) {
  424.             embedding[2 * i + 1] = "-I";
  425.             embedding[2 * i + 2] = (char *) m[i].data;
  426.         }
  427.     }

  428.     embedding[n++] = "-Mnginx";
  429.     embedding[n++] = "-e";
  430.     embedding[n++] = "0";
  431.     embedding[n] = NULL;

  432.     n = perl_parse(perl, ngx_http_perl_xs_init, n, embedding, NULL);

  433.     if (n != 0) {
  434.         ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_parse() failed: %d", n);
  435.         goto fail;
  436.     }

  437.     sv = get_sv("nginx::VERSION", FALSE);
  438.     ver = SvPV(sv, len);

  439.     if (ngx_strcmp(ver, NGINX_VERSION) != 0) {
  440.         ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
  441.                       "version " NGINX_VERSION " of nginx.pm is required, "
  442.                       "but %s was found", ver);
  443.         goto fail;
  444.     }

  445.     if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log) != NGX_OK) {
  446.         goto fail;
  447.     }

  448.     }

  449.     return perl;

  450. fail:

  451.     (void) perl_destruct(perl);

  452.     perl_free(perl);

  453.     return NULL;
  454. }


  455. static ngx_int_t
  456. ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log)
  457. {
  458.     u_char      *err;
  459.     STRLEN       len;
  460.     ngx_str_t   *script;
  461.     ngx_uint_t   i;

  462.     if (requires == NGX_CONF_UNSET_PTR) {
  463.         return NGX_OK;
  464.     }

  465.     script = requires->elts;
  466.     for (i = 0; i < requires->nelts; i++) {

  467.         require_pv((char *) script[i].data);

  468.         if (SvTRUE(ERRSV)) {

  469.             err = (u_char *) SvPV(ERRSV, len);
  470.             while (--len && (err[len] == CR || err[len] == LF)) { /* void */ }

  471.             ngx_log_error(NGX_LOG_EMERG, log, 0,
  472.                           "require_pv(\"%s\") failed: \"%*s\"",
  473.                           script[i].data, len + 1, err);

  474.             return NGX_ERROR;
  475.         }
  476.     }

  477.     return NGX_OK;
  478. }


  479. static ngx_int_t
  480. ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub,
  481.     SV **args, ngx_str_t *handler, ngx_str_t *rv)
  482. {
  483.     SV                *sv;
  484.     int                n, status;
  485.     char              *line;
  486.     u_char            *err;
  487.     STRLEN             len, n_a;
  488.     ngx_uint_t         i;
  489.     ngx_connection_t  *c;

  490.     dSP;

  491.     status = 0;

  492.     ENTER;
  493.     SAVETMPS;

  494.     PUSHMARK(sp);

  495.     sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx));
  496.     XPUSHs(sv);

  497.     if (args) {
  498.         EXTEND(sp, (intptr_t) args[0]);

  499.         for (i = 1; i <= (uintptr_t) args[0]; i++) {
  500.             PUSHs(sv_2mortal(args[i]));
  501.         }
  502.     }

  503.     PUTBACK;

  504.     c = r->connection;

  505.     n = call_sv(sub, G_EVAL);

  506.     SPAGAIN;

  507.     if (n) {
  508.         if (rv == NULL) {
  509.             status = POPi;

  510.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  511.                            "call_sv: %d", status);

  512.         } else {
  513.             line = SvPVx(POPs, n_a);
  514.             rv->len = n_a;

  515.             rv->data = ngx_pnalloc(r->pool, n_a);
  516.             if (rv->data == NULL) {
  517.                 return NGX_ERROR;
  518.             }

  519.             ngx_memcpy(rv->data, line, n_a);
  520.         }
  521.     }

  522.     PUTBACK;

  523.     FREETMPS;
  524.     LEAVE;

  525.     /* check $@ */

  526.     if (SvTRUE(ERRSV)) {

  527.         err = (u_char *) SvPV(ERRSV, len);
  528.         while (--len && (err[len] == CR || err[len] == LF)) { /* void */ }

  529.         ngx_log_error(NGX_LOG_ERR, c->log, 0,
  530.                       "call_sv(\"%V\") failed: \"%*s\"", handler, len + 1, err);

  531.         if (rv) {
  532.             return NGX_ERROR;
  533.         }

  534.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  535.     }

  536.     if (n != 1) {
  537.         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  538.                       "call_sv(\"%V\") returned %d results", handler, n);
  539.         status = NGX_OK;
  540.     }

  541.     if (rv) {
  542.         return NGX_OK;
  543.     }

  544.     return (ngx_int_t) status;
  545. }


  546. static void
  547. ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv)
  548. {
  549.     u_char  *p;

  550.     for (p = handler->data; *p; p++) {
  551.         if (*p != ' ' && *p != '\t' && *p != CR && *p != LF) {
  552.             break;
  553.         }
  554.     }

  555.     if (ngx_strncmp(p, "sub ", 4) == 0
  556.         || ngx_strncmp(p, "sub{", 4) == 0
  557.         || ngx_strncmp(p, "use ", 4) == 0)
  558.     {
  559.         *sv = eval_pv((char *) p, FALSE);

  560.         /* eval_pv() does not set ERRSV on failure */

  561.         return;
  562.     }

  563.     *sv = NULL;
  564. }


  565. static void *
  566. ngx_http_perl_create_main_conf(ngx_conf_t *cf)
  567. {
  568.     ngx_http_perl_main_conf_t  *pmcf;

  569.     pmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_main_conf_t));
  570.     if (pmcf == NULL) {
  571.         return NULL;
  572.     }

  573.     pmcf->modules = NGX_CONF_UNSET_PTR;
  574.     pmcf->requires = NGX_CONF_UNSET_PTR;

  575.     return pmcf;
  576. }


  577. static char *
  578. ngx_http_perl_init_main_conf(ngx_conf_t *cf, void *conf)
  579. {
  580.     ngx_http_perl_main_conf_t *pmcf = conf;

  581.     if (pmcf->perl == NULL) {
  582.         if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
  583.             return NGX_CONF_ERROR;
  584.         }
  585.     }

  586.     return NGX_CONF_OK;
  587. }


  588. #if (NGX_HAVE_PERL_MULTIPLICITY)

  589. static void
  590. ngx_http_perl_cleanup_perl(void *data)
  591. {
  592.     PerlInterpreter  *perl = data;

  593.     PERL_SET_CONTEXT(perl);

  594.     (void) perl_destruct(perl);

  595.     perl_free(perl);

  596.     if (ngx_perl_term) {
  597.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "perl term");

  598.         PERL_SYS_TERM();
  599.     }
  600. }

  601. #endif


  602. static ngx_int_t
  603. ngx_http_perl_preconfiguration(ngx_conf_t *cf)
  604. {
  605. #if (NGX_HTTP_SSI)
  606.     ngx_int_t                  rc;
  607.     ngx_http_ssi_main_conf_t  *smcf;

  608.     smcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_ssi_filter_module);

  609.     rc = ngx_hash_add_key(&smcf->commands, &ngx_http_perl_ssi_command.name,
  610.                           &ngx_http_perl_ssi_command, NGX_HASH_READONLY_KEY);

  611.     if (rc != NGX_OK) {
  612.         if (rc == NGX_BUSY) {
  613.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  614.                                "conflicting SSI command \"%V\"",
  615.                                &ngx_http_perl_ssi_command.name);
  616.         }

  617.         return NGX_ERROR;
  618.     }
  619. #endif

  620.     return NGX_OK;
  621. }


  622. static void *
  623. ngx_http_perl_create_loc_conf(ngx_conf_t *cf)
  624. {
  625.     ngx_http_perl_loc_conf_t *plcf;

  626.     plcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_loc_conf_t));
  627.     if (plcf == NULL) {
  628.         return NULL;
  629.     }

  630.     /*
  631.      * set by ngx_pcalloc():
  632.      *
  633.      *     plcf->handler = { 0, NULL };
  634.      */

  635.     return plcf;
  636. }


  637. static char *
  638. ngx_http_perl_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  639. {
  640.     ngx_http_perl_loc_conf_t *prev = parent;
  641.     ngx_http_perl_loc_conf_t *conf = child;

  642.     if (conf->sub == NULL) {
  643.         conf->sub = prev->sub;
  644.         conf->handler = prev->handler;
  645.     }

  646.     return NGX_CONF_OK;
  647. }


  648. static char *
  649. ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  650. {
  651.     ngx_http_perl_loc_conf_t *plcf = conf;

  652.     ngx_str_t                  *value;
  653.     ngx_http_core_loc_conf_t   *clcf;
  654.     ngx_http_perl_main_conf_t  *pmcf;

  655.     value = cf->args->elts;

  656.     if (plcf->handler.data) {
  657.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  658.                            "duplicate perl handler \"%V\"", &value[1]);
  659.         return NGX_CONF_ERROR;
  660.     }

  661.     pmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_perl_module);

  662.     if (pmcf->perl == NULL) {
  663.         if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
  664.             return NGX_CONF_ERROR;
  665.         }
  666.     }

  667.     plcf->handler = value[1];

  668.     {

  669.     dTHXa(pmcf->perl);
  670.     PERL_SET_CONTEXT(pmcf->perl);

  671.     ngx_http_perl_eval_anon_sub(aTHX_ &value[1], &plcf->sub);

  672.     if (plcf->sub == &PL_sv_undef) {
  673.         ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
  674.                            "eval_pv(\"%V\") failed", &value[1]);
  675.         return NGX_CONF_ERROR;
  676.     }

  677.     if (plcf->sub == NULL) {
  678.         plcf->sub = newSVpvn((char *) value[1].data, value[1].len);
  679.     }

  680.     }

  681.     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
  682.     clcf->handler = ngx_http_perl_handler;

  683.     return NGX_CONF_OK;
  684. }


  685. static char *
  686. ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  687. {
  688.     ngx_int_t                   index;
  689.     ngx_str_t                  *value;
  690.     ngx_http_variable_t        *v;
  691.     ngx_http_perl_variable_t   *pv;
  692.     ngx_http_perl_main_conf_t  *pmcf;

  693.     value = cf->args->elts;

  694.     if (value[1].data[0] != '$') {
  695.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  696.                            "invalid variable name \"%V\"", &value[1]);
  697.         return NGX_CONF_ERROR;
  698.     }

  699.     value[1].len--;
  700.     value[1].data++;

  701.     v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE);
  702.     if (v == NULL) {
  703.         return NGX_CONF_ERROR;
  704.     }

  705.     pv = ngx_palloc(cf->pool, sizeof(ngx_http_perl_variable_t));
  706.     if (pv == NULL) {
  707.         return NGX_CONF_ERROR;
  708.     }

  709.     index = ngx_http_get_variable_index(cf, &value[1]);
  710.     if (index == NGX_ERROR) {
  711.         return NGX_CONF_ERROR;
  712.     }

  713.     pmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_perl_module);

  714.     if (pmcf->perl == NULL) {
  715.         if (ngx_http_perl_init_interpreter(cf, pmcf) != NGX_CONF_OK) {
  716.             return NGX_CONF_ERROR;
  717.         }
  718.     }

  719.     pv->handler = value[2];

  720.     {

  721.     dTHXa(pmcf->perl);
  722.     PERL_SET_CONTEXT(pmcf->perl);

  723.     ngx_http_perl_eval_anon_sub(aTHX_ &value[2], &pv->sub);

  724.     if (pv->sub == &PL_sv_undef) {
  725.         ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
  726.                            "eval_pv(\"%V\") failed", &value[2]);
  727.         return NGX_CONF_ERROR;
  728.     }

  729.     if (pv->sub == NULL) {
  730.         pv->sub = newSVpvn((char *) value[2].data, value[2].len);
  731.     }

  732.     }

  733.     v->get_handler = ngx_http_perl_variable;
  734.     v->data = (uintptr_t) pv;

  735.     return NGX_CONF_OK;
  736. }


  737. static ngx_int_t
  738. ngx_http_perl_init_worker(ngx_cycle_t *cycle)
  739. {
  740.     ngx_http_perl_main_conf_t  *pmcf;

  741.     pmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_perl_module);

  742.     if (pmcf) {
  743.         dTHXa(pmcf->perl);
  744.         PERL_SET_CONTEXT(pmcf->perl);

  745.         /* set worker's $$ */

  746.         sv_setiv(GvSV(gv_fetchpv("$", TRUE, SVt_PV)), (I32) ngx_pid);
  747.     }

  748.     return NGX_OK;
  749. }


  750. static void
  751. ngx_http_perl_exit(ngx_cycle_t *cycle)
  752. {
  753. #if (NGX_HAVE_PERL_MULTIPLICITY)

  754.     /*
  755.      * the master exit hook is run before global pool cleanup,
  756.      * therefore just set flag here
  757.      */

  758.     ngx_perl_term = 1;

  759. #else

  760.     if (nginx_stash) {
  761.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, "perl term");

  762.         (void) perl_destruct(perl);

  763.         perl_free(perl);

  764.         PERL_SYS_TERM();
  765.     }

  766. #endif
  767. }