Line data Source code
1 :
2 : /*
3 : * Copyright (C) Xiaozhe Wang (chaoslawful)
4 : * Copyright (C) Yichun Zhang (agentzh)
5 : */
6 :
7 :
8 : #ifndef DDEBUG
9 : #define DDEBUG 0
10 : #endif
11 : #include "ddebug.h"
12 :
13 :
14 : #include "ngx_http_lua_setby.h"
15 : #include "ngx_http_lua_exception.h"
16 : #include "ngx_http_lua_util.h"
17 : #include "ngx_http_lua_pcrefix.h"
18 : #include "ngx_http_lua_time.h"
19 : #include "ngx_http_lua_log.h"
20 : #include "ngx_http_lua_regex.h"
21 : #include "ngx_http_lua_variable.h"
22 : #include "ngx_http_lua_string.h"
23 : #include "ngx_http_lua_misc.h"
24 : #include "ngx_http_lua_consts.h"
25 : #include "ngx_http_lua_shdict.h"
26 : #include "ngx_http_lua_util.h"
27 :
28 :
29 : static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r,
30 : size_t nargs, ngx_http_variable_value_t *args);
31 :
32 :
33 : /* keys in Lua thread for fetching args and nargs in set_by_lua* */
34 :
35 : #define ngx_http_lua_nargs_key "__ngx_nargs"
36 :
37 : #define ngx_http_lua_args_key "__ngx_args"
38 :
39 :
40 : ngx_int_t
41 0 : ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val,
42 : ngx_http_variable_value_t *args, size_t nargs, ngx_str_t *script)
43 : {
44 : size_t i;
45 : ngx_int_t rc;
46 : u_char *err_msg;
47 : size_t len;
48 : u_char *data;
49 : #if (NGX_PCRE)
50 : ngx_pool_t *old_pool;
51 : #endif
52 :
53 : dd("nargs: %d", (int) nargs);
54 :
55 : dd("set Lua VM panic handler");
56 :
57 0 : lua_atpanic(L, ngx_http_lua_atpanic);
58 :
59 0 : NGX_LUA_EXCEPTION_TRY {
60 : dd("initialize nginx context in Lua VM, code chunk at "
61 : "stack top sp = 1");
62 0 : ngx_http_lua_set_by_lua_env(L, r, nargs, args);
63 :
64 : /* passing directive arguments to the user code */
65 0 : for (i = 0; i < nargs; i++) {
66 0 : lua_pushlstring(L, (const char *) args[i].data, args[i].len);
67 : }
68 :
69 : #if (NGX_PCRE)
70 : /* XXX: work-around to nginx regex subsystem */
71 0 : old_pool = ngx_http_lua_pcre_malloc_init(r->pool);
72 : #endif
73 :
74 0 : lua_pushcfunction(L, ngx_http_lua_traceback);
75 0 : lua_insert(L, 1); /* put it under chunk and args */
76 :
77 : dd("protected call user code");
78 :
79 0 : rc = lua_pcall(L, nargs, 1, 1);
80 :
81 : dd("after protected call user code");
82 :
83 0 : lua_remove(L, 1); /* remove traceback function */
84 :
85 : #if (NGX_PCRE)
86 : /* XXX: work-around to nginx regex subsystem */
87 0 : ngx_http_lua_pcre_malloc_done(old_pool);
88 : #endif
89 :
90 0 : if (rc != 0) {
91 : /* error occurred when running loaded code */
92 0 : err_msg = (u_char *) lua_tolstring(L, -1, &len);
93 :
94 0 : if (err_msg == NULL) {
95 0 : err_msg = (u_char *) "unknown reason";
96 0 : len = sizeof("unknown reason") - 1;
97 : }
98 :
99 0 : ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
100 : "failed to run set_by_lua*: %*s", len, err_msg);
101 :
102 0 : lua_settop(L, 0); /* clear remaining elems on stack */
103 :
104 0 : return NGX_ERROR;
105 : }
106 :
107 0 : data = (u_char *) lua_tolstring(L, -1, &len);
108 :
109 0 : if (data) {
110 0 : val->data = ngx_palloc(r->pool, len);
111 0 : if (val->data == NULL) {
112 0 : return NGX_ERROR;
113 : }
114 :
115 0 : ngx_memcpy(val->data, data, len);
116 0 : val->len = len;
117 :
118 : } else {
119 0 : val->data = NULL;
120 0 : val->len = 0;
121 : }
122 :
123 : } NGX_LUA_EXCEPTION_CATCH {
124 :
125 : dd("nginx execution restored");
126 0 : return NGX_ERROR;
127 : }
128 :
129 : /* clear Lua stack */
130 0 : lua_settop(L, 0);
131 :
132 0 : return NGX_OK;
133 : }
134 :
135 :
136 : int
137 0 : ngx_http_lua_setby_param_get(lua_State *L)
138 : {
139 : int idx;
140 : int n;
141 :
142 : ngx_http_variable_value_t *v;
143 :
144 0 : idx = luaL_checkint(L, 2);
145 0 : idx--;
146 :
147 : /* get number of args from globals */
148 0 : lua_getglobal(L, ngx_http_lua_nargs_key);
149 0 : n = (int) lua_tointeger(L, -1);
150 :
151 : /* get args from globals */
152 0 : lua_getglobal(L, ngx_http_lua_args_key);
153 0 : v = lua_touserdata(L, -1);
154 :
155 0 : if (idx < 0 || idx > n - 1) {
156 0 : lua_pushnil(L);
157 :
158 : } else {
159 0 : lua_pushlstring(L, (const char *) (v[idx].data), v[idx].len);
160 : }
161 :
162 0 : return 1;
163 : }
164 :
165 :
166 : /**
167 : * Set environment table for the given code closure.
168 : *
169 : * Before:
170 : * | code closure | <- top
171 : * | ... |
172 : *
173 : * After:
174 : * | code closure | <- top
175 : * | ... |
176 : * */
177 : static void
178 0 : ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs,
179 : ngx_http_variable_value_t *args)
180 : {
181 : /* set nginx request pointer to current lua thread's globals table */
182 0 : ngx_http_lua_set_req(L, r);
183 :
184 0 : lua_pushinteger(L, nargs);
185 0 : lua_setglobal(L, ngx_http_lua_nargs_key);
186 :
187 0 : lua_pushlightuserdata(L, args);
188 0 : lua_setglobal(L, ngx_http_lua_args_key);
189 :
190 : /**
191 : * we want to create empty environment for current script
192 : *
193 : * newt = {}
194 : * newt["_G"] = newt
195 : * setmetatable(newt, {__index = _G})
196 : *
197 : * if a function or symbol is not defined in our env, __index will lookup
198 : * in the global env.
199 : *
200 : * all variables created in the script-env will be thrown away at the end
201 : * of the script run.
202 : * */
203 0 : ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */);
204 :
205 : /* {{{ make new env inheriting main thread's globals table */
206 : /* the metatable for the new env */
207 0 : lua_createtable(L, 0 /* narr */, 1 /* nrec */);
208 0 : ngx_http_lua_get_globals_table(L);
209 0 : lua_setfield(L, -2, "__index");
210 0 : lua_setmetatable(L, -2); /* setmetatable(newt, {__index = _G}) */
211 : /* }}} */
212 :
213 0 : lua_setfenv(L, -2); /* set new running env for the code closure */
214 0 : }
215 :
216 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|