blob: c177659ebab6da7d45324be8e9b83f6df3e1fecf [file] [log] [blame] [raw]
/*
* Copyright (C) Xiaozhe Wang (chaoslawful)
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_lua_setby.h"
#include "ngx_http_lua_exception.h"
#include "ngx_http_lua_util.h"
#include "ngx_http_lua_pcrefix.h"
#include "ngx_http_lua_time.h"
#include "ngx_http_lua_log.h"
#include "ngx_http_lua_regex.h"
#include "ngx_http_lua_variable.h"
#include "ngx_http_lua_string.h"
#include "ngx_http_lua_misc.h"
#include "ngx_http_lua_consts.h"
#include "ngx_http_lua_shdict.h"
#include "ngx_http_lua_util.h"
static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r,
size_t nargs, ngx_http_variable_value_t *args);
/* chars whose addresses are used as keys in Lua VM regsitry */
static char ngx_http_lua_setby_nargs_key;
static char ngx_http_lua_setby_args_key;
ngx_int_t
ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val,
ngx_http_variable_value_t *args, size_t nargs, ngx_str_t *script)
{
size_t i;
ngx_int_t rc;
u_char *err_msg;
size_t len;
u_char *data;
#if (NGX_PCRE)
ngx_pool_t *old_pool;
#endif
dd("nargs: %d", (int) nargs);
dd("set Lua VM panic handler");
lua_atpanic(L, ngx_http_lua_atpanic);
NGX_LUA_EXCEPTION_TRY {
dd("initialize nginx context in Lua VM, code chunk at "
"stack top sp = 1");
ngx_http_lua_set_by_lua_env(L, r, nargs, args);
/* passing directive arguments to the user code */
for (i = 0; i < nargs; i++) {
lua_pushlstring(L, (const char *) args[i].data, args[i].len);
}
#if (NGX_PCRE)
/* XXX: work-around to nginx regex subsystem */
old_pool = ngx_http_lua_pcre_malloc_init(r->pool);
#endif
lua_pushcfunction(L, ngx_http_lua_traceback);
lua_insert(L, 1); /* put it under chunk and args */
dd("protected call user code");
rc = lua_pcall(L, nargs, 1, 1);
dd("after protected call user code");
lua_remove(L, 1); /* remove traceback function */
#if (NGX_PCRE)
/* XXX: work-around to nginx regex subsystem */
ngx_http_lua_pcre_malloc_done(old_pool);
#endif
if (rc != 0) {
/* error occured when running loaded code */
err_msg = (u_char *) lua_tolstring(L, -1, &len);
if (err_msg == NULL) {
err_msg = (u_char *) "unknown reason";
len = sizeof("unknown reason") - 1;
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"failed to run set_by_lua*: %*s", len, err_msg);
lua_settop(L, 0); /* clear remaining elems on stack */
return NGX_ERROR;
}
data = (u_char *) lua_tolstring(L, -1, &len);
if (data) {
val->data = ngx_palloc(r->pool, len);
if (val->data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(val->data, data, len);
val->len = len;
} else {
val->data = NULL;
val->len = 0;
}
} NGX_LUA_EXCEPTION_CATCH {
dd("nginx execution restored");
return NGX_ERROR;
}
/* clear Lua stack */
lua_settop(L, 0);
return NGX_OK;
}
int
ngx_http_lua_setby_param_get(lua_State *L)
{
int idx;
int n;
ngx_http_variable_value_t *v;
idx = luaL_checkint(L, 2);
idx--;
/* get number of args from globals */
lua_pushlightuserdata(L, &ngx_http_lua_setby_nargs_key);
lua_rawget(L, LUA_GLOBALSINDEX);
n = (int) lua_tointeger(L, -1);
/* get args from globals */
lua_pushlightuserdata(L, &ngx_http_lua_setby_args_key);
lua_rawget(L, LUA_GLOBALSINDEX);
v = lua_touserdata(L, -1);
if (idx < 0 || idx > n - 1) {
lua_pushnil(L);
} else {
lua_pushlstring(L, (const char *) (v[idx].data), v[idx].len);
}
return 1;
}
/**
* Set environment table for the given code closure.
*
* Before:
* | code closure | <- top
* | ... |
*
* After:
* | code closure | <- top
* | ... |
* */
static void
ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs,
ngx_http_variable_value_t *args)
{
/* set nginx request pointer to current lua thread's globals table */
ngx_http_lua_set_req(L, r);
lua_pushlightuserdata(L, &ngx_http_lua_setby_nargs_key);
lua_pushinteger(L, nargs);
lua_rawset(L, LUA_GLOBALSINDEX);
lua_pushlightuserdata(L, &ngx_http_lua_setby_args_key);
lua_pushlightuserdata(L, args);
lua_rawset(L, LUA_GLOBALSINDEX);
/**
* we want to create empty environment for current script
*
* newt = {}
* newt["_G"] = newt
* setmetatable(newt, {__index = _G})
*
* if a function or symbol is not defined in our env, __index will lookup
* in the global env.
*
* all variables created in the script-env will be thrown away at the end
* of the script run.
* */
ngx_http_lua_create_new_global_table(L, 0 /* narr */, 1 /* nrec */);
/* {{{ make new env inheriting main thread's globals table */
/* the metatable for the new env */
lua_createtable(L, 0 /* narr */, 1 /* nrec */);
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2); /* setmetatable(newt, {__index = _G}) */
/* }}} */
lua_setfenv(L, -2); /* set new running env for the code closure */
}
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */