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 <nginx.h>
15 : #include <ngx_md5.h>
16 : #include "ngx_http_lua_common.h"
17 : #include "ngx_http_lua_cache.h"
18 : #include "ngx_http_lua_clfactory.h"
19 : #include "ngx_http_lua_util.h"
20 :
21 :
22 : /**
23 : * Find code chunk associated with the given key in code cache,
24 : * and push it to the top of Lua stack if found.
25 : *
26 : * Stack layout before call:
27 : * | ... | <- top
28 : *
29 : * Stack layout after call:
30 : * | code chunk | <- top
31 : * | ... |
32 : *
33 : * */
34 : static ngx_int_t
35 1 : ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L,
36 : const char *key)
37 : {
38 : int rc;
39 : u_char *err;
40 :
41 : /* get code cache table */
42 1 : lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key);
43 1 : lua_rawget(L, LUA_REGISTRYINDEX); /* sp++ */
44 :
45 : dd("Code cache table to load: %p", lua_topointer(L, -1));
46 :
47 1 : if (!lua_istable(L, -1)) {
48 : dd("Error: code cache table to load did not exist!!");
49 0 : return NGX_ERROR;
50 : }
51 :
52 1 : lua_getfield(L, -1, key); /* sp++ */
53 :
54 1 : if (lua_isfunction(L, -1)) {
55 : /* call closure factory to gen new closure */
56 0 : rc = lua_pcall(L, 0, 1, 0);
57 0 : if (rc == 0) {
58 : /* remove cache table from stack, leave code chunk at
59 : * top of stack */
60 0 : lua_remove(L, -2); /* sp-- */
61 0 : return NGX_OK;
62 : }
63 :
64 0 : if (lua_isstring(L, -1)) {
65 0 : err = (u_char *) lua_tostring(L, -1);
66 :
67 : } else {
68 0 : err = (u_char *) "unknown error";
69 : }
70 :
71 0 : ngx_log_error(NGX_LOG_ERR, log, 0,
72 : "lua: failed to run factory at key \"%s\": %s",
73 : key, err);
74 0 : lua_pop(L, 2);
75 0 : return NGX_ERROR;
76 : }
77 :
78 : dd("Value associated with given key in code cache table is not code "
79 : "chunk: stack top=%d, top value type=%s\n",
80 : lua_gettop(L), lua_typename(L, -1));
81 :
82 : /* remove cache table and value from stack */
83 1 : lua_pop(L, 2); /* sp-=2 */
84 :
85 1 : return NGX_DECLINED;
86 : }
87 :
88 :
89 : /**
90 : * Store the closure factory at the top of Lua stack to code cache, and
91 : * associate it with the given key. Then generate new closure.
92 : *
93 : * Stack layout before call:
94 : * | code factory | <- top
95 : * | ... |
96 : *
97 : * Stack layout after call:
98 : * | code chunk | <- top
99 : * | ... |
100 : *
101 : * */
102 : static ngx_int_t
103 1 : ngx_http_lua_cache_store_code(lua_State *L, const char *key)
104 : {
105 : int rc;
106 :
107 : /* get code cache table */
108 1 : lua_pushlightuserdata(L, &ngx_http_lua_code_cache_key);
109 1 : lua_rawget(L, LUA_REGISTRYINDEX);
110 :
111 : dd("Code cache table to store: %p", lua_topointer(L, -1));
112 :
113 1 : if (!lua_istable(L, -1)) {
114 : dd("Error: code cache table to load did not exist!!");
115 0 : return NGX_ERROR;
116 : }
117 :
118 1 : lua_pushvalue(L, -2); /* closure cache closure */
119 1 : lua_setfield(L, -2, key); /* closure cache */
120 :
121 : /* remove cache table, leave closure factory at top of stack */
122 1 : lua_pop(L, 1); /* closure */
123 :
124 : /* call closure factory to generate new closure */
125 1 : rc = lua_pcall(L, 0, 1, 0);
126 1 : if (rc != 0) {
127 : dd("Error: failed to call closure factory!!");
128 0 : return NGX_ERROR;
129 : }
130 :
131 1 : return NGX_OK;
132 : }
133 :
134 :
135 : ngx_int_t
136 1 : ngx_http_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L,
137 : const u_char *src, size_t src_len, const u_char *cache_key,
138 : const char *name)
139 : {
140 : int n;
141 : ngx_int_t rc;
142 1 : const char *err = NULL;
143 :
144 1 : n = lua_gettop(L);
145 :
146 : dd("XXX cache key: [%s]", cache_key);
147 :
148 1 : rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key);
149 1 : if (rc == NGX_OK) {
150 : /* code chunk loaded from cache, sp++ */
151 : dd("Code cache hit! cache key='%s', stack top=%d, script='%.*s'",
152 : cache_key, lua_gettop(L), (int) src_len, src);
153 0 : return NGX_OK;
154 : }
155 :
156 1 : if (rc == NGX_ERROR) {
157 0 : return NGX_ERROR;
158 : }
159 :
160 : /* rc == NGX_DECLINED */
161 :
162 : dd("Code cache missed! cache key='%s', stack top=%d, script='%.*s'",
163 : cache_key, lua_gettop(L), (int) src_len, src);
164 :
165 : /* load closure factory of inline script to the top of lua stack, sp++ */
166 1 : rc = ngx_http_lua_clfactory_loadbuffer(L, (char *) src, src_len, name);
167 :
168 1 : if (rc != 0) {
169 : /* Oops! error occurred when loading Lua script */
170 0 : if (rc == LUA_ERRMEM) {
171 0 : err = "memory allocation error";
172 :
173 : } else {
174 0 : if (lua_isstring(L, -1)) {
175 0 : err = lua_tostring(L, -1);
176 :
177 : } else {
178 0 : err = "unknown error";
179 : }
180 : }
181 :
182 0 : goto error;
183 : }
184 :
185 : /* store closure factory and gen new closure at the top of lua stack to
186 : * code cache */
187 1 : rc = ngx_http_lua_cache_store_code(L, (char *) cache_key);
188 1 : if (rc != NGX_OK) {
189 0 : err = "fail to generate new closure from the closure factory";
190 0 : goto error;
191 : }
192 :
193 1 : return NGX_OK;
194 :
195 0 : error:
196 :
197 0 : ngx_log_error(NGX_LOG_ERR, log, 0,
198 : "failed to load inlined Lua code: %s", err);
199 0 : lua_settop(L, n);
200 0 : return NGX_ERROR;
201 : }
202 :
203 :
204 : ngx_int_t
205 0 : ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L,
206 : const u_char *script, const u_char *cache_key)
207 : {
208 : int n;
209 0 : ngx_int_t rc, errcode = NGX_ERROR;
210 : u_char *p;
211 : u_char buf[NGX_HTTP_LUA_FILE_KEY_LEN + 1];
212 0 : const char *err = NULL;
213 :
214 0 : n = lua_gettop(L);
215 :
216 : /* calculate digest of script file path */
217 0 : if (cache_key == NULL) {
218 : dd("CACHE file key not pre-calculated...calculating");
219 0 : p = ngx_copy(buf, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN);
220 :
221 0 : p = ngx_http_lua_digest_hex(p, script, ngx_strlen(script));
222 :
223 0 : *p = '\0';
224 0 : cache_key = buf;
225 :
226 : } else {
227 : dd("CACHE file key already pre-calculated");
228 : }
229 :
230 : dd("XXX cache key for file: [%s]", cache_key);
231 :
232 0 : rc = ngx_http_lua_cache_load_code(log, L, (char *) cache_key);
233 0 : if (rc == NGX_OK) {
234 : /* code chunk loaded from cache, sp++ */
235 : dd("Code cache hit! cache key='%s', stack top=%d, file path='%s'",
236 : cache_key, lua_gettop(L), script);
237 0 : return NGX_OK;
238 : }
239 :
240 0 : if (rc == NGX_ERROR) {
241 0 : return NGX_ERROR;
242 : }
243 :
244 : /* rc == NGX_DECLINED */
245 :
246 : dd("Code cache missed! cache key='%s', stack top=%d, file path='%s'",
247 : cache_key, lua_gettop(L), script);
248 :
249 : /* load closure factory of script file to the top of lua stack, sp++ */
250 0 : rc = ngx_http_lua_clfactory_loadfile(L, (char *) script);
251 :
252 : dd("loadfile returns %d (%d)", (int) rc, LUA_ERRFILE);
253 :
254 0 : if (rc != 0) {
255 : /* Oops! error occurred when loading Lua script */
256 0 : switch (rc) {
257 0 : case LUA_ERRMEM:
258 0 : err = "memory allocation error";
259 0 : break;
260 :
261 0 : case LUA_ERRFILE:
262 0 : errcode = NGX_HTTP_NOT_FOUND;
263 : /* fall through */
264 :
265 0 : default:
266 0 : if (lua_isstring(L, -1)) {
267 0 : err = lua_tostring(L, -1);
268 :
269 : } else {
270 0 : err = "unknown error";
271 : }
272 : }
273 :
274 0 : goto error;
275 : }
276 :
277 : /* store closure factory and gen new closure at the top of lua stack
278 : * to code cache */
279 0 : rc = ngx_http_lua_cache_store_code(L, (char *) cache_key);
280 0 : if (rc != NGX_OK) {
281 0 : err = "fail to generate new closure from the closure factory";
282 0 : goto error;
283 : }
284 :
285 0 : return NGX_OK;
286 :
287 0 : error:
288 :
289 0 : ngx_log_error(NGX_LOG_ERR, log, 0,
290 : "failed to load external Lua file \"%s\": %s", script, err);
291 :
292 0 : lua_settop(L, n);
293 0 : return errcode;
294 : }
295 :
296 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|