]> granicus.if.org Git - apache/blob - modules/lua/lua_vmprep.c
* modules/lua/config.m4: Use liblua paths from pkg-config if
[apache] / modules / lua / lua_vmprep.c
1 /**
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
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17 #include "mod_lua.h"
18 #include "http_log.h"
19 #include "apr_uuid.h"
20 #include "lua_config.h"
21 #include "apr_file_info.h"
22 #include "mod_auth.h"
23
24 APLOG_USE_MODULE(lua);
25
26 #ifndef AP_LUA_MODULE_EXT
27 #if defined(NETWARE) 
28 #define AP_LUA_MODULE_EXT ".nlm"
29 #elif defined(WIN32)
30 #define AP_LUA_MODULE_EXT ".dll"
31 #elif (defined(__hpux__) || defined(__hpux)) && !defined(__ia64)
32 #define AP_LUA_MODULE_EXT ".sl"
33 #else
34 #define AP_LUA_MODULE_EXT ".so"
35 #endif
36 #endif
37
38 #if APR_HAS_THREADS
39     apr_thread_mutex_t *ap_lua_mutex;
40 #endif
41 extern apr_global_mutex_t *lua_ivm_mutex;
42     
43 void ap_lua_init_mutex(apr_pool_t *pool, server_rec *s) 
44 {
45     apr_status_t rv;
46     
47     /* global IVM mutex */
48     rv = apr_global_mutex_child_init(&lua_ivm_mutex,
49                                      apr_global_mutex_lockfile(lua_ivm_mutex),
50                                      pool);
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");
54         exit(1); /* bah :( */
55     }
56     
57     /* Server pool mutex */
58 #if APR_HAS_THREADS
59     apr_thread_mutex_create(&ap_lua_mutex, APR_THREAD_MUTEX_DEFAULT, pool);
60 #endif
61 }
62
63 /* forward dec'l from this file */
64
65 #if 0
66 static void pstack_dump(lua_State *L, apr_pool_t *r, int level,
67                         const char *msg)
68 {
69     int i;
70     int top = lua_gettop(L);
71
72     ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03211)
73                   "Lua Stack Dump: [%s]", msg);
74
75     for (i = 1; i <= top; i++) {
76         int t = lua_type(L, i);
77         switch (t) {
78         case LUA_TSTRING:{
79                 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03212)
80                               "%d:  '%s'", i, lua_tostring(L, i));
81                 break;
82             }
83         case LUA_TUSERDATA:{
84                 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03213)
85                               "%d:  userdata", i);
86                 break;
87             }
88         case LUA_TLIGHTUSERDATA:{
89                 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03214)
90                               "%d:  lightuserdata", i);
91                 break;
92             }
93         case LUA_TNIL:{
94                 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03215)
95                               "%d:  NIL", i);
96                 break;
97             }
98         case LUA_TNONE:{
99                 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03216)
100                               "%d:  None", i);
101                 break;
102             }
103         case LUA_TBOOLEAN:{
104                 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03217)
105                               "%d:  %s",
106                               i, lua_toboolean(L, i) ? "true" : "false");
107                 break;
108             }
109         case LUA_TNUMBER:{
110                 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03218)
111                               "%d:  %g", i, lua_tonumber(L, i));
112                 break;
113             }
114         case LUA_TTABLE:{
115                 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03219)
116                               "%d:  <table>", i);
117                 break;
118             }
119         case LUA_TTHREAD:{
120                 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03220)
121                               "%d:  <thread>", i);
122                 break;
123             }
124         case LUA_TFUNCTION:{
125                 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03221)
126                               "%d:  <function>", i);
127                 break;
128             }
129         default:{
130                 ap_log_perror(APLOG_MARK, level, 0, r, APLOGNO(03222)
131                               "%d:  unknown: [%s]", i, lua_typename(L, i));
132                 break;
133             }
134         }
135     }
136 }
137 #endif
138
139 /* BEGIN modules*/
140
141 /* BEGIN apache lmodule  */
142
143 #define makeintegerfield(L, n) lua_pushinteger(L, n); lua_setfield(L, -2, #n)
144
145 void ap_lua_load_apache2_lmodule(lua_State *L)
146 {
147     lua_getglobal(L, "package");
148     lua_getfield(L, -1, "loaded");
149     lua_newtable(L);
150     lua_setfield(L, -2, "apache2");
151     lua_setglobal(L, "apache2");
152     lua_pop(L, 1);              /* empty stack */
153
154     lua_getglobal(L, "apache2");
155
156     lua_pushstring(L, ap_get_server_banner());
157     lua_setfield(L, -2, "version");
158
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);
173     
174     /*
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);
232      */
233 }
234
235 /* END apache2 lmodule */
236
237 /*  END library functions */
238
239 /* callback for cleaning up a lua vm when pool is closed */
240 static apr_status_t cleanup_lua(void *l)
241 {
242     AP_DEBUG_ASSERT(l != NULL);
243     lua_close((lua_State *) l);
244     return APR_SUCCESS;
245 }
246
247 static apr_status_t server_cleanup_lua(void *resource)
248 {
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);
253     }
254     return APR_SUCCESS;
255 }
256
257 /*
258         munge_path(L, 
259                    "path", 
260                    "?.lua", 
261                    "./?.lua", 
262                    lifecycle_pool,
263                    spec->package_paths, 
264                    spec->file);
265 */
266 /**
267  * field -> "path" or "cpath"
268  * sub_pat -> "?.lua"
269  * rep_pat -> "./?.lua"
270  * pool -> lifecycle pool for allocations
271  * paths -> things to add
272  * file -> ???
273  */
274 static void munge_path(lua_State *L,
275                        const char *field,
276                        const char *sub_pat,
277                        const char *rep_pat,
278                        apr_pool_t *pool,
279                        apr_array_header_t *paths,
280                        const char *file)
281 {
282     const char *current;
283     const char *parent_dir;
284     const char *pattern;
285     const char *modified;
286     char *part;
287
288     lua_getglobal(L, "package");
289     lua_getfield(L, -1, field);
290     
291     current = lua_tostring(L, -1);
292
293     parent_dir = ap_make_dirstr_parent(pool, file);
294  
295     pattern = apr_pstrcat(pool, parent_dir, sub_pat, NULL);
296
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);
301
302
303     lua_pop(L, 2);
304
305     part = apr_pstrcat(pool, modified, ";", apr_array_pstrcat(pool, paths, ';'),
306                        NULL);
307
308     lua_pushstring(L, part);
309     lua_setfield(L, -2, field);
310     lua_pop(L, 1);              /* pop "package" off the stack     */
311 }
312
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);
318     lua_concat(L, 2);
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);
323         return 1;
324     }
325     lua_getfield(L, -1, "start");
326     lua_remove(L, -2);  /* drop module table */
327     return 0;
328 }
329
330 #endif
331
332 static apr_status_t vm_construct(lua_State **vm, void *params, apr_pool_t *lifecycle_pool)
333 {
334     lua_State* L;
335
336     ap_lua_vm_spec *spec = params;
337
338     L = luaL_newstate();
339 #ifdef AP_ENABLE_LUAJIT
340     luaopen_jit(L);
341 #endif
342     luaL_openlibs(L);
343     if (spec->package_paths) {
344         munge_path(L, 
345                    "path", "?.lua", "./?.lua", 
346                    lifecycle_pool,
347                    spec->package_paths, 
348                    spec->file);
349     }
350     if (spec->package_cpaths) {
351         munge_path(L,
352                    "cpath", "?" AP_LUA_MODULE_EXT, "./?" AP_LUA_MODULE_EXT,
353                    lifecycle_pool,
354                    spec->package_cpaths,
355                    spec->file);
356     }
357
358     if (spec->cb) {
359         spec->cb(L, lifecycle_pool, spec->cb_arg);
360     }
361
362
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);
366     }
367     else {
368         int rc;
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);
372         if (rc != 0) {
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));
377             return APR_EBADF;
378         }
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));
383             return APR_EBADF;
384         }
385     }
386
387 #ifdef AP_ENABLE_LUAJIT
388     loadjitmodule(L, lifecycle_pool);
389 #endif
390     lua_pushlightuserdata(L, lifecycle_pool);
391     lua_setfield(L, LUA_REGISTRYINDEX, "Apache2.Wombat.pool");
392     *vm = L;
393
394     return APR_SUCCESS;
395 }
396
397 static ap_lua_vm_spec* copy_vm_spec(apr_pool_t* pool, ap_lua_vm_spec* spec) 
398 {
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;
410     return copied_spec;
411 }
412
413 static apr_status_t server_vm_construct(lua_State **resource, void *params, apr_pool_t *pool)
414 {
415     lua_State* L;
416     ap_lua_server_spec* spec = apr_pcalloc(pool, sizeof(ap_lua_server_spec));
417     *resource = NULL;
418     if (vm_construct(&L, params, pool) == APR_SUCCESS) {
419         spec->finfo = apr_pcalloc(pool, sizeof(ap_lua_finfo));
420         if (L != NULL) {
421             spec->L = L;
422             *resource = (void*) spec;
423             lua_pushlightuserdata(L, spec);
424             lua_setfield(L, LUA_REGISTRYINDEX, "Apache2.Lua.server_spec");
425             return APR_SUCCESS;
426         }
427     }
428     return APR_EGENERAL;
429 }
430
431 /**
432  * Function used to create a lua_State instance bound into the web
433  * server in the appropriate scope.
434  */
435 lua_State *ap_lua_get_lua_state(apr_pool_t *lifecycle_pool,
436                                                ap_lua_vm_spec *spec, request_rec* r)
437 {
438     lua_State *L = NULL;
439     ap_lua_finfo *cache_info = NULL;
440     int tryCache = 0;
441     
442     if (spec->scope == AP_LUA_SCOPE_SERVER) {
443         char *hash;
444         apr_reslist_t* reslist = NULL;
445         ap_lua_server_spec* sspec = NULL;
446         hash = apr_psprintf(r->pool, "reslist:%s", spec->file);
447 #if APR_HAS_THREADS
448         apr_thread_mutex_lock(ap_lua_mutex);
449 #endif
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) {
454                     L = sspec->L;
455                     cache_info = sspec->finfo;
456                 }
457             }
458         }
459         if (L == NULL) {
460             ap_lua_vm_spec* server_spec = copy_vm_spec(r->server->process->pool, spec);
461             if (
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) {
470                     L = sspec->L;
471                     cache_info = sspec->finfo;
472                 }
473                 else {
474 #if APR_HAS_THREADS
475                     apr_thread_mutex_unlock(ap_lua_mutex);
476 #endif
477                     return NULL;
478                 }
479             }
480         }
481 #if APR_HAS_THREADS
482         apr_thread_mutex_unlock(ap_lua_mutex);
483 #endif
484     }
485     else {
486         if (apr_pool_userdata_get((void **)&L, spec->file,
487                               lifecycle_pool) != APR_SUCCESS) {
488             L = NULL;
489         }
490     }
491     if (L == NULL) {
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 */
495
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);
499         }
500     }
501
502     if (spec->codecache == AP_LUA_CACHE_FOREVER || (spec->bytecode && spec->bytecode_len > 0)) {
503         tryCache = 1;
504     }
505     else {
506         char* mkey;
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);
513             }
514         }
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);
518
519             /* On first visit, modified will be zero, but that's fine - The file is 
520             loaded in the vm_construct function.
521             */
522             if ((cache_info->modified == lua_finfo.mtime && cache_info->size == lua_finfo.size)
523                     || cache_info->modified == 0) {
524                 tryCache = 1;
525             }
526             cache_info->modified = lua_finfo.mtime;
527             cache_info->size = lua_finfo.size;
528         }
529         else if (spec->codecache == AP_LUA_CACHE_NEVER) {
530             if (cache_info->runs == 0)
531                 tryCache = 1;
532         }
533         cache_info->runs++;
534     }
535     if (tryCache == 0 && spec->scope != AP_LUA_SCOPE_ONCE) {
536         int rc;
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);
540         if (rc != 0) {
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));
545             return 0;
546         }
547         lua_pcall(L, 0, LUA_MULTRET, 0);
548     }
549
550     return L;
551 }