From 69f781731cd773120ee170978e78e086d75e9331 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Sun, 3 Dec 2017 17:11:20 -0800 Subject: [PATCH 1/2] feature: implemented a configure_by_lua phase. --- config | 2 + src/ngx_http_lua_common.h | 5 + src/ngx_http_lua_configureby.c | 287 +++++++++++++++++++++++++++++++++ src/ngx_http_lua_configureby.h | 35 ++++ src/ngx_http_lua_directive.c | 2 +- src/ngx_http_lua_module.c | 24 +++ src/ngx_http_lua_phase.c | 6 + src/ngx_http_lua_shdict.c | 138 +++++++++------- src/ngx_http_lua_shdict.h | 6 + src/ngx_http_lua_util.c | 1 + t/156-configure-by.t | 284 ++++++++++++++++++++++++++++++++ 11 files changed, 733 insertions(+), 57 deletions(-) create mode 100644 src/ngx_http_lua_configureby.c create mode 100644 src/ngx_http_lua_configureby.h create mode 100644 t/156-configure-by.t diff --git a/config b/config index 044deb974e..f12e9c3b94 100644 --- a/config +++ b/config @@ -344,6 +344,7 @@ HTTP_LUA_SRCS=" \ $ngx_addon_dir/src/ngx_http_lua_semaphore.c\ $ngx_addon_dir/src/ngx_http_lua_coroutine.c \ $ngx_addon_dir/src/ngx_http_lua_bodyfilterby.c \ + $ngx_addon_dir/src/ngx_http_lua_configureby.c \ $ngx_addon_dir/src/ngx_http_lua_initby.c \ $ngx_addon_dir/src/ngx_http_lua_initworkerby.c \ $ngx_addon_dir/src/ngx_http_lua_socket_udp.c \ @@ -405,6 +406,7 @@ HTTP_LUA_DEPS=" \ $ngx_addon_dir/src/ngx_http_lua_semaphore.h\ $ngx_addon_dir/src/ngx_http_lua_coroutine.h \ $ngx_addon_dir/src/ngx_http_lua_bodyfilterby.h \ + $ngx_addon_dir/src/ngx_http_lua_configureby.h \ $ngx_addon_dir/src/ngx_http_lua_initby.h \ $ngx_addon_dir/src/ngx_http_lua_initworkerby.h \ $ngx_addon_dir/src/ngx_http_lua_socket_udp.h \ diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h index 3bfaa09054..8139eddbec 100644 --- a/src/ngx_http_lua_common.h +++ b/src/ngx_http_lua_common.h @@ -148,6 +148,8 @@ typedef struct ngx_http_lua_balancer_peer_data_s typedef struct ngx_http_lua_sema_mm_s ngx_http_lua_sema_mm_t; +typedef ngx_int_t (*ngx_http_lua_configure_handler_pt)(ngx_conf_t *cf, + ngx_http_lua_main_conf_t *lmcf); typedef ngx_int_t (*ngx_http_lua_main_conf_handler_pt)(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, lua_State *L); typedef ngx_int_t (*ngx_http_lua_srv_conf_handler_pt)(ngx_http_request_t *r, @@ -198,6 +200,9 @@ struct ngx_http_lua_main_conf_s { ngx_flag_t postponed_to_rewrite_phase_end; ngx_flag_t postponed_to_access_phase_end; + ngx_http_lua_configure_handler_pt configure_handler; + ngx_str_t configure_src; + ngx_http_lua_main_conf_handler_pt init_handler; ngx_str_t init_src; diff --git a/src/ngx_http_lua_configureby.c b/src/ngx_http_lua_configureby.c new file mode 100644 index 0000000000..d798c27200 --- /dev/null +++ b/src/ngx_http_lua_configureby.c @@ -0,0 +1,287 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + * + * Author: Thibault Charbonnier (thibaultcha) + * I hereby assign copyright in this code to the lua-nginx-module project, + * to be licensed under the same terms as the rest of the code. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif + + +#include "ddebug.h" +#include "ngx_http_lua_configureby.h" +#include "ngx_http_lua_directive.h" +#include "ngx_http_lua_util.h" +#include "ngx_http_lua_shdict.h" +#include "ngx_http_lua_api.h" + + +static ngx_conf_t *cfp; + + +char * +ngx_http_lua_configure_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *rv; + ngx_conf_t save; + + save = *cf; + cf->handler = ngx_http_lua_configure_by_lua; + cf->handler_conf = conf; + + rv = ngx_http_lua_conf_lua_block_parse(cf, cmd); + + *cf = save; + + return rv; +} + + +char * +ngx_http_lua_configure_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + u_char *name; + ngx_str_t *value; + ngx_http_lua_main_conf_t *lmcf = conf; + + if (cmd->post == NULL) { + return NGX_CONF_ERROR; + } + + if (lmcf->configure_handler) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (value[1].len == 0) { + ngx_conf_log_error(NGX_LOG_ERR, cf, 0, + "invalid location config: no runnable Lua code"); + return NGX_CONF_ERROR; + } + + lmcf->configure_handler = (ngx_http_lua_configure_handler_pt) cmd->post; + + if (cmd->post == ngx_http_lua_configure_handler_file) { + name = ngx_http_lua_rebase_path(cf->pool, value[1].data, + value[1].len); + if (name == NULL) { + return NGX_CONF_ERROR; + } + + lmcf->configure_src.data = name; + lmcf->configure_src.len = ngx_strlen(name); + + } else { + lmcf->configure_src = value[1]; + } + + return NGX_CONF_OK; +} + + +ngx_int_t +ngx_http_lua_configure_handler_inline(ngx_conf_t *cf, + ngx_http_lua_main_conf_t *lmcf) +{ + int status; + lua_State *L = lmcf->lua; + + cfp = cf; + + status = luaL_loadbuffer(L, (char *) lmcf->configure_src.data, + lmcf->configure_src.len, "=configure_by_lua") + || ngx_http_lua_do_call(cf->log, L); + + cfp = NULL; + + return ngx_http_lua_report(cf->log, L, status, "configure_by_lua"); +} + + +ngx_int_t +ngx_http_lua_configure_handler_file(ngx_conf_t *cf, + ngx_http_lua_main_conf_t *lmcf) +{ + int status; + lua_State *L = lmcf->lua; + + cfp = cf; + + status = luaL_loadfile(L, (char *) lmcf->configure_src.data) + || ngx_http_lua_do_call(cf->log, L); + + cfp = NULL; + + return ngx_http_lua_report(cf->log, L, status, "configure_by_lua_file"); +} + + +ngx_uint_t +ngx_http_lua_is_configure_phase() +{ + return cfp != NULL; +} + + +#ifndef NGX_LUA_NO_FFI_API +unsigned int +ngx_http_lua_ffi_is_configure_phase() +{ + return ngx_http_lua_is_configure_phase(); +} + + +int +ngx_http_lua_ffi_configure_shared_dict(ngx_str_t *name, ngx_str_t *size, + u_char *errstr, size_t *err_len) +{ + ssize_t ssize; + ngx_shm_zone_t **zp; + ngx_shm_zone_t *zone; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_main_conf_t *lmcf; + lua_State *L; + ngx_conf_t *cf = cfp; + + lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); + + ssize = ngx_parse_size(size); + if (ssize <= NGX_HTTP_LUA_SHDICT_MINSIZE) { + *err_len = ngx_snprintf(errstr, *err_len, + "invalid lua shared dict size \"%s\"", + size->data) + - errstr; + return NGX_ERROR; + } + + ctx = ngx_pcalloc(cf->cycle->pool, sizeof(ngx_http_lua_shdict_ctx_t)); + if (ctx == NULL) { + *err_len = ngx_snprintf(errstr, *err_len, "no memory") + - errstr; + return NGX_ERROR; + } + + ctx->name = *name; + ctx->main_conf = lmcf; + ctx->log = &cf->cycle->new_log; + + zone = ngx_http_lua_shared_memory_add(cf, name, (size_t) ssize, + &ngx_http_lua_module); + if (zone == NULL) { + *err_len = ngx_snprintf(errstr, *err_len, "no memory") + - errstr; + return NGX_ERROR; + } + + if (zone->data) { + return NGX_DECLINED; + } + + zone->init = ngx_http_lua_shdict_init_zone; + zone->data = ctx; + + if (lmcf->shdict_zones == NULL) { + lmcf->shdict_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); + if (lmcf->shdict_zones == NULL) { + *err_len = ngx_snprintf(errstr, *err_len, "no memory") + - errstr; + return NGX_ERROR; + } + + if (ngx_array_init(lmcf->shdict_zones, cf->pool, 2, + sizeof(ngx_shm_zone_t *)) + != NGX_OK) + { + *err_len = ngx_snprintf(errstr, *err_len, "no memory") + - errstr; + return NGX_ERROR; + } + } + + zp = ngx_array_push(lmcf->shdict_zones); + if (zp == NULL) { + *err_len = ngx_snprintf(errstr, *err_len, "no memory") + - errstr; + return NGX_ERROR; + } + + *zp = zone; + + L = lmcf->lua; + + lua_getglobal(L, "ngx"); + lua_getfield(L, -1, "shared"); + if (!lua_getmetatable(L, -1)) { + ngx_http_lua_create_shdict_mt(L); /* ngx.shared shmt */ + } + + ngx_http_lua_attach_shdict(L, name, zone); + lua_pop(L, 2); /* pop: ngx.shared + shmt */ + + return NGX_OK; +} + + +void +ngx_http_lua_ffi_configure_max_pending_timers(int n_timers) +{ + + ngx_http_lua_main_conf_t *lmcf; + ngx_conf_t *cf = cfp; + + lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); + + lmcf->max_pending_timers = (ngx_int_t) n_timers; +} + + +void +ngx_http_lua_ffi_configure_max_running_timers(int n_timers) +{ + + ngx_http_lua_main_conf_t *lmcf; + ngx_conf_t *cf = cfp; + + lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); + + lmcf->max_running_timers = (ngx_int_t) n_timers; +} + + +int +ngx_http_lua_ffi_configure_env(u_char *value, size_t name_len, size_t len) +{ + ngx_core_conf_t *ccf; + ngx_str_t *var; + ngx_conf_t *cf = cfp; + + ccf = (ngx_core_conf_t *) ngx_get_conf(cf->cycle->conf_ctx, + ngx_core_module); + + var = ngx_array_push(&ccf->env); + if (var == NULL) { + return NGX_ERROR; + } + + var->data = ngx_pnalloc(cf->pool, len); + if (var->data == NULL) { + return NGX_ERROR; + } + + (void) ngx_copy(var->data, value, len); + var->len = name_len; + + return NGX_OK; +} +#endif + + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_configureby.h b/src/ngx_http_lua_configureby.h new file mode 100644 index 0000000000..59a91f0040 --- /dev/null +++ b/src/ngx_http_lua_configureby.h @@ -0,0 +1,35 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + * + * Author: Thibault Charbonnier (thibaultcha) + * I hereby assign copyright in this code to the lua-nginx-module project, + * to be licensed under the same terms as the rest of the code. + */ + + +#ifndef _NGX_HTTP_LUA_CONFIGUREBY_H_INCLUDED_ +#define _NGX_HTTP_LUA_CONFIGUREBY_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +char *ngx_http_lua_configure_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +char *ngx_http_lua_configure_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + +ngx_int_t ngx_http_lua_configure_handler_inline(ngx_conf_t *cf, + ngx_http_lua_main_conf_t *lmcf); + +ngx_int_t ngx_http_lua_configure_handler_file(ngx_conf_t *cf, + ngx_http_lua_main_conf_t *lmcf); + +ngx_uint_t ngx_http_lua_is_configure_phase(); + + +#endif /* _NGX_HTTP_LUA_CONFIGUREBY_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index fb8c6dc5bf..8ff6760962 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -109,7 +109,7 @@ ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) size = ngx_parse_size(&value[2]); - if (size <= 8191) { + if (size <= NGX_HTTP_LUA_SHDICT_MINSIZE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid lua shared dict size \"%V\"", &value[2]); return NGX_CONF_ERROR; diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c index ae8bc0e36f..5554e48f4b 100644 --- a/src/ngx_http_lua_module.c +++ b/src/ngx_http_lua_module.c @@ -20,6 +20,7 @@ #include "ngx_http_lua_util.h" #include "ngx_http_lua_headerfilterby.h" #include "ngx_http_lua_bodyfilterby.h" +#include "ngx_http_lua_configureby.h" #include "ngx_http_lua_initby.h" #include "ngx_http_lua_initworkerby.h" #include "ngx_http_lua_probe.h" @@ -166,6 +167,20 @@ static ngx_command_t ngx_http_lua_cmds[] = { offsetof(ngx_http_lua_loc_conf_t, log_socket_errors), NULL }, + { ngx_string("configure_by_lua_block"), + NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_http_lua_configure_by_lua_block, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + (void *) ngx_http_lua_configure_handler_inline }, + + { ngx_string("configure_by_lua_file"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_lua_configure_by_lua, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + (void *) ngx_http_lua_configure_handler_file }, + { ngx_string("init_by_lua_block"), NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, ngx_http_lua_init_by_lua_block, @@ -752,6 +767,13 @@ ngx_http_lua_init(ngx_conf_t *cf) return NGX_ERROR; } + if (lmcf->configure_handler) { + rc = lmcf->configure_handler(cf, lmcf); + if (rc != NGX_OK) { + return NGX_ERROR; + } + } + if (!lmcf->requires_shm && lmcf->init_handler) { saved_cycle = ngx_cycle; ngx_cycle = cf->cycle; @@ -826,6 +848,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) * lmcf->regex_cache_entries = 0; * lmcf->jit_stack = NULL; * lmcf->shm_zones = NULL; + * lmcf->configure_handler = NULL; + * lmcf->configure_src = { 0, NULL }; * lmcf->init_handler = NULL; * lmcf->init_src = { 0, NULL }; * lmcf->shm_zones_inited = 0; diff --git a/src/ngx_http_lua_phase.c b/src/ngx_http_lua_phase.c index 304c88ae13..21710d5cc0 100644 --- a/src/ngx_http_lua_phase.c +++ b/src/ngx_http_lua_phase.c @@ -13,6 +13,7 @@ #include "ngx_http_lua_phase.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_ctx.h" +#include "ngx_http_lua_configureby.h" static int ngx_http_lua_ngx_get_phase(lua_State *L); @@ -30,6 +31,11 @@ ngx_http_lua_ngx_get_phase(lua_State *L) * phase. */ if (r == NULL) { + if (ngx_http_lua_is_configure_phase(L)) { + lua_pushliteral(L, "configure"); + return 1; + } + lua_pushliteral(L, "init"); return 1; } diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index b300673e82..a05f291b72 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -10,6 +10,7 @@ #include "ddebug.h" +#include "ngx_http_lua_configureby.h" #include "ngx_http_lua_shdict.h" #include "ngx_http_lua_util.h" #include "ngx_http_lua_api.h" @@ -320,93 +321,113 @@ ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, ngx_uint_t n) void -ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) +ngx_http_lua_create_shdict_mt(lua_State *L) { - ngx_http_lua_shdict_ctx_t *ctx; - ngx_uint_t i; - ngx_shm_zone_t **zone; + lua_createtable(L, 0 /* narr */, 18 /* nrec */); + /* ngx ngx.shared shmt */ - if (lmcf->shdict_zones != NULL) { - lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); - /* ngx.shared */ + lua_pushcfunction(L, ngx_http_lua_shdict_get); + lua_setfield(L, -2, "get"); - lua_createtable(L, 0 /* narr */, 18 /* nrec */); /* shared mt */ + lua_pushcfunction(L, ngx_http_lua_shdict_get_stale); + lua_setfield(L, -2, "get_stale"); - lua_pushcfunction(L, ngx_http_lua_shdict_get); - lua_setfield(L, -2, "get"); + lua_pushcfunction(L, ngx_http_lua_shdict_set); + lua_setfield(L, -2, "set"); - lua_pushcfunction(L, ngx_http_lua_shdict_get_stale); - lua_setfield(L, -2, "get_stale"); + lua_pushcfunction(L, ngx_http_lua_shdict_safe_set); + lua_setfield(L, -2, "safe_set"); - lua_pushcfunction(L, ngx_http_lua_shdict_set); - lua_setfield(L, -2, "set"); + lua_pushcfunction(L, ngx_http_lua_shdict_add); + lua_setfield(L, -2, "add"); - lua_pushcfunction(L, ngx_http_lua_shdict_safe_set); - lua_setfield(L, -2, "safe_set"); + lua_pushcfunction(L, ngx_http_lua_shdict_safe_add); + lua_setfield(L, -2, "safe_add"); - lua_pushcfunction(L, ngx_http_lua_shdict_add); - lua_setfield(L, -2, "add"); + lua_pushcfunction(L, ngx_http_lua_shdict_replace); + lua_setfield(L, -2, "replace"); - lua_pushcfunction(L, ngx_http_lua_shdict_safe_add); - lua_setfield(L, -2, "safe_add"); + lua_pushcfunction(L, ngx_http_lua_shdict_incr); + lua_setfield(L, -2, "incr"); - lua_pushcfunction(L, ngx_http_lua_shdict_replace); - lua_setfield(L, -2, "replace"); + lua_pushcfunction(L, ngx_http_lua_shdict_delete); + lua_setfield(L, -2, "delete"); - lua_pushcfunction(L, ngx_http_lua_shdict_incr); - lua_setfield(L, -2, "incr"); + lua_pushcfunction(L, ngx_http_lua_shdict_lpush); + lua_setfield(L, -2, "lpush"); - lua_pushcfunction(L, ngx_http_lua_shdict_delete); - lua_setfield(L, -2, "delete"); + lua_pushcfunction(L, ngx_http_lua_shdict_rpush); + lua_setfield(L, -2, "rpush"); - lua_pushcfunction(L, ngx_http_lua_shdict_lpush); - lua_setfield(L, -2, "lpush"); + lua_pushcfunction(L, ngx_http_lua_shdict_lpop); + lua_setfield(L, -2, "lpop"); - lua_pushcfunction(L, ngx_http_lua_shdict_rpush); - lua_setfield(L, -2, "rpush"); + lua_pushcfunction(L, ngx_http_lua_shdict_rpop); + lua_setfield(L, -2, "rpop"); - lua_pushcfunction(L, ngx_http_lua_shdict_lpop); - lua_setfield(L, -2, "lpop"); + lua_pushcfunction(L, ngx_http_lua_shdict_llen); + lua_setfield(L, -2, "llen"); - lua_pushcfunction(L, ngx_http_lua_shdict_rpop); - lua_setfield(L, -2, "rpop"); + lua_pushcfunction(L, ngx_http_lua_shdict_flush_all); + lua_setfield(L, -2, "flush_all"); - lua_pushcfunction(L, ngx_http_lua_shdict_llen); - lua_setfield(L, -2, "llen"); + lua_pushcfunction(L, ngx_http_lua_shdict_flush_expired); + lua_setfield(L, -2, "flush_expired"); - lua_pushcfunction(L, ngx_http_lua_shdict_flush_all); - lua_setfield(L, -2, "flush_all"); + lua_pushcfunction(L, ngx_http_lua_shdict_get_keys); + lua_setfield(L, -2, "get_keys"); - lua_pushcfunction(L, ngx_http_lua_shdict_flush_expired); - lua_setfield(L, -2, "flush_expired"); + lua_pushvalue(L, -1); /* ngx ngx.shared shmt shmt */ + lua_setfield(L, -2, "__index"); /* ngx ngx.shared shmt */ +} - lua_pushcfunction(L, ngx_http_lua_shdict_get_keys); - lua_setfield(L, -2, "get_keys"); - lua_pushvalue(L, -1); /* shared mt mt */ - lua_setfield(L, -2, "__index"); /* shared mt */ +void +ngx_http_lua_attach_shdict(lua_State *L, ngx_str_t *name, ngx_shm_zone_t *zone) +{ + lua_pushlstring(L, (char *) name->data, name->len); + /* ngx ngx.shared shmt name */ + lua_createtable(L, 1 /* narr */, 0 /* nrec */); /* table of zone[i] */ + /* ngx ngx.shared shmt name tzone */ + lua_pushlightuserdata(L, zone); + /* ngx ngx.shared shmt name tzone ud */ + lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); + /* ngx ngx.shared shmt name tzone */ + lua_pushvalue(L, -3); + /* ngx ngx.shared shmt name tzone shmt */ + lua_setmetatable(L, -2); + /* ngx ngx.shared shmt name tzone */ + lua_rawset(L, -4); + /* ngx ngx.shared shmt */ +} + + +void +ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) +{ + ngx_http_lua_shdict_ctx_t *ctx; + ngx_uint_t i; + ngx_shm_zone_t **zone; + + if (lmcf->shdict_zones != NULL) { + lua_createtable(L, 0, lmcf->shdict_zones->nelts /* nrec */); + /* ngx ngx.shared */ + + ngx_http_lua_create_shdict_mt(L); + /* ngx ngx.shared shmt */ zone = lmcf->shdict_zones->elts; for (i = 0; i < lmcf->shdict_zones->nelts; i++) { ctx = zone[i]->data; - lua_pushlstring(L, (char *) ctx->name.data, ctx->name.len); - /* shared mt key */ - - lua_createtable(L, 1 /* narr */, 0 /* nrec */); - /* table of zone[i] */ - lua_pushlightuserdata(L, zone[i]); /* shared mt key ud */ - lua_rawseti(L, -2, SHDICT_USERDATA_INDEX); /* {zone[i]} */ - lua_pushvalue(L, -3); /* shared mt key ud mt */ - lua_setmetatable(L, -2); /* shared mt key ud */ - lua_rawset(L, -4); /* shared mt */ + ngx_http_lua_attach_shdict(L, &ctx->name, zone[i]); } - lua_pop(L, 1); /* shared */ + lua_pop(L, 1); /* ngx ngx.shared */ } else { - lua_newtable(L); /* ngx.shared */ + lua_newtable(L); /* ngx ngx.shared */ } lua_setfield(L, -2, "shared"); @@ -432,6 +453,11 @@ ngx_http_lua_shdict_get_zone(lua_State *L, int index) { ngx_shm_zone_t *zone; + if (ngx_http_lua_is_configure_phase(L)) { + luaL_error(L, "API disabled in the context of configure_by_lua"); + return NULL; + } + lua_rawgeti(L, index, SHDICT_USERDATA_INDEX); zone = lua_touserdata(L, -1); lua_pop(L, 1); diff --git a/src/ngx_http_lua_shdict.h b/src/ngx_http_lua_shdict.h index 90a0099f5d..9d83c07ef5 100644 --- a/src/ngx_http_lua_shdict.h +++ b/src/ngx_http_lua_shdict.h @@ -8,6 +8,9 @@ #define _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ +#define NGX_HTTP_LUA_SHDICT_MINSIZE 8191 + + #include "ngx_http_lua_common.h" @@ -58,6 +61,9 @@ typedef struct { ngx_int_t ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data); void ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +void ngx_http_lua_attach_shdict(lua_State *L, ngx_str_t *name, + ngx_shm_zone_t *zone); +void ngx_http_lua_create_shdict_mt(lua_State *L); void ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L); diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index c2d5c41147..537b0d8283 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -44,6 +44,7 @@ #include "ngx_http_lua_phase.h" #include "ngx_http_lua_probe.h" #include "ngx_http_lua_uthread.h" +#include "ngx_http_lua_configureby.h" #include "ngx_http_lua_contentby.h" #include "ngx_http_lua_timer.h" #include "ngx_http_lua_config.h" diff --git a/t/156-configure-by.t b/t/156-configure-by.t new file mode 100644 index 0000000000..089b09ff47 --- /dev/null +++ b/t/156-configure-by.t @@ -0,0 +1,284 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use Test::Nginx::Socket::Lua; + +log_level('notice'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 5); + +#no_diff(); +#no_long_string(); +check_accum_error_log(); + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- http_config + configure_by_lua_block { + _G.configure_by = true + } +--- config + location /t { + content_by_lua_block { + ngx.say("configure_by: ", configure_by) + } + } +--- request +GET /t +--- response_body +configure_by: true +--- no_error_log +[error] +[crit] +[alert] +[emerg] + + + +=== TEST 2: duplicate +--- http_config + configure_by_lua_block { + + } + + configure_by_lua_block { + + } +--- config + location /t { + return 200; + } +--- must_die +--- error_log eval +qr/\[emerg\] .*? is duplicate/ +--- no_error_log +[error] +[crit] +[alert] + + + +=== TEST 3: wrong block +--- http_config +--- config + location /t { + configure_by_lua_block { + + } + } +--- must_die +--- error_log eval +qr/\[emerg\] .*? directive is not allowed here/ +--- no_error_log +[error] +[crit] +[alert] + + + +=== TEST 4: print +--- http_config + configure_by_lua_block { + print("hello from configure_by_lua") + } +--- config + location /t { + return 200; + } +--- request +GET /t +--- error_log eval +qr/\[notice\] .*? configure_by_lua:\d+: hello from configure_by_lua/ +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 5: ngx.log +--- http_config + configure_by_lua_block { + ngx.log(ngx.NOTICE, "hello from ngx.log in configure_by_lua") + } +--- config + location /t { + return 200; + } +--- request +GET /t +--- error_log eval +qr/\[notice\] .*? configure_by_lua:\d+: hello from ngx\.log in configure_by_lua/ +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 6: ngx.get_phase +--- http_config + configure_by_lua_block { + ngx.log(ngx.NOTICE, "phase: ", ngx.get_phase()) + } +--- config + location /t { + return 200; + } +--- request +GET /t +--- error_log eval +qr/\[notice\] .*? configure_by_lua:\d+: phase: configure/ +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 7: sanity (by_lua_file) +--- http_config + configure_by_lua_file html/configure.lua; +--- config + location /t { + content_by_lua_block { + ngx.say("configure_by: ", configure_by) + } + } +--- user_files +>>> configure.lua +_G.configure_by = true +--- request +GET /t +--- response_body +configure_by: true +--- no_error_log +[error] +[crit] +[alert] + + + +=== TEST 8: duplicate (by_lua_file) +--- http_config + configure_by_lua_file html/configure.lua; + configure_by_lua_file html/configure.lua; +--- config + location /t { + return 200; + } +--- user_files +>>> configure.lua +_G.configure_by = true +--- must_die +--- error_log eval +qr/\[emerg\] .*? is duplicate/ +--- no_error_log +[error] +[crit] +[alert] + + + +=== TEST 9: invalid directive argument (by_lua_file) +--- http_config + configure_by_lua_file ''; +--- config + location /t { + return 200; + } +--- must_die +--- error_log eval +qr/\[error\] .*? invalid location config: no runnable Lua code in/ +--- no_error_log +[crit] +[alert] +[emerg] + + + +=== TEST 10: ngx.get_phase (by_lua_file) +--- http_config + configure_by_lua_file html/configure.lua; +--- config + location /t { + return 200; + } +--- user_files +>>> configure.lua +ngx.log(ngx.NOTICE, "phase: ", ngx.get_phase()) +--- request +GET /t +--- error_log eval +qr/\[notice\] .*? configure\.lua:\d+: phase: configure/ +--- no_error_log +[error] +[alert] +[emerg] + + + +=== TEST 11: error in configure causes exit +--- http_config + configure_by_lua_block { + error("failed to configure") + } +--- config + location /t { + return 200; + } +--- must_die +--- error_log eval +qr/\[error\] .*? configure_by_lua:\d+: failed to configure/ +--- no_error_log +[alert] +[emerg] + + + +=== TEST 12: disabled API (ngx.timer.at) +--- http_config + configure_by_lua_block { + local pok, err = pcall(ngx.timer.at, 0, function() end) + if not pok then + print(err) + end + } +--- config + location /t { + return 200; + } +--- request +GET /t +--- error_log eval +qr/\[notice\] .*? configure_by_lua:\d+: no request/ +--- no_error_log +[crit] +[alert] +[emerg] + + + +=== TEST 13: disabled API (ngx.socket.tcp) +--- http_config + configure_by_lua_block { + local pok, err = pcall(ngx.socket.tcp) + if not pok then + print(err) + end + } +--- config + location /t { + return 200; + } +--- request +GET /t +--- error_log eval +qr/\[notice\] .*? configure_by_lua:\d+: no request/ +--- no_error_log +[crit] +[alert] +[emerg] From 545deb04d828d80711d3c3fa37f201bcd666a909 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Sun, 18 Feb 2018 14:28:50 -0800 Subject: [PATCH 2/2] refactor: configure: avoid duplicated code for shm creation. --- src/ngx_http_lua_api.c | 5 +- src/ngx_http_lua_configureby.c | 83 +++++++++------------------------- src/ngx_http_lua_directive.c | 68 +++++----------------------- src/ngx_http_lua_shdict.c | 70 +++++++++++++++++++++++++++- src/ngx_http_lua_shdict.h | 2 + 5 files changed, 104 insertions(+), 124 deletions(-) diff --git a/src/ngx_http_lua_api.c b/src/ngx_http_lua_api.c index 7b590e7a9f..b8fbfc684b 100644 --- a/src/ngx_http_lua_api.c +++ b/src/ngx_http_lua_api.c @@ -91,7 +91,6 @@ ngx_http_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, ngx_shm_zone_t **zp; ngx_shm_zone_t *zone; ngx_http_lua_shm_zone_ctx_t *ctx; - ngx_int_t n; lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); if (lmcf == NULL) { @@ -122,9 +121,7 @@ ngx_http_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, return &ctx->zone; } - n = sizeof(ngx_http_lua_shm_zone_ctx_t); - - ctx = ngx_pcalloc(cf->pool, n); + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_shm_zone_ctx_t)); if (ctx == NULL) { return NULL; } diff --git a/src/ngx_http_lua_configureby.c b/src/ngx_http_lua_configureby.c index d798c27200..d7bb880143 100644 --- a/src/ngx_http_lua_configureby.c +++ b/src/ngx_http_lua_configureby.c @@ -143,88 +143,49 @@ int ngx_http_lua_ffi_configure_shared_dict(ngx_str_t *name, ngx_str_t *size, u_char *errstr, size_t *err_len) { - ssize_t ssize; - ngx_shm_zone_t **zp; - ngx_shm_zone_t *zone; - ngx_http_lua_shdict_ctx_t *ctx; - ngx_http_lua_main_conf_t *lmcf; - lua_State *L; - ngx_conf_t *cf = cfp; + ngx_int_t rc; + ssize_t ssize; + lua_State *L; + ngx_http_lua_main_conf_t *lmcf; + ngx_conf_t *cf = cfp; + ngx_shm_zone_t **zone; lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); ssize = ngx_parse_size(size); if (ssize <= NGX_HTTP_LUA_SHDICT_MINSIZE) { *err_len = ngx_snprintf(errstr, *err_len, - "invalid lua shared dict size \"%s\"", - size->data) - - errstr; - return NGX_ERROR; - } - - ctx = ngx_pcalloc(cf->cycle->pool, sizeof(ngx_http_lua_shdict_ctx_t)); - if (ctx == NULL) { - *err_len = ngx_snprintf(errstr, *err_len, "no memory") + "invalid lua shared dict size \"%s\"", + size->data) - errstr; - return NGX_ERROR; - } - - ctx->name = *name; - ctx->main_conf = lmcf; - ctx->log = &cf->cycle->new_log; - - zone = ngx_http_lua_shared_memory_add(cf, name, (size_t) ssize, - &ngx_http_lua_module); - if (zone == NULL) { - *err_len = ngx_snprintf(errstr, *err_len, "no memory") - - errstr; - return NGX_ERROR; - } - - if (zone->data) { return NGX_DECLINED; } - zone->init = ngx_http_lua_shdict_init_zone; - zone->data = ctx; - - if (lmcf->shdict_zones == NULL) { - lmcf->shdict_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); - if (lmcf->shdict_zones == NULL) { - *err_len = ngx_snprintf(errstr, *err_len, "no memory") - - errstr; - return NGX_ERROR; - } - - if (ngx_array_init(lmcf->shdict_zones, cf->pool, 2, - sizeof(ngx_shm_zone_t *)) - != NGX_OK) - { - *err_len = ngx_snprintf(errstr, *err_len, "no memory") + rc = ngx_http_lua_shared_dict_add(cf, name, ssize); + if (rc != NGX_OK) { + if (rc == NGX_DECLINED) { + *err_len = ngx_snprintf(errstr, *err_len, + "lua_shared_dict \"%V\" is already defined" + " as \"%V\"", name, name) - errstr; - return NGX_ERROR; } - } - zp = ngx_array_push(lmcf->shdict_zones); - if (zp == NULL) { - *err_len = ngx_snprintf(errstr, *err_len, "no memory") - - errstr; - return NGX_ERROR; + return rc; } - *zp = zone; + zone = lmcf->shdict_zones->elts; L = lmcf->lua; lua_getglobal(L, "ngx"); lua_getfield(L, -1, "shared"); - if (!lua_getmetatable(L, -1)) { - ngx_http_lua_create_shdict_mt(L); /* ngx.shared shmt */ - } + ngx_http_lua_create_shdict_mt(L); + + /* ngx ngx.shared shmt */ + + ngx_http_lua_attach_shdict(L, name, zone[lmcf->shdict_zones->nelts - 1]); - ngx_http_lua_attach_shdict(L, name, zone); - lua_pop(L, 2); /* pop: ngx.shared + shmt */ + lua_pop(L, 3); /* pop: ngx ngx.shared shmt */ return NGX_OK; } diff --git a/src/ngx_http_lua_directive.c b/src/ngx_http_lua_directive.c index 8ff6760962..0b533c90c5 100644 --- a/src/ngx_http_lua_directive.c +++ b/src/ngx_http_lua_directive.c @@ -73,40 +73,19 @@ enum { char * ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_http_lua_main_conf_t *lmcf = conf; - ngx_str_t *value, name; - ngx_shm_zone_t *zone; - ngx_shm_zone_t **zp; - ngx_http_lua_shdict_ctx_t *ctx; ssize_t size; - - if (lmcf->shdict_zones == NULL) { - lmcf->shdict_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); - if (lmcf->shdict_zones == NULL) { - return NGX_CONF_ERROR; - } - - if (ngx_array_init(lmcf->shdict_zones, cf->pool, 2, - sizeof(ngx_shm_zone_t *)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - } + ngx_int_t rc; value = cf->args->elts; + name = value[1]; - ctx = NULL; - - if (value[1].len == 0) { + if (name.len == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid lua shared dict name \"%V\"", &value[1]); + "invalid lua shared dict name \"%V\"", &name); return NGX_CONF_ERROR; } - name = value[1]; - size = ngx_parse_size(&value[2]); if (size <= NGX_HTTP_LUA_SHDICT_MINSIZE) { @@ -115,42 +94,17 @@ ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_shdict_ctx_t)); - if (ctx == NULL) { - return NGX_CONF_ERROR; - } - - ctx->name = name; - ctx->main_conf = lmcf; - ctx->log = &cf->cycle->new_log; - - zone = ngx_http_lua_shared_memory_add(cf, &name, (size_t) size, - &ngx_http_lua_module); - if (zone == NULL) { - return NGX_CONF_ERROR; - } - - if (zone->data) { - ctx = zone->data; - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "lua_shared_dict \"%V\" is already defined as " - "\"%V\"", &name, &ctx->name); - return NGX_CONF_ERROR; - } - - zone->init = ngx_http_lua_shdict_init_zone; - zone->data = ctx; + rc = ngx_http_lua_shared_dict_add(cf, &name, size); + if (rc != NGX_OK) { + if (rc == NGX_DECLINED) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "lua_shared_dict \"%V\" is already defined as " + "\"%V\"", &name, &name); + } - zp = ngx_array_push(lmcf->shdict_zones); - if (zp == NULL) { return NGX_CONF_ERROR; } - *zp = zone; - - lmcf->requires_shm = 1; - return NGX_CONF_OK; } diff --git a/src/ngx_http_lua_shdict.c b/src/ngx_http_lua_shdict.c index a05f291b72..df1dbc51cf 100644 --- a/src/ngx_http_lua_shdict.c +++ b/src/ngx_http_lua_shdict.c @@ -79,6 +79,63 @@ ngx_http_lua_shdict_get_list_head(ngx_http_lua_shdict_node_t *sd, size_t len) } +ngx_int_t +ngx_http_lua_shared_dict_add(ngx_conf_t *cf, ngx_str_t *name, ssize_t size) +{ + ngx_http_lua_main_conf_t *lmcf; + ngx_http_lua_shdict_ctx_t *ctx = NULL; + ngx_shm_zone_t *zone; + ngx_shm_zone_t **zp; + + lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); + + if (lmcf->shdict_zones == NULL) { + lmcf->shdict_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t)); + if (lmcf->shdict_zones == NULL) { + return NGX_ERROR; + } + + if (ngx_array_init(lmcf->shdict_zones, cf->pool, 2, + sizeof(ngx_shm_zone_t *)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_shdict_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->name = *name; + ctx->main_conf = lmcf; + ctx->log = &cf->cycle->new_log; + + zone = ngx_http_lua_shared_memory_add(cf, name, (size_t) size, + &ngx_http_lua_module); + if (zone == NULL) { + return NGX_ERROR; + } + + if (zone->data) { + return NGX_DECLINED; + } + + zone->init = ngx_http_lua_shdict_init_zone; + zone->data = ctx; + + zp = ngx_array_push(lmcf->shdict_zones); + if (zp == NULL) { + return NGX_ERROR; + } + + *zp = zone; + + return NGX_OK; +} + + ngx_int_t ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data) { @@ -323,6 +380,15 @@ ngx_http_lua_shdict_expire(ngx_http_lua_shdict_ctx_t *ctx, ngx_uint_t n) void ngx_http_lua_create_shdict_mt(lua_State *L) { + /* ngx ngx.shared */ + + if (lua_getmetatable(L, -1)) { + /* when no lua_shared_dict directives have been set, but we + * we add a dict via the configure phase, we lazily create the + * shdict mt. This avoids creating it multiple times. */ + return; + } + lua_createtable(L, 0 /* narr */, 18 /* nrec */); /* ngx ngx.shared shmt */ @@ -383,7 +449,8 @@ ngx_http_lua_create_shdict_mt(lua_State *L) void -ngx_http_lua_attach_shdict(lua_State *L, ngx_str_t *name, ngx_shm_zone_t *zone) +ngx_http_lua_attach_shdict(lua_State *L, ngx_str_t *name, + ngx_shm_zone_t *zone) { lua_pushlstring(L, (char *) name->data, name->len); /* ngx ngx.shared shmt name */ @@ -414,7 +481,6 @@ ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, lua_State *L) /* ngx ngx.shared */ ngx_http_lua_create_shdict_mt(L); - /* ngx ngx.shared shmt */ zone = lmcf->shdict_zones->elts; diff --git a/src/ngx_http_lua_shdict.h b/src/ngx_http_lua_shdict.h index 9d83c07ef5..1b40b8a1bb 100644 --- a/src/ngx_http_lua_shdict.h +++ b/src/ngx_http_lua_shdict.h @@ -58,6 +58,8 @@ typedef struct { } ngx_http_lua_shm_zone_ctx_t; +ngx_int_t ngx_http_lua_shared_dict_add(ngx_conf_t *cf, ngx_str_t *name, + ssize_t size); ngx_int_t ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data); void ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);