2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 #include "lua_config.h"
21 #include "apr_file_info.h"
24 APLOG_USE_MODULE(lua);
26 #ifndef AP_LUA_MODULE_EXT
28 #define AP_LUA_MODULE_EXT ".nlm"
30 #define AP_LUA_MODULE_EXT ".dll"
31 #elif (defined(__hpux__) || defined(__hpux)) && !defined(__ia64)
32 #define AP_LUA_MODULE_EXT ".sl"
34 #define AP_LUA_MODULE_EXT ".so"
39 apr_thread_mutex_t *ap_lua_mutex;
41 extern apr_global_mutex_t *lua_ivm_mutex;
43 void ap_lua_init_mutex(apr_pool_t *pool, server_rec *s)
47 /* global IVM mutex */
48 rv = apr_global_mutex_child_init(&lua_ivm_mutex,
49 apr_global_mutex_lockfile(lua_ivm_mutex),
51 if (rv != APR_SUCCESS) {
52 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(03016)
53 "mod_lua: Failed to reopen mutex lua-ivm-shm in child");
57 /* Server pool mutex */
59 apr_thread_mutex_create(&ap_lua_mutex, APR_THREAD_MUTEX_DEFAULT, pool);
63 /* forward dec'l from this file */
66 static void pstack_dump(lua_State *L, apr_pool_t *r, int level,
70 int top = lua_gettop(L);
72 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03211)
73 "Lua Stack Dump: [%s]", msg);
75 for (i = 1; i <= top; i++) {
76 int t = lua_type(L, i);
79 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03212)
80 "%d: '%s'", i, lua_tostring(L, i));
84 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03213)
88 case LUA_TLIGHTUSERDATA:{
89 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03214)
90 "%d: lightuserdata", i);
94 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03215)
99 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03216)
104 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03217)
106 i, lua_toboolean(L, i) ? "true" : "false");
110 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03218)
111 "%d: %g", i, lua_tonumber(L, i));
115 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03219)
120 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03220)
125 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03221)
126 "%d: <function>", i);
130 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03222)
131 "%d: unknown: [%s]", i, lua_typename(L, i));
141 /* BEGIN apache lmodule */
143 #define makeintegerfield(L, n) lua_pushinteger(L, n); lua_setfield(L, -2, #n)
145 void ap_lua_load_apache2_lmodule(lua_State *L)
147 lua_getglobal(L, "package");
148 lua_getfield(L, -1, "loaded");
150 lua_setfield(L, -2, "apache2");
151 lua_setglobal(L, "apache2");
152 lua_pop(L, 1); /* empty stack */
154 lua_getglobal(L, "apache2");
156 lua_pushstring(L, ap_get_server_banner());
157 lua_setfield(L, -2, "version");
159 makeintegerfield(L, OK);
160 makeintegerfield(L, DECLINED);
161 makeintegerfield(L, DONE);
162 makeintegerfield(L, HTTP_MOVED_TEMPORARILY);
163 makeintegerfield(L, PROXYREQ_NONE);
164 makeintegerfield(L, PROXYREQ_PROXY);
165 makeintegerfield(L, PROXYREQ_REVERSE);
166 makeintegerfield(L, PROXYREQ_RESPONSE);
167 makeintegerfield(L, PROXYREQ_RESPONSE);
168 makeintegerfield(L, AUTHZ_DENIED);
169 makeintegerfield(L, AUTHZ_GRANTED);
170 makeintegerfield(L, AUTHZ_NEUTRAL);
171 makeintegerfield(L, AUTHZ_GENERAL_ERROR);
172 makeintegerfield(L, AUTHZ_DENIED_NO_USER);
175 makeintegerfield(L, HTTP_CONTINUE);
176 makeintegerfield(L, HTTP_SWITCHING_PROTOCOLS);
177 makeintegerfield(L, HTTP_PROCESSING);
178 makeintegerfield(L, HTTP_OK);
179 makeintegerfield(L, HTTP_CREATED);
180 makeintegerfield(L, HTTP_ACCEPTED);
181 makeintegerfield(L, HTTP_NON_AUTHORITATIVE);
182 makeintegerfield(L, HTTP_NO_CONTENT);
183 makeintegerfield(L, HTTP_RESET_CONTENT);
184 makeintegerfield(L, HTTP_PARTIAL_CONTENT);
185 makeintegerfield(L, HTTP_MULTI_STATUS);
186 makeintegerfield(L, HTTP_ALREADY_REPORTED);
187 makeintegerfield(L, HTTP_IM_USED);
188 makeintegerfield(L, HTTP_MULTIPLE_CHOICES);
189 makeintegerfield(L, HTTP_MOVED_PERMANENTLY);
190 makeintegerfield(L, HTTP_MOVED_TEMPORARILY);
191 makeintegerfield(L, HTTP_SEE_OTHER);
192 makeintegerfield(L, HTTP_NOT_MODIFIED);
193 makeintegerfield(L, HTTP_USE_PROXY);
194 makeintegerfield(L, HTTP_TEMPORARY_REDIRECT);
195 makeintegerfield(L, HTTP_PERMANENT_REDIRECT);
196 makeintegerfield(L, HTTP_BAD_REQUEST);
197 makeintegerfield(L, HTTP_UNAUTHORIZED);
198 makeintegerfield(L, HTTP_PAYMENT_REQUIRED);
199 makeintegerfield(L, HTTP_FORBIDDEN);
200 makeintegerfield(L, HTTP_NOT_FOUND);
201 makeintegerfield(L, HTTP_METHOD_NOT_ALLOWED);
202 makeintegerfield(L, HTTP_NOT_ACCEPTABLE);
203 makeintegerfield(L, HTTP_PROXY_AUTHENTICATION_REQUIRED);
204 makeintegerfield(L, HTTP_REQUEST_TIME_OUT);
205 makeintegerfield(L, HTTP_CONFLICT);
206 makeintegerfield(L, HTTP_GONE);
207 makeintegerfield(L, HTTP_LENGTH_REQUIRED);
208 makeintegerfield(L, HTTP_PRECONDITION_FAILED);
209 makeintegerfield(L, HTTP_REQUEST_ENTITY_TOO_LARGE);
210 makeintegerfield(L, HTTP_REQUEST_URI_TOO_LARGE);
211 makeintegerfield(L, HTTP_UNSUPPORTED_MEDIA_TYPE);
212 makeintegerfield(L, HTTP_RANGE_NOT_SATISFIABLE);
213 makeintegerfield(L, HTTP_EXPECTATION_FAILED);
214 makeintegerfield(L, HTTP_UNPROCESSABLE_ENTITY);
215 makeintegerfield(L, HTTP_LOCKED);
216 makeintegerfield(L, HTTP_FAILED_DEPENDENCY);
217 makeintegerfield(L, HTTP_UPGRADE_REQUIRED);
218 makeintegerfield(L, HTTP_PRECONDITION_REQUIRED);
219 makeintegerfield(L, HTTP_TOO_MANY_REQUESTS);
220 makeintegerfield(L, HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE);
221 makeintegerfield(L, HTTP_INTERNAL_SERVER_ERROR);
222 makeintegerfield(L, HTTP_NOT_IMPLEMENTED);
223 makeintegerfield(L, HTTP_BAD_GATEWAY);
224 makeintegerfield(L, HTTP_SERVICE_UNAVAILABLE);
225 makeintegerfield(L, HTTP_GATEWAY_TIME_OUT);
226 makeintegerfield(L, HTTP_VERSION_NOT_SUPPORTED);
227 makeintegerfield(L, HTTP_VARIANT_ALSO_VARIES);
228 makeintegerfield(L, HTTP_INSUFFICIENT_STORAGE);
229 makeintegerfield(L, HTTP_LOOP_DETECTED);
230 makeintegerfield(L, HTTP_NOT_EXTENDED);
231 makeintegerfield(L, HTTP_NETWORK_AUTHENTICATION_REQUIRED);
235 /* END apache2 lmodule */
237 /* END library functions */
239 /* callback for cleaning up a lua vm when pool is closed */
240 static apr_status_t cleanup_lua(void *l)
242 AP_DEBUG_ASSERT(l != NULL);
243 lua_close((lua_State *) l);
247 static apr_status_t server_cleanup_lua(void *resource)
249 ap_lua_server_spec* spec = (ap_lua_server_spec*) resource;
250 AP_DEBUG_ASSERT(spec != NULL);
251 if (spec->L != NULL) {
252 lua_close((lua_State *) spec->L);
267 * field -> "path" or "cpath"
269 * rep_pat -> "./?.lua"
270 * pool -> lifecycle pool for allocations
271 * paths -> things to add
274 static void munge_path(lua_State *L,
279 apr_array_header_t *paths,
283 const char *parent_dir;
285 const char *modified;
288 lua_getglobal(L, "package");
289 lua_getfield(L, -1, field);
291 current = lua_tostring(L, -1);
293 parent_dir = ap_make_dirstr_parent(pool, file);
295 pattern = apr_pstrcat(pool, parent_dir, sub_pat, NULL);
297 luaL_gsub(L, current, rep_pat, pattern);
298 lua_setfield(L, -3, field);
299 lua_getfield(L, -2, field);
300 modified = lua_tostring(L, -1);
305 part = apr_pstrcat(pool, modified, ";", apr_array_pstrcat(pool, paths, ';'),
308 lua_pushstring(L, part);
309 lua_setfield(L, -2, field);
310 lua_pop(L, 1); /* pop "package" off the stack */
313 #ifdef AP_ENABLE_LUAJIT
314 static int loadjitmodule(lua_State *L, apr_pool_t *lifecycle_pool) {
315 lua_getglobal(L, "require");
316 lua_pushliteral(L, "jit.");
317 lua_pushvalue(L, -3);
319 if (lua_pcall(L, 1, 1, 0)) {
320 const char *msg = lua_tostring(L, -1);
321 ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, lifecycle_pool, APLOGNO(01480)
322 "Failed to init LuaJIT: %s", msg);
325 lua_getfield(L, -1, "start");
326 lua_remove(L, -2); /* drop module table */
332 static apr_status_t vm_construct(lua_State **vm, void *params, apr_pool_t *lifecycle_pool)
336 ap_lua_vm_spec *spec = params;
339 #ifdef AP_ENABLE_LUAJIT
343 if (spec->package_paths) {
345 "path", "?.lua", "./?.lua",
350 if (spec->package_cpaths) {
352 "cpath", "?" AP_LUA_MODULE_EXT, "./?" AP_LUA_MODULE_EXT,
354 spec->package_cpaths,
359 spec->cb(L, lifecycle_pool, spec->cb_arg);
363 if (spec->bytecode && spec->bytecode_len > 0) {
364 luaL_loadbuffer(L, spec->bytecode, spec->bytecode_len, spec->file);
365 lua_pcall(L, 0, LUA_MULTRET, 0);
369 ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, lifecycle_pool, APLOGNO(01481)
370 "loading lua file %s", spec->file);
371 rc = luaL_loadfile(L, spec->file);
373 ap_log_perror(APLOG_MARK, APLOG_ERR, 0, lifecycle_pool, APLOGNO(01482)
374 "Error loading %s: %s", spec->file,
375 rc == LUA_ERRMEM ? "memory allocation error"
376 : lua_tostring(L, 0));
379 if ( lua_pcall(L, 0, LUA_MULTRET, 0) == LUA_ERRRUN ) {
380 ap_log_perror(APLOG_MARK, APLOG_ERR, 0, lifecycle_pool, APLOGNO(02613)
381 "Error loading %s: %s", spec->file,
382 lua_tostring(L, -1));
387 #ifdef AP_ENABLE_LUAJIT
388 loadjitmodule(L, lifecycle_pool);
390 lua_pushlightuserdata(L, lifecycle_pool);
391 lua_setfield(L, LUA_REGISTRYINDEX, "Apache2.Wombat.pool");
397 static ap_lua_vm_spec* copy_vm_spec(apr_pool_t* pool, ap_lua_vm_spec* spec)
399 ap_lua_vm_spec* copied_spec = apr_pcalloc(pool, sizeof(ap_lua_vm_spec));
400 copied_spec->bytecode_len = spec->bytecode_len;
401 copied_spec->bytecode = apr_pstrdup(pool, spec->bytecode);
402 copied_spec->cb = spec->cb;
403 copied_spec->cb_arg = NULL;
404 copied_spec->file = apr_pstrdup(pool, spec->file);
405 copied_spec->package_cpaths = apr_array_copy(pool, spec->package_cpaths);
406 copied_spec->package_paths = apr_array_copy(pool, spec->package_paths);
407 copied_spec->pool = pool;
408 copied_spec->scope = AP_LUA_SCOPE_SERVER;
409 copied_spec->codecache = spec->codecache;
413 static apr_status_t server_vm_construct(lua_State **resource, void *params, apr_pool_t *pool)
416 ap_lua_server_spec* spec = apr_pcalloc(pool, sizeof(ap_lua_server_spec));
418 if (vm_construct(&L, params, pool) == APR_SUCCESS) {
419 spec->finfo = apr_pcalloc(pool, sizeof(ap_lua_finfo));
422 *resource = (void*) spec;
423 lua_pushlightuserdata(L, spec);
424 lua_setfield(L, LUA_REGISTRYINDEX, "Apache2.Lua.server_spec");
432 * Function used to create a lua_State instance bound into the web
433 * server in the appropriate scope.
435 lua_State *ap_lua_get_lua_state(apr_pool_t *lifecycle_pool,
436 ap_lua_vm_spec *spec, request_rec* r)
439 ap_lua_finfo *cache_info = NULL;
442 if (spec->scope == AP_LUA_SCOPE_SERVER) {
444 apr_reslist_t* reslist = NULL;
445 ap_lua_server_spec* sspec = NULL;
446 hash = apr_psprintf(r->pool, "reslist:%s", spec->file);
448 apr_thread_mutex_lock(ap_lua_mutex);
450 if (apr_pool_userdata_get((void **)&reslist, hash,
451 r->server->process->pool) == APR_SUCCESS) {
452 if (reslist != NULL) {
453 if (apr_reslist_acquire(reslist, (void**) &sspec) == APR_SUCCESS) {
455 cache_info = sspec->finfo;
460 ap_lua_vm_spec* server_spec = copy_vm_spec(r->server->process->pool, spec);
462 apr_reslist_create(&reslist, spec->vm_min, spec->vm_max, spec->vm_max, 0,
463 (apr_reslist_constructor) server_vm_construct,
464 (apr_reslist_destructor) server_cleanup_lua,
465 server_spec, r->server->process->pool)
466 == APR_SUCCESS && reslist != NULL) {
467 apr_pool_userdata_set(reslist, hash, NULL,
468 r->server->process->pool);
469 if (apr_reslist_acquire(reslist, (void**) &sspec) == APR_SUCCESS) {
471 cache_info = sspec->finfo;
475 apr_thread_mutex_unlock(ap_lua_mutex);
482 apr_thread_mutex_unlock(ap_lua_mutex);
486 if (apr_pool_userdata_get((void **)&L, spec->file,
487 lifecycle_pool) != APR_SUCCESS) {
492 ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, lifecycle_pool, APLOGNO(01483)
493 "creating lua_State with file %s", spec->file);
494 /* not available, so create */
496 if (!vm_construct(&L, spec, lifecycle_pool)) {
497 AP_DEBUG_ASSERT(L != NULL);
498 apr_pool_userdata_set(L, spec->file, cleanup_lua, lifecycle_pool);
502 if (spec->codecache == AP_LUA_CACHE_FOREVER || (spec->bytecode && spec->bytecode_len > 0)) {
507 if (spec->scope != AP_LUA_SCOPE_SERVER) {
508 mkey = apr_psprintf(r->pool, "ap_lua_modified:%s", spec->file);
509 apr_pool_userdata_get((void **)&cache_info, mkey, lifecycle_pool);
510 if (cache_info == NULL) {
511 cache_info = apr_pcalloc(lifecycle_pool, sizeof(ap_lua_finfo));
512 apr_pool_userdata_set((void*) cache_info, mkey, NULL, lifecycle_pool);
515 if (spec->codecache == AP_LUA_CACHE_STAT) {
516 apr_finfo_t lua_finfo;
517 apr_stat(&lua_finfo, spec->file, APR_FINFO_MTIME|APR_FINFO_SIZE, lifecycle_pool);
519 /* On first visit, modified will be zero, but that's fine - The file is
520 loaded in the vm_construct function.
522 if ((cache_info->modified == lua_finfo.mtime && cache_info->size == lua_finfo.size)
523 || cache_info->modified == 0) {
526 cache_info->modified = lua_finfo.mtime;
527 cache_info->size = lua_finfo.size;
529 else if (spec->codecache == AP_LUA_CACHE_NEVER) {
530 if (cache_info->runs == 0)
535 if (tryCache == 0 && spec->scope != AP_LUA_SCOPE_ONCE) {
537 ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, lifecycle_pool, APLOGNO(02332)
538 "(re)loading lua file %s", spec->file);
539 rc = luaL_loadfile(L, spec->file);
541 ap_log_perror(APLOG_MARK, APLOG_ERR, 0, lifecycle_pool, APLOGNO(02333)
542 "Error loading %s: %s", spec->file,
543 rc == LUA_ERRMEM ? "memory allocation error"
544 : lua_tostring(L, 0));
547 lua_pcall(L, 0, LUA_MULTRET, 0);