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.
22 #include <apr_thread_mutex.h>
23 #include <apr_pools.h>
25 #include "lua_config.h"
26 #include "apr_optional.h"
29 #include "util_mutex.h"
32 #ifdef APR_HAS_THREADS
33 #include "apr_thread_proc.h"
37 #if APR_HAVE_SYS_TYPES_H
38 #include <sys/types.h>
44 /* getpid for Windows */
45 #if APR_HAVE_PROCESS_H
49 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap_lua, AP_LUA, int, lua_open,
50 (lua_State *L, apr_pool_t *p),
53 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap_lua, AP_LUA, int, lua_request,
54 (lua_State *L, request_rec *r),
56 static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *lua_ssl_val = NULL;
57 static APR_OPTIONAL_FN_TYPE(ssl_is_https) *lua_ssl_is_https = NULL;
59 module AP_MODULE_DECLARE_DATA lua_module;
61 #define AP_LUA_HOOK_FIRST (APR_HOOK_FIRST - 1)
62 #define AP_LUA_HOOK_LAST (APR_HOOK_LAST + 1)
66 const char *file_name;
67 const char *function_name;
69 } lua_authz_provider_spec;
72 lua_authz_provider_spec *spec;
73 apr_array_header_t *args;
74 } lua_authz_provider_func;
76 apr_hash_t *lua_authz_providers;
80 apr_bucket_brigade *tmpBucket;
86 #define DEFAULT_LUA_SHMFILE "lua_ivm_shm"
88 apr_global_mutex_t *lua_ivm_mutex;
89 apr_shm_t *lua_ivm_shm;
90 char *lua_ivm_shmfile;
92 static apr_status_t shm_cleanup_wrapper(void *unused)
95 return apr_shm_destroy(lua_ivm_shm);
101 * error reporting if lua has an error.
102 * Extracts the error from lua stack and prints
104 static void report_lua_error(lua_State *L, request_rec *r)
106 const char *lua_response;
107 r->status = HTTP_INTERNAL_SERVER_ERROR;
108 r->content_type = "text/html";
109 ap_rputs("<h3>Error!</h3>\n", r);
110 ap_rputs("<pre>", r);
111 lua_response = lua_tostring(L, -1);
112 ap_rputs(ap_escape_html(r->pool, lua_response), r);
113 ap_rputs("</pre>\n", r);
115 ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, r->pool, APLOGNO(01471) "Lua error: %s",
119 static void lua_open_callback(lua_State *L, apr_pool_t *p, void *ctx)
122 ap_lua_load_apache2_lmodule(L);
123 ap_lua_load_request_lmodule(L, p);
124 ap_lua_load_config_lmodule(L);
127 static int lua_open_hook(lua_State *L, apr_pool_t *p)
129 lua_open_callback(L, p, NULL);
133 static const char *scope_to_string(unsigned int scope)
136 case AP_LUA_SCOPE_ONCE:
137 case AP_LUA_SCOPE_UNSET:
139 case AP_LUA_SCOPE_REQUEST:
141 case AP_LUA_SCOPE_CONN:
144 case AP_LUA_SCOPE_THREAD:
146 case AP_LUA_SCOPE_SERVER:
155 static void ap_lua_release_state(lua_State* L, ap_lua_vm_spec* spec, request_rec* r)
158 apr_reslist_t* reslist = NULL;
160 if (spec->scope == AP_LUA_SCOPE_SERVER) {
161 ap_lua_server_spec* sspec = NULL;
163 lua_getfield(L, LUA_REGISTRYINDEX, "Apache2.Lua.server_spec");
164 sspec = (ap_lua_server_spec*) lua_touserdata(L, 1);
165 hash = apr_psprintf(r->pool, "reslist:%s", spec->file);
166 if (apr_pool_userdata_get((void **)&reslist, hash,
167 r->server->process->pool) == APR_SUCCESS) {
168 AP_DEBUG_ASSERT(sspec != NULL);
169 if (reslist != NULL) {
170 apr_reslist_release(reslist, sspec);
176 static ap_lua_vm_spec *create_vm_spec(apr_pool_t **lifecycle_pool,
178 const ap_lua_dir_cfg *cfg,
179 const ap_lua_server_cfg *server_cfg,
180 const char *filename,
181 const char *bytecode,
182 apr_size_t bytecode_len,
183 const char *function,
187 ap_lua_vm_spec *spec = apr_pcalloc(r->pool, sizeof(ap_lua_vm_spec));
189 spec->scope = cfg->vm_scope;
190 spec->pool = r->pool;
191 spec->package_paths = cfg->package_paths;
192 spec->package_cpaths = cfg->package_cpaths;
193 spec->cb = &lua_open_callback;
195 spec->bytecode = bytecode;
196 spec->bytecode_len = bytecode_len;
197 spec->codecache = (cfg->codecache == AP_LUA_CACHE_UNSET) ? AP_LUA_CACHE_STAT : cfg->codecache;
198 spec->vm_min = cfg->vm_min ? cfg->vm_min : 1;
199 spec->vm_max = cfg->vm_max ? cfg->vm_max : 1;
203 apr_filepath_merge(&file, server_cfg->root_path,
204 filename, APR_FILEPATH_NOTRELATIVE, r->pool);
208 spec->file = r->filename;
210 ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, APLOGNO(02313)
211 "%s details: scope: %s, file: %s, func: %s",
212 what, scope_to_string(spec->scope), spec->file,
213 function ? function : "-");
215 switch (spec->scope) {
216 case AP_LUA_SCOPE_ONCE:
217 case AP_LUA_SCOPE_UNSET:
218 apr_pool_create(&pool, r->pool);
220 case AP_LUA_SCOPE_REQUEST:
223 case AP_LUA_SCOPE_CONN:
224 pool = r->connection->pool;
227 case AP_LUA_SCOPE_THREAD:
228 pool = apr_thread_pool_get(r->connection->current_thread);
230 case AP_LUA_SCOPE_SERVER:
231 pool = r->server->process->pool;
238 *lifecycle_pool = pool;
242 static const char* ap_lua_interpolate_string(apr_pool_t* pool, const char* string, const char** values)
247 srclen = strlen(string);
250 for (x=0; x < srclen; x++) {
251 if (string[x] == '$' && x != srclen-1 && string[x+1] >= '0' && string[x+1] <= '9') {
252 int v = *(string+x+1) - '0';
254 stringBetween = apr_pstrndup(pool, string+y, x-y);
259 ret = apr_pstrcat(pool, ret, stringBetween, values[v], NULL);
264 if (x-y > 0 && y > 0) {
265 stringBetween = apr_pstrndup(pool, string+y, x-y);
266 ret = apr_pstrcat(pool, ret, stringBetween, NULL);
268 /* If no replacement was made, just return the original string */
280 static int lua_handler(request_rec *r)
283 if (strcmp(r->handler, "lua-script")) {
286 /* Decline the request if the script does not exist (or is a directory),
287 * rather than just returning internal server error */
289 (r->finfo.filetype == APR_NOFILE)
290 || (r->finfo.filetype & APR_DIR)
294 ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(01472)
295 "handling [%s] in mod_lua", r->filename);
297 /* XXX: This seems wrong because it may generate wrong headers for HEAD requests */
298 if (!r->header_only) {
301 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
303 ap_lua_vm_spec *spec = create_vm_spec(&pool, r, cfg, NULL, NULL, NULL,
304 0, "handle", "request handler");
306 L = ap_lua_get_lua_state(pool, spec, r);
308 /* TODO annotate spec with failure reason */
309 r->status = HTTP_INTERNAL_SERVER_ERROR;
310 ap_rputs("Unable to compile VM, see logs", r);
311 ap_lua_release_state(L, spec, r);
312 return HTTP_INTERNAL_SERVER_ERROR;
314 ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, APLOGNO(01474) "got a vm!");
315 lua_getglobal(L, "handle");
316 if (!lua_isfunction(L, -1)) {
317 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01475)
318 "lua: Unable to find entry function '%s' in %s (not a valid function)",
321 ap_lua_release_state(L, spec, r);
322 return HTTP_INTERNAL_SERVER_ERROR;
324 ap_lua_run_lua_request(L, r);
325 if (lua_pcall(L, 1, 1, 0)) {
326 report_lua_error(L, r);
328 if (lua_isnumber(L, -1)) {
329 rc = lua_tointeger(L, -1);
331 ap_lua_release_state(L, spec, r);
337 /* ------------------- Input/output content filters ------------------- */
340 static apr_status_t lua_setup_filter_ctx(ap_filter_t* f, request_rec* r, lua_filter_ctx** c)
343 ap_lua_vm_spec *spec;
347 ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
349 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
352 ctx = apr_pcalloc(r->pool, sizeof(lua_filter_ctx));
355 /* Find the filter that was called.
356 * XXX: If we were wired with mod_filter, the filter (mod_filters name)
357 * and the provider (our underlying filters name) need to have matched.
359 for (n = 0; n < cfg->mapped_filters->nelts; n++) {
360 ap_lua_filter_handler_spec *hook_spec =
361 ((ap_lua_filter_handler_spec **) cfg->mapped_filters->elts)[n];
363 if (hook_spec == NULL) {
366 if (!strcasecmp(hook_spec->filter_name, f->frec->name)) {
367 spec = create_vm_spec(&pool, r, cfg, server_cfg,
368 hook_spec->file_name,
371 hook_spec->function_name,
373 L = ap_lua_get_lua_state(pool, spec, r);
375 L = lua_newthread(L);
379 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02328)
380 "lua: Failed to obtain lua interpreter for %s %s",
381 hook_spec->function_name, hook_spec->file_name);
382 ap_lua_release_state(L, spec, r);
385 if (hook_spec->function_name != NULL) {
386 lua_getglobal(L, hook_spec->function_name);
387 if (!lua_isfunction(L, -1)) {
388 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02329)
389 "lua: Unable to find entry function '%s' in %s (not a valid function)",
390 hook_spec->function_name,
391 hook_spec->file_name);
392 ap_lua_release_state(L, spec, r);
396 ap_lua_run_lua_request(L, r);
400 ap_lua_run_lua_request(L, r);
403 lua_setglobal(L, "r");
409 /* If a Lua filter is interested in filtering a request, it must first do a yield,
410 * otherwise we'll assume that it's not interested and pretend we didn't find it.
412 rc = lua_resume(L, 1);
413 if (rc == LUA_YIELD) {
414 if (f->frec->providers == NULL) {
415 /* Not wired by mod_filter */
416 apr_table_unset(r->headers_out, "Content-Length");
417 apr_table_unset(r->headers_out, "Content-MD5");
418 apr_table_unset(r->headers_out, "ETAG");
423 ap_lua_release_state(L, spec, r);
431 static apr_status_t lua_output_filter_handle(ap_filter_t *f, apr_bucket_brigade *pbbIn)
433 request_rec *r = f->r;
437 conn_rec *c = r->connection;
441 /* Set up the initial filter context and acquire the function.
442 * The corresponding Lua function should yield here.
445 rc = lua_setup_filter_ctx(f,r,&ctx);
446 if (rc == APR_EGENERAL) {
447 return HTTP_INTERNAL_SERVER_ERROR;
449 if (rc == APR_ENOENT) {
450 /* No filter entry found (or the script declined to filter), just pass on the buckets */
451 ap_remove_output_filter(f);
452 return ap_pass_brigade(f->next,pbbIn);
455 /* We've got a willing lua filter, setup and check for a prefix */
458 const char* output = lua_tolstring(ctx->L, 1, &olen);
461 ctx->tmpBucket = apr_brigade_create(r->pool, c->bucket_alloc);
464 pbktOut = apr_bucket_heap_create(output, olen, NULL, c->bucket_alloc);
465 APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut);
466 rv = ap_pass_brigade(f->next, ctx->tmpBucket);
467 apr_brigade_cleanup(ctx->tmpBucket);
468 if (rv != APR_SUCCESS) {
474 ctx = (lua_filter_ctx*) f->ctx;
476 /* While the Lua function is still yielding, pass in buckets to the coroutine */
478 for (pbktIn = APR_BRIGADE_FIRST(pbbIn);
479 pbktIn != APR_BRIGADE_SENTINEL(pbbIn);
480 pbktIn = APR_BUCKET_NEXT(pbktIn))
486 /* read the bucket */
487 apr_bucket_read(pbktIn,&data,&len,APR_BLOCK_READ);
489 /* Push the bucket onto the Lua stack as a global var */
490 lua_pushlstring(L, data, len);
491 lua_setglobal(L, "bucket");
493 /* If Lua yielded, it means we have something to pass on */
494 if (lua_resume(L, 0) == LUA_YIELD) {
496 const char* output = lua_tolstring(L, 1, &olen);
498 pbktOut = apr_bucket_heap_create(output, olen, NULL,
500 APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut);
501 rv = ap_pass_brigade(f->next, ctx->tmpBucket);
502 apr_brigade_cleanup(ctx->tmpBucket);
503 if (rv != APR_SUCCESS) {
510 ap_lua_release_state(L, ctx->spec, r);
511 ap_remove_output_filter(f);
512 apr_brigade_cleanup(pbbIn);
513 apr_brigade_cleanup(ctx->tmpBucket);
514 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02663)
515 "lua: Error while executing filter: %s",
516 lua_tostring(L, -1));
517 return HTTP_INTERNAL_SERVER_ERROR;
520 /* If we've safely reached the end, do a final call to Lua to allow for any
521 finishing moves by the script, such as appending a tail. */
522 if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pbbIn))) {
525 lua_setglobal(L, "bucket");
526 if (lua_resume(L, 0) == LUA_YIELD) {
529 const char* output = lua_tolstring(L, 1, &olen);
531 pbktOut = apr_bucket_heap_create(output, olen, NULL,
533 APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut);
536 pbktEOS = apr_bucket_eos_create(c->bucket_alloc);
537 APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktEOS);
538 ap_lua_release_state(L, ctx->spec, r);
539 rv = ap_pass_brigade(f->next, ctx->tmpBucket);
540 apr_brigade_cleanup(ctx->tmpBucket);
541 if (rv != APR_SUCCESS) {
547 apr_brigade_cleanup(pbbIn);
553 static apr_status_t lua_input_filter_handle(ap_filter_t *f,
554 apr_bucket_brigade *pbbOut,
555 ap_input_mode_t eMode,
556 apr_read_type_e eBlock,
559 request_rec *r = f->r;
560 int rc, lastCall = 0;
563 conn_rec *c = r->connection;
566 /* Set up the initial filter context and acquire the function.
567 * The corresponding Lua function should yield here.
570 rc = lua_setup_filter_ctx(f,r,&ctx);
572 if (rc == APR_EGENERAL) {
574 ap_remove_input_filter(f);
575 return HTTP_INTERNAL_SERVER_ERROR;
577 if (rc == APR_ENOENT ) {
578 ap_remove_input_filter(f);
581 if (rc == APR_SUCCESS) {
582 ctx->tmpBucket = apr_brigade_create(r->pool, c->bucket_alloc);
585 ctx = (lua_filter_ctx*) f->ctx;
587 /* If the Lua script broke or denied serving the request, just pass the buckets through */
589 return ap_get_brigade(f->next, pbbOut, eMode, eBlock, nBytes);
592 if (APR_BRIGADE_EMPTY(ctx->tmpBucket)) {
593 ret = ap_get_brigade(f->next, ctx->tmpBucket, eMode, eBlock, nBytes);
594 if (eMode == AP_MODE_EATCRLF || ret != APR_SUCCESS)
598 /* While the Lua function is still yielding, pass buckets to the coroutine */
601 while (!APR_BRIGADE_EMPTY(ctx->tmpBucket)) {
602 apr_bucket *pbktIn = APR_BRIGADE_FIRST(ctx->tmpBucket);
607 if (APR_BUCKET_IS_EOS(pbktIn)) {
608 APR_BUCKET_REMOVE(pbktIn);
612 /* read the bucket */
613 ret = apr_bucket_read(pbktIn, &data, &len, eBlock);
614 if (ret != APR_SUCCESS)
617 /* Push the bucket onto the Lua stack as a global var */
619 lua_pushlstring(L, data, len);
620 lua_setglobal(L, "bucket");
622 /* If Lua yielded, it means we have something to pass on */
623 if (lua_resume(L, 0) == LUA_YIELD) {
625 const char* output = lua_tolstring(L, 1, &olen);
626 pbktOut = apr_bucket_heap_create(output, olen, 0, c->bucket_alloc);
627 APR_BRIGADE_INSERT_TAIL(pbbOut, pbktOut);
628 apr_bucket_delete(pbktIn);
633 ap_lua_release_state(L, ctx->spec, r);
634 ap_remove_input_filter(f);
635 apr_bucket_delete(pbktIn);
636 return HTTP_INTERNAL_SERVER_ERROR;
639 /* If we've safely reached the end, do a final call to Lua to allow for any
640 finishing moves by the script, such as appending a tail. */
642 apr_bucket *pbktEOS = apr_bucket_eos_create(c->bucket_alloc);
644 lua_setglobal(L, "bucket");
645 if (lua_resume(L, 0) == LUA_YIELD) {
648 const char* output = lua_tolstring(L, 1, &olen);
649 pbktOut = apr_bucket_heap_create(output, olen, 0, c->bucket_alloc);
650 APR_BRIGADE_INSERT_TAIL(pbbOut, pbktOut);
652 APR_BRIGADE_INSERT_TAIL(pbbOut,pbktEOS);
653 ap_lua_release_state(L, ctx->spec, r);
660 /* ---------------- Configury stuff --------------- */
662 /** harnesses for magic hooks **/
664 static int lua_request_rec_hook_harness(request_rec *r, const char *name, int apr_hook_when)
669 ap_lua_vm_spec *spec;
670 ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
672 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
674 const char *key = apr_psprintf(r->pool, "%s_%d", name, apr_hook_when);
675 apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
676 APR_HASH_KEY_STRING);
679 for (i = 0; i < hook_specs->nelts; i++) {
680 ap_lua_mapped_handler_spec *hook_spec =
681 ((ap_lua_mapped_handler_spec **) hook_specs->elts)[i];
683 if (hook_spec == NULL) {
686 spec = create_vm_spec(&pool, r, cfg, server_cfg,
687 hook_spec->file_name,
689 hook_spec->bytecode_len,
690 hook_spec->function_name,
693 L = ap_lua_get_lua_state(pool, spec, r);
696 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01477)
697 "lua: Failed to obtain lua interpreter for entry function '%s' in %s",
698 hook_spec->function_name, hook_spec->file_name);
699 return HTTP_INTERNAL_SERVER_ERROR;
702 if (hook_spec->function_name != NULL) {
703 lua_getglobal(L, hook_spec->function_name);
704 if (!lua_isfunction(L, -1)) {
705 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01478)
706 "lua: Unable to find entry function '%s' in %s (not a valid function)",
707 hook_spec->function_name,
708 hook_spec->file_name);
709 ap_lua_release_state(L, spec, r);
710 return HTTP_INTERNAL_SERVER_ERROR;
713 ap_lua_run_lua_request(L, r);
717 ap_lua_run_lua_request(L, r);
720 lua_setglobal(L, "r");
724 if (lua_pcall(L, 1, 1, 0)) {
725 report_lua_error(L, r);
726 ap_lua_release_state(L, spec, r);
727 return HTTP_INTERNAL_SERVER_ERROR;
730 if (lua_isnumber(L, -1)) {
731 rc = lua_tointeger(L, -1);
732 ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, "Lua hook %s:%s for phase %s returned %d",
733 hook_spec->file_name, hook_spec->function_name, name, rc);
736 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(03017)
737 "Lua hook %s:%s for phase %s did not return a numeric value",
738 hook_spec->file_name, hook_spec->function_name, name);
739 return HTTP_INTERNAL_SERVER_ERROR;
741 if (rc != DECLINED) {
742 ap_lua_release_state(L, spec, r);
745 ap_lua_release_state(L, spec, r);
752 /* Fix for making sure that LuaMapHandler works when FallbackResource is set */
753 static int lua_map_handler_fixups(request_rec *r)
755 /* If there is no handler set yet, this might be a LuaMapHandler request */
756 if (r->handler == NULL) {
758 ap_regmatch_t match[10];
759 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
761 for (n = 0; n < cfg->mapped_handlers->nelts; n++) {
762 ap_lua_mapped_handler_spec *hook_spec =
763 ((ap_lua_mapped_handler_spec **) cfg->mapped_handlers->elts)[n];
765 if (hook_spec == NULL) {
768 if (!ap_regexec(hook_spec->uri_pattern, r->uri, 10, match, 0)) {
769 r->handler = apr_pstrdup(r->pool, "lua-map-handler");
778 static int lua_map_handler(request_rec *r)
783 const char *filename, *function_name;
784 const char *values[10];
785 ap_lua_vm_spec *spec;
786 ap_regmatch_t match[10];
787 ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
789 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
791 for (n = 0; n < cfg->mapped_handlers->nelts; n++) {
792 ap_lua_mapped_handler_spec *hook_spec =
793 ((ap_lua_mapped_handler_spec **) cfg->mapped_handlers->elts)[n];
795 if (hook_spec == NULL) {
798 if (!ap_regexec(hook_spec->uri_pattern, r->uri, 10, match, 0)) {
800 for (i=0 ; i < 10; i++) {
801 if (match[i].rm_eo >= 0) {
802 values[i] = apr_pstrndup(r->pool, r->uri+match[i].rm_so, match[i].rm_eo - match[i].rm_so);
806 filename = ap_lua_interpolate_string(r->pool, hook_spec->file_name, values);
807 function_name = ap_lua_interpolate_string(r->pool, hook_spec->function_name, values);
808 spec = create_vm_spec(&pool, r, cfg, server_cfg,
811 hook_spec->bytecode_len,
814 L = ap_lua_get_lua_state(pool, spec, r);
817 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02330)
818 "lua: Failed to obtain Lua interpreter for entry function '%s' in %s",
819 function_name, filename);
820 ap_lua_release_state(L, spec, r);
821 return HTTP_INTERNAL_SERVER_ERROR;
824 if (function_name != NULL) {
825 lua_getglobal(L, function_name);
826 if (!lua_isfunction(L, -1)) {
827 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02331)
828 "lua: Unable to find entry function '%s' in %s (not a valid function)",
831 ap_lua_release_state(L, spec, r);
832 return HTTP_INTERNAL_SERVER_ERROR;
835 ap_lua_run_lua_request(L, r);
839 ap_lua_run_lua_request(L, r);
842 lua_setglobal(L, "r");
846 if (lua_pcall(L, 1, 1, 0)) {
847 report_lua_error(L, r);
848 ap_lua_release_state(L, spec, r);
849 return HTTP_INTERNAL_SERVER_ERROR;
852 if (lua_isnumber(L, -1)) {
853 rc = lua_tointeger(L, -1);
856 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02483)
857 "lua: Lua handler %s in %s did not return a value, assuming apache2.OK",
862 ap_lua_release_state(L, spec, r);
863 if (rc != DECLINED) {
872 static apr_size_t config_getstr(ap_configfile_t *cfg, char *buf,
878 apr_status_t rc = (cfg->getstr) (buf, bufsiz, cfg->param);
879 if (rc == APR_SUCCESS) {
881 if (i && buf[i - 1] == '\n')
892 apr_status_t rc = (cfg->getch) (&ch, cfg->param);
893 if (rc != APR_SUCCESS)
905 typedef struct cr_ctx
908 ap_configfile_t *cfp;
911 char buf[HUGE_STRING_LEN];
915 /* Okay, this deserves a little explanation -- in order for the errors that lua
916 * generates to be 'accuarate', including line numbers, we basically inject
917 * N line number new lines into the 'top' of the chunk reader.....
919 * be happy. this is cool.
922 static const char *lf =
923 "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
926 static const char *direct_chunkreader(lua_State *lvm, void *udata,
930 struct cr_ctx *ctx = udata;
932 if (ctx->startline) {
933 *plen = ctx->startline > N_LF ? N_LF : ctx->startline;
934 ctx->startline -= *plen;
937 *plen = config_getstr(ctx->cfp, ctx->buf, HUGE_STRING_LEN);
939 for (p = ctx->buf; isspace(*p); ++p);
940 if (p[0] == '<' && p[1] == '/') {
942 while (i < strlen(ctx->endstr)) {
943 if (tolower(p[i + 2]) != ctx->endstr[i])
950 /*fprintf(stderr, "buf read: %s\n", ctx->buf); */
954 static int ldump_writer(lua_State *L, const void *b, size_t size, void *B)
957 luaL_addlstring((luaL_Buffer *) B, (const char *) b, size);
961 typedef struct hack_section_baton
964 ap_lua_mapped_handler_spec *spec;
966 } hack_section_baton;
968 /* You can be unhappy now.
972 * When you create a <Section handler in httpd, the only 'easy' way to create
973 * a directory context is to parse the section, and convert it into a 'normal'
974 * Configureation option, and then collapse the entire section, in memory,
975 * back into the parent section -- from which you can then get the new directive
976 * invoked.... anyways. evil. Rici taught me how to do this hack :-)
978 static const char *hack_section_handler(cmd_parms *cmd, void *_cfg,
981 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
982 ap_directive_t *directive = cmd->directive;
983 hack_section_baton *baton = directive->data;
984 const char *key = apr_psprintf(cmd->pool, "%s_%d", baton->name, baton->apr_hook_when);
986 apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
987 APR_HASH_KEY_STRING);
989 hook_specs = apr_array_make(cmd->pool, 2,
990 sizeof(ap_lua_mapped_handler_spec *));
991 apr_hash_set(cfg->hooks, key,
992 APR_HASH_KEY_STRING, hook_specs);
995 baton->spec->scope = cfg->vm_scope;
997 *(ap_lua_mapped_handler_spec **) apr_array_push(hook_specs) = baton->spec;
1002 static const char *register_named_block_function_hook(const char *name,
1007 const char *function = NULL;
1008 ap_lua_mapped_handler_spec *spec;
1009 int when = APR_HOOK_MIDDLE;
1010 const char *endp = ap_strrchr_c(line, '>');
1013 return apr_pstrcat(cmd->pool, cmd->cmd->name,
1014 "> directive missing closing '>'", NULL);
1017 line = apr_pstrndup(cmd->temp_pool, line, endp - line);
1021 word = ap_getword_conf(cmd->temp_pool, &line);
1023 function = apr_pstrdup(cmd->pool, word);
1025 word = ap_getword_conf(cmd->temp_pool, &line);
1027 if (!strcasecmp("early", word)) {
1028 when = AP_LUA_HOOK_FIRST;
1030 else if (!strcasecmp("late", word)) {
1031 when = AP_LUA_HOOK_LAST;
1034 return apr_pstrcat(cmd->pool, cmd->cmd->name,
1035 "> 2nd argument must be 'early' or 'late'", NULL);
1040 spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec));
1047 ap_directive_t **current;
1048 hack_section_baton *baton;
1050 spec->file_name = apr_psprintf(cmd->pool, "%s:%u",
1051 cmd->config_file->name,
1052 cmd->config_file->line_number);
1054 spec->function_name = (char *) function;
1061 tmp = apr_pstrdup(cmd->pool, cmd->err_directive->directive + 1);
1062 ap_str_tolower(tmp);
1064 ctx.cfp = cmd->config_file;
1065 ctx.startline = cmd->config_file->line_number;
1067 /* This lua State is used only to compile the input strings -> bytecode, so we don't need anything extra. */
1068 lvm = luaL_newstate();
1072 rv = lua_load(lvm, direct_chunkreader, &ctx, spec->file_name);
1075 const char *errstr = apr_pstrcat(cmd->pool, "Lua Error:",
1076 lua_tostring(lvm, -1), NULL);
1082 luaL_buffinit(lvm, &b);
1083 lua_dump(lvm, ldump_writer, &b);
1084 luaL_pushresult(&b);
1085 spec->bytecode_len = lua_rawlen(lvm, -1);
1086 spec->bytecode = apr_pstrmemdup(cmd->pool, lua_tostring(lvm, -1),
1087 spec->bytecode_len);
1093 /* Here, we have to replace our current config node for the next pass */
1095 *current = apr_pcalloc(cmd->pool, sizeof(**current));
1098 baton = apr_pcalloc(cmd->pool, sizeof(hack_section_baton));
1101 baton->apr_hook_when = when;
1103 (*current)->filename = cmd->config_file->name;
1104 (*current)->line_num = cmd->config_file->line_number;
1105 (*current)->directive = apr_pstrdup(cmd->pool, "Lua_____ByteCodeHack");
1106 (*current)->args = NULL;
1107 (*current)->data = baton;
1113 static const char *register_named_file_function_hook(const char *name,
1117 const char *function,
1120 ap_lua_mapped_handler_spec *spec;
1121 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1122 const char *key = apr_psprintf(cmd->pool, "%s_%d", name, apr_hook_when);
1123 apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
1124 APR_HASH_KEY_STRING);
1127 hook_specs = apr_array_make(cmd->pool, 2,
1128 sizeof(ap_lua_mapped_handler_spec *));
1129 apr_hash_set(cfg->hooks, key, APR_HASH_KEY_STRING, hook_specs);
1132 spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec));
1133 spec->file_name = apr_pstrdup(cmd->pool, file);
1134 spec->function_name = apr_pstrdup(cmd->pool, function);
1135 spec->scope = cfg->vm_scope;
1137 *(ap_lua_mapped_handler_spec **) apr_array_push(hook_specs) = spec;
1140 static const char *register_mapped_file_function_hook(const char *pattern,
1144 const char *function)
1146 ap_lua_mapped_handler_spec *spec;
1147 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1148 ap_regex_t *regex = apr_pcalloc(cmd->pool, sizeof(ap_regex_t));
1149 if (ap_regcomp(regex, pattern,0)) {
1150 return "Invalid regex pattern!";
1153 spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec));
1154 spec->file_name = apr_pstrdup(cmd->pool, file);
1155 spec->function_name = apr_pstrdup(cmd->pool, function);
1156 spec->scope = cfg->vm_scope;
1157 spec->uri_pattern = regex;
1159 *(ap_lua_mapped_handler_spec **) apr_array_push(cfg->mapped_handlers) = spec;
1162 static const char *register_filter_function_hook(const char *filter,
1166 const char *function,
1169 ap_lua_filter_handler_spec *spec;
1170 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1172 spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_filter_handler_spec));
1173 spec->file_name = apr_pstrdup(cmd->pool, file);
1174 spec->function_name = apr_pstrdup(cmd->pool, function);
1175 spec->filter_name = filter;
1177 *(ap_lua_filter_handler_spec **) apr_array_push(cfg->mapped_filters) = spec;
1178 /* TODO: Make it work on other types than just AP_FTYPE_RESOURCE? */
1179 if (direction == AP_LUA_FILTER_OUTPUT) {
1180 spec->direction = AP_LUA_FILTER_OUTPUT;
1181 ap_register_output_filter_protocol(filter, lua_output_filter_handle, NULL, AP_FTYPE_RESOURCE,
1182 AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH);
1185 spec->direction = AP_LUA_FILTER_INPUT;
1186 ap_register_input_filter(filter, lua_input_filter_handle, NULL, AP_FTYPE_RESOURCE);
1190 /* disabled (see reference below)
1191 static int lua_check_user_id_harness_first(request_rec *r)
1193 return lua_request_rec_hook_harness(r, "check_user_id", AP_LUA_HOOK_FIRST);
1196 static int lua_check_user_id_harness(request_rec *r)
1198 return lua_request_rec_hook_harness(r, "check_user_id", APR_HOOK_MIDDLE);
1200 /* disabled (see reference below)
1201 static int lua_check_user_id_harness_last(request_rec *r)
1203 return lua_request_rec_hook_harness(r, "check_user_id", AP_LUA_HOOK_LAST);
1207 static int lua_translate_name_harness_first(request_rec *r)
1209 return lua_request_rec_hook_harness(r, "translate_name", AP_LUA_HOOK_FIRST);
1211 static int lua_translate_name_harness(request_rec *r)
1213 return lua_request_rec_hook_harness(r, "translate_name", APR_HOOK_MIDDLE);
1215 static int lua_translate_name_harness_last(request_rec *r)
1217 return lua_request_rec_hook_harness(r, "translate_name", AP_LUA_HOOK_LAST);
1220 static int lua_fixup_harness(request_rec *r)
1222 return lua_request_rec_hook_harness(r, "fixups", APR_HOOK_MIDDLE);
1225 static int lua_map_to_storage_harness(request_rec *r)
1227 return lua_request_rec_hook_harness(r, "map_to_storage", APR_HOOK_MIDDLE);
1230 static int lua_type_checker_harness(request_rec *r)
1232 return lua_request_rec_hook_harness(r, "type_checker", APR_HOOK_MIDDLE);
1235 static int lua_access_checker_harness_first(request_rec *r)
1237 return lua_request_rec_hook_harness(r, "access_checker", AP_LUA_HOOK_FIRST);
1239 static int lua_access_checker_harness(request_rec *r)
1241 return lua_request_rec_hook_harness(r, "access_checker", APR_HOOK_MIDDLE);
1243 static int lua_access_checker_harness_last(request_rec *r)
1245 return lua_request_rec_hook_harness(r, "access_checker", AP_LUA_HOOK_LAST);
1248 static int lua_auth_checker_harness_first(request_rec *r)
1250 return lua_request_rec_hook_harness(r, "auth_checker", AP_LUA_HOOK_FIRST);
1252 static int lua_auth_checker_harness(request_rec *r)
1254 return lua_request_rec_hook_harness(r, "auth_checker", APR_HOOK_MIDDLE);
1256 static int lua_auth_checker_harness_last(request_rec *r)
1258 return lua_request_rec_hook_harness(r, "auth_checker", AP_LUA_HOOK_LAST);
1260 static void lua_insert_filter_harness(request_rec *r)
1262 /* ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(03223)
1263 * "LuaHookInsertFilter not yet implemented"); */
1266 static int lua_log_transaction_harness(request_rec *r)
1268 return lua_request_rec_hook_harness(r, "log_transaction", APR_HOOK_FIRST);
1271 static int lua_quick_harness(request_rec *r, int lookup)
1276 return lua_request_rec_hook_harness(r, "quick", APR_HOOK_MIDDLE);
1279 static const char *register_translate_name_hook(cmd_parms *cmd, void *_cfg,
1281 const char *function,
1284 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
1286 int apr_hook_when = APR_HOOK_MIDDLE;
1292 if (!strcasecmp(when, "early")) {
1293 apr_hook_when = AP_LUA_HOOK_FIRST;
1295 else if (!strcasecmp(when, "late")) {
1296 apr_hook_when = AP_LUA_HOOK_LAST;
1299 return "Third argument must be 'early' or 'late'";
1303 return register_named_file_function_hook("translate_name", cmd, _cfg,
1304 file, function, apr_hook_when);
1307 static const char *register_translate_name_block(cmd_parms *cmd, void *_cfg,
1310 return register_named_block_function_hook("translate_name", cmd, _cfg,
1315 static const char *register_fixups_hook(cmd_parms *cmd, void *_cfg,
1317 const char *function)
1319 return register_named_file_function_hook("fixups", cmd, _cfg, file,
1320 function, APR_HOOK_MIDDLE);
1322 static const char *register_fixups_block(cmd_parms *cmd, void *_cfg,
1325 return register_named_block_function_hook("fixups", cmd, _cfg, line);
1328 static const char *register_map_to_storage_hook(cmd_parms *cmd, void *_cfg,
1330 const char *function)
1332 return register_named_file_function_hook("map_to_storage", cmd, _cfg,
1333 file, function, APR_HOOK_MIDDLE);
1336 static const char *register_log_transaction_hook(cmd_parms *cmd, void *_cfg,
1338 const char *function)
1340 return register_named_file_function_hook("log_transaction", cmd, _cfg,
1341 file, function, APR_HOOK_FIRST);
1344 static const char *register_map_to_storage_block(cmd_parms *cmd, void *_cfg,
1347 return register_named_block_function_hook("map_to_storage", cmd, _cfg,
1352 static const char *register_check_user_id_hook(cmd_parms *cmd, void *_cfg,
1354 const char *function,
1357 int apr_hook_when = APR_HOOK_MIDDLE;
1358 /* XXX: This does not currently work!!
1360 if (!strcasecmp(when, "early")) {
1361 apr_hook_when = AP_LUA_HOOK_FIRST;
1363 else if (!strcasecmp(when, "late")) {
1364 apr_hook_when = AP_LUA_HOOK_LAST;
1367 return "Third argument must be 'early' or 'late'";
1371 return register_named_file_function_hook("check_user_id", cmd, _cfg, file,
1372 function, apr_hook_when);
1374 static const char *register_check_user_id_block(cmd_parms *cmd, void *_cfg,
1377 return register_named_block_function_hook("check_user_id", cmd, _cfg,
1381 static const char *register_type_checker_hook(cmd_parms *cmd, void *_cfg,
1383 const char *function)
1385 return register_named_file_function_hook("type_checker", cmd, _cfg, file,
1386 function, APR_HOOK_MIDDLE);
1388 static const char *register_type_checker_block(cmd_parms *cmd, void *_cfg,
1391 return register_named_block_function_hook("type_checker", cmd, _cfg,
1395 static const char *register_access_checker_hook(cmd_parms *cmd, void *_cfg,
1397 const char *function,
1400 int apr_hook_when = APR_HOOK_MIDDLE;
1403 if (!strcasecmp(when, "early")) {
1404 apr_hook_when = AP_LUA_HOOK_FIRST;
1406 else if (!strcasecmp(when, "late")) {
1407 apr_hook_when = AP_LUA_HOOK_LAST;
1410 return "Third argument must be 'early' or 'late'";
1414 return register_named_file_function_hook("access_checker", cmd, _cfg,
1415 file, function, apr_hook_when);
1417 static const char *register_access_checker_block(cmd_parms *cmd, void *_cfg,
1421 return register_named_block_function_hook("access_checker", cmd, _cfg,
1425 static const char *register_auth_checker_hook(cmd_parms *cmd, void *_cfg,
1427 const char *function,
1430 int apr_hook_when = APR_HOOK_MIDDLE;
1433 if (!strcasecmp(when, "early")) {
1434 apr_hook_when = AP_LUA_HOOK_FIRST;
1436 else if (!strcasecmp(when, "late")) {
1437 apr_hook_when = AP_LUA_HOOK_LAST;
1440 return "Third argument must be 'early' or 'late'";
1444 return register_named_file_function_hook("auth_checker", cmd, _cfg, file,
1445 function, apr_hook_when);
1447 static const char *register_auth_checker_block(cmd_parms *cmd, void *_cfg,
1450 return register_named_block_function_hook("auth_checker", cmd, _cfg,
1454 static const char *register_insert_filter_hook(cmd_parms *cmd, void *_cfg,
1456 const char *function)
1458 return "LuaHookInsertFilter not yet implemented";
1461 static const char *register_quick_hook(cmd_parms *cmd, void *_cfg,
1462 const char *file, const char *function)
1464 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
1469 return register_named_file_function_hook("quick", cmd, _cfg, file,
1470 function, APR_HOOK_MIDDLE);
1472 static const char *register_map_handler(cmd_parms *cmd, void *_cfg,
1473 const char* match, const char *file, const char *function)
1475 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
1480 if (!function) function = "handle";
1481 return register_mapped_file_function_hook(match, cmd, _cfg, file,
1484 static const char *register_output_filter(cmd_parms *cmd, void *_cfg,
1485 const char* filter, const char *file, const char *function)
1487 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
1492 if (!function) function = "handle";
1493 return register_filter_function_hook(filter, cmd, _cfg, file,
1494 function, AP_LUA_FILTER_OUTPUT);
1496 static const char *register_input_filter(cmd_parms *cmd, void *_cfg,
1497 const char* filter, const char *file, const char *function)
1499 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
1504 if (!function) function = "handle";
1505 return register_filter_function_hook(filter, cmd, _cfg, file,
1506 function, AP_LUA_FILTER_INPUT);
1508 static const char *register_quick_block(cmd_parms *cmd, void *_cfg,
1511 return register_named_block_function_hook("quick", cmd, _cfg,
1517 static const char *register_package_helper(cmd_parms *cmd,
1519 apr_array_header_t *dir_array)
1523 ap_lua_server_cfg *server_cfg =
1524 ap_get_module_config(cmd->server->module_config, &lua_module);
1526 char *fixed_filename;
1527 rv = apr_filepath_merge(&fixed_filename,
1528 server_cfg->root_path,
1530 APR_FILEPATH_NOTRELATIVE,
1533 if (rv != APR_SUCCESS) {
1534 return apr_psprintf(cmd->pool,
1535 "Unable to build full path to file, %s", arg);
1538 *(const char **) apr_array_push(dir_array) = fixed_filename;
1544 * Called for config directive which looks like
1545 * LuaPackagePath /lua/package/path/mapped/thing/like/this/?.lua
1547 static const char *register_package_dir(cmd_parms *cmd, void *_cfg,
1550 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1552 return register_package_helper(cmd, arg, cfg->package_paths);
1556 * Called for config directive which looks like
1557 * LuaPackageCPath /lua/package/path/mapped/thing/like/this/?.so
1559 static const char *register_package_cdir(cmd_parms *cmd,
1563 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1565 return register_package_helper(cmd, arg, cfg->package_cpaths);
1568 static const char *register_lua_inherit(cmd_parms *cmd,
1572 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1574 if (strcasecmp("none", arg) == 0) {
1575 cfg->inherit = AP_LUA_INHERIT_NONE;
1577 else if (strcasecmp("parent-first", arg) == 0) {
1578 cfg->inherit = AP_LUA_INHERIT_PARENT_FIRST;
1580 else if (strcasecmp("parent-last", arg) == 0) {
1581 cfg->inherit = AP_LUA_INHERIT_PARENT_LAST;
1584 return apr_psprintf(cmd->pool,
1585 "LuaInherit type of '%s' not recognized, valid "
1586 "options are 'none', 'parent-first', and 'parent-last'",
1591 static const char *register_lua_codecache(cmd_parms *cmd,
1595 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1597 if (strcasecmp("never", arg) == 0) {
1598 cfg->codecache = AP_LUA_CACHE_NEVER;
1600 else if (strcasecmp("stat", arg) == 0) {
1601 cfg->codecache = AP_LUA_CACHE_STAT;
1603 else if (strcasecmp("forever", arg) == 0) {
1604 cfg->codecache = AP_LUA_CACHE_FOREVER;
1607 return apr_psprintf(cmd->pool,
1608 "LuaCodeCache type of '%s' not recognized, valid "
1609 "options are 'never', 'stat', and 'forever'",
1614 static const char *register_lua_scope(cmd_parms *cmd,
1620 ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1621 if (strcmp("once", scope) == 0) {
1622 cfg->vm_scope = AP_LUA_SCOPE_ONCE;
1624 else if (strcmp("request", scope) == 0) {
1625 cfg->vm_scope = AP_LUA_SCOPE_REQUEST;
1627 else if (strcmp("conn", scope) == 0) {
1628 cfg->vm_scope = AP_LUA_SCOPE_CONN;
1630 else if (strcmp("thread", scope) == 0) {
1631 #if !APR_HAS_THREADS
1632 return apr_psprintf(cmd->pool,
1633 "Scope type of '%s' cannot be used because this "
1634 "server does not have threading support "
1638 cfg->vm_scope = AP_LUA_SCOPE_THREAD;
1640 else if (strcmp("server", scope) == 0) {
1641 unsigned int vmin, vmax;
1642 #if !APR_HAS_THREADS
1643 return apr_psprintf(cmd->pool,
1644 "Scope type of '%s' cannot be used because this "
1645 "server does not have threading support "
1649 cfg->vm_scope = AP_LUA_SCOPE_SERVER;
1650 vmin = min ? atoi(min) : 1;
1651 vmax = max ? atoi(max) : 1;
1662 return apr_psprintf(cmd->pool,
1663 "Invalid value for LuaScope, '%s', acceptable "
1664 "values are: 'once', 'request', 'conn'"
1666 ", 'thread', 'server'"
1676 static const char *register_lua_root(cmd_parms *cmd, void *_cfg,
1679 /* ap_lua_dir_cfg* cfg = (ap_lua_dir_cfg*)_cfg; */
1680 ap_lua_server_cfg *cfg = ap_get_module_config(cmd->server->module_config,
1683 cfg->root_path = root;
1687 const char *ap_lua_ssl_val(apr_pool_t *p, server_rec *s, conn_rec *c,
1688 request_rec *r, const char *var)
1691 return (const char *)lua_ssl_val(p, s, c, r, (char *)var);
1696 int ap_lua_ssl_is_https(conn_rec *c)
1698 return lua_ssl_is_https ? lua_ssl_is_https(c) : 0;
1701 /*******************************/
1703 static const char *lua_authz_parse(cmd_parms *cmd, const char *require_line,
1704 const void **parsed_require_line)
1706 const char *provider_name;
1707 lua_authz_provider_spec *spec;
1708 lua_authz_provider_func *func = apr_pcalloc(cmd->pool, sizeof(lua_authz_provider_func));
1710 apr_pool_userdata_get((void**)&provider_name, AUTHZ_PROVIDER_NAME_NOTE,
1712 ap_assert(provider_name != NULL);
1714 spec = apr_hash_get(lua_authz_providers, provider_name, APR_HASH_KEY_STRING);
1715 ap_assert(spec != NULL);
1718 if (require_line && *require_line) {
1720 func->args = apr_array_make(cmd->pool, 2, sizeof(const char *));
1721 while ((arg = ap_getword_conf(cmd->pool, &require_line)) && *arg) {
1722 APR_ARRAY_PUSH(func->args, const char *) = arg;
1726 *parsed_require_line = func;
1730 static authz_status lua_authz_check(request_rec *r, const char *require_line,
1731 const void *parsed_require_line)
1734 ap_lua_vm_spec *spec;
1736 ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
1738 const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
1740 const lua_authz_provider_func *prov_func = parsed_require_line;
1741 const lua_authz_provider_spec *prov_spec = prov_func->spec;
1745 spec = create_vm_spec(&pool, r, cfg, server_cfg, prov_spec->file_name,
1746 NULL, 0, prov_spec->function_name, "authz provider");
1748 L = ap_lua_get_lua_state(pool, spec, r);
1750 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02314)
1751 "Unable to compile VM for authz provider %s", prov_spec->name);
1752 return AUTHZ_GENERAL_ERROR;
1754 lua_getglobal(L, prov_spec->function_name);
1755 if (!lua_isfunction(L, -1)) {
1756 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02319)
1757 "Unable to find entry function '%s' in %s (not a valid function)",
1758 prov_spec->function_name, prov_spec->file_name);
1759 ap_lua_release_state(L, spec, r);
1760 return AUTHZ_GENERAL_ERROR;
1762 ap_lua_run_lua_request(L, r);
1763 if (prov_func->args) {
1765 if (!lua_checkstack(L, prov_func->args->nelts)) {
1766 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02315)
1767 "Error: authz provider %s: too many arguments", prov_spec->name);
1768 ap_lua_release_state(L, spec, r);
1769 return AUTHZ_GENERAL_ERROR;
1771 for (i = 0; i < prov_func->args->nelts; i++) {
1772 const char *arg = APR_ARRAY_IDX(prov_func->args, i, const char *);
1773 lua_pushstring(L, arg);
1775 nargs = prov_func->args->nelts;
1777 if (lua_pcall(L, 1 + nargs, 1, 0)) {
1778 const char *err = lua_tostring(L, -1);
1779 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02316)
1780 "Error executing authz provider %s: %s", prov_spec->name, err);
1781 ap_lua_release_state(L, spec, r);
1782 return AUTHZ_GENERAL_ERROR;
1784 if (!lua_isnumber(L, -1)) {
1785 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02317)
1786 "Error: authz provider %s did not return integer", prov_spec->name);
1787 ap_lua_release_state(L, spec, r);
1788 return AUTHZ_GENERAL_ERROR;
1790 result = lua_tointeger(L, -1);
1791 ap_lua_release_state(L, spec, r);
1796 case AUTHZ_GENERAL_ERROR:
1797 case AUTHZ_DENIED_NO_USER:
1800 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02318)
1801 "Error: authz provider %s: invalid return value %d",
1802 prov_spec->name, result);
1804 return AUTHZ_GENERAL_ERROR;
1807 static const authz_provider lua_authz_provider =
1813 static const char *register_authz_provider(cmd_parms *cmd, void *_cfg,
1814 const char *name, const char *file,
1815 const char *function)
1817 lua_authz_provider_spec *spec;
1818 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1822 spec = apr_pcalloc(cmd->pool, sizeof(*spec));
1824 spec->file_name = file;
1825 spec->function_name = function;
1827 apr_hash_set(lua_authz_providers, name, APR_HASH_KEY_STRING, spec);
1828 ap_register_auth_provider(cmd->pool, AUTHZ_PROVIDER_GROUP, name,
1829 AUTHZ_PROVIDER_VERSION,
1830 &lua_authz_provider,
1831 AP_AUTH_INTERNAL_PER_CONF);
1836 command_rec lua_commands[] = {
1838 AP_INIT_TAKE1("LuaRoot", register_lua_root, NULL, OR_ALL,
1839 "Specify the base path for resolving relative paths for mod_lua directives"),
1841 AP_INIT_TAKE1("LuaPackagePath", register_package_dir, NULL, OR_ALL,
1842 "Add a directory to lua's package.path"),
1844 AP_INIT_TAKE1("LuaPackageCPath", register_package_cdir, NULL, OR_ALL,
1845 "Add a directory to lua's package.cpath"),
1847 AP_INIT_TAKE3("LuaAuthzProvider", register_authz_provider, NULL, RSRC_CONF|EXEC_ON_READ,
1848 "Provide an authorization provider"),
1850 AP_INIT_TAKE23("LuaHookTranslateName", register_translate_name_hook, NULL,
1852 "Provide a hook for the translate name phase of request processing"),
1854 AP_INIT_RAW_ARGS("<LuaHookTranslateName", register_translate_name_block,
1856 EXEC_ON_READ | OR_ALL,
1857 "Provide a hook for the translate name phase of request processing"),
1859 AP_INIT_TAKE2("LuaHookFixups", register_fixups_hook, NULL, OR_ALL,
1860 "Provide a hook for the fixups phase of request processing"),
1861 AP_INIT_RAW_ARGS("<LuaHookFixups", register_fixups_block, NULL,
1862 EXEC_ON_READ | OR_ALL,
1863 "Provide a inline hook for the fixups phase of request processing"),
1866 AP_INIT_TAKE2("LuaHookMapToStorage", register_map_to_storage_hook, NULL,
1868 "Provide a hook for the map_to_storage phase of request processing"),
1869 AP_INIT_RAW_ARGS("<LuaHookMapToStorage", register_map_to_storage_block,
1871 EXEC_ON_READ | OR_ALL,
1872 "Provide a hook for the map_to_storage phase of request processing"),
1875 AP_INIT_TAKE23("LuaHookCheckUserID", register_check_user_id_hook, NULL,
1877 "Provide a hook for the check_user_id phase of request processing"),
1878 AP_INIT_RAW_ARGS("<LuaHookCheckUserID", register_check_user_id_block,
1880 EXEC_ON_READ | OR_ALL,
1881 "Provide a hook for the check_user_id phase of request processing"),
1884 AP_INIT_TAKE2("LuaHookTypeChecker", register_type_checker_hook, NULL,
1886 "Provide a hook for the type_checker phase of request processing"),
1887 AP_INIT_RAW_ARGS("<LuaHookTypeChecker", register_type_checker_block, NULL,
1888 EXEC_ON_READ | OR_ALL,
1889 "Provide a hook for the type_checker phase of request processing"),
1892 AP_INIT_TAKE23("LuaHookAccessChecker", register_access_checker_hook, NULL,
1894 "Provide a hook for the access_checker phase of request processing"),
1895 AP_INIT_RAW_ARGS("<LuaHookAccessChecker", register_access_checker_block,
1897 EXEC_ON_READ | OR_ALL,
1898 "Provide a hook for the access_checker phase of request processing"),
1901 AP_INIT_TAKE23("LuaHookAuthChecker", register_auth_checker_hook, NULL,
1903 "Provide a hook for the auth_checker phase of request processing"),
1904 AP_INIT_RAW_ARGS("<LuaHookAuthChecker", register_auth_checker_block, NULL,
1905 EXEC_ON_READ | OR_ALL,
1906 "Provide a hook for the auth_checker phase of request processing"),
1909 AP_INIT_TAKE2("LuaHookInsertFilter", register_insert_filter_hook, NULL,
1911 "Provide a hook for the insert_filter phase of request processing"),
1913 AP_INIT_TAKE2("LuaHookLog", register_log_transaction_hook, NULL,
1915 "Provide a hook for the logging phase of request processing"),
1917 AP_INIT_TAKE123("LuaScope", register_lua_scope, NULL, OR_ALL,
1918 "One of once, request, conn, server -- default is once"),
1920 AP_INIT_TAKE1("LuaInherit", register_lua_inherit, NULL, OR_ALL,
1921 "Controls how Lua scripts in parent contexts are merged with the current "
1922 " context: none|parent-last|parent-first (default: parent-first) "),
1924 AP_INIT_TAKE1("LuaCodeCache", register_lua_codecache, NULL, OR_ALL,
1925 "Controls the behavior of the in-memory code cache "
1926 " context: stat|forever|never (default: stat) "),
1928 AP_INIT_TAKE2("LuaQuickHandler", register_quick_hook, NULL, OR_ALL,
1929 "Provide a hook for the quick handler of request processing"),
1930 AP_INIT_RAW_ARGS("<LuaQuickHandler", register_quick_block, NULL,
1931 EXEC_ON_READ | OR_ALL,
1932 "Provide a hook for the quick handler of request processing"),
1933 AP_INIT_RAW_ARGS("Lua_____ByteCodeHack", hack_section_handler, NULL,
1935 "(internal) Byte code handler"),
1936 AP_INIT_TAKE23("LuaMapHandler", register_map_handler, NULL, OR_ALL,
1937 "Maps a path to a lua handler"),
1938 AP_INIT_TAKE3("LuaOutputFilter", register_output_filter, NULL, OR_ALL,
1939 "Registers a Lua function as an output filter"),
1940 AP_INIT_TAKE3("LuaInputFilter", register_input_filter, NULL, OR_ALL,
1941 "Registers a Lua function as an input filter"),
1946 static void *create_dir_config(apr_pool_t *p, char *dir)
1948 ap_lua_dir_cfg *cfg = apr_pcalloc(p, sizeof(ap_lua_dir_cfg));
1949 cfg->package_paths = apr_array_make(p, 2, sizeof(char *));
1950 cfg->package_cpaths = apr_array_make(p, 2, sizeof(char *));
1951 cfg->mapped_handlers =
1952 apr_array_make(p, 1, sizeof(ap_lua_mapped_handler_spec *));
1953 cfg->mapped_filters =
1954 apr_array_make(p, 1, sizeof(ap_lua_filter_handler_spec *));
1956 cfg->hooks = apr_hash_make(p);
1957 cfg->dir = apr_pstrdup(p, dir);
1958 cfg->vm_scope = AP_LUA_SCOPE_UNSET;
1959 cfg->codecache = AP_LUA_CACHE_UNSET;
1962 cfg->inherit = AP_LUA_INHERIT_UNSET;
1967 static int create_request_config(request_rec *r)
1969 ap_lua_request_cfg *cfg = apr_palloc(r->pool, sizeof(ap_lua_request_cfg));
1970 cfg->mapped_request_details = NULL;
1971 cfg->request_scoped_vms = apr_hash_make(r->pool);
1972 ap_set_module_config(r->request_config, &lua_module, cfg);
1976 static void *create_server_config(apr_pool_t *p, server_rec *s)
1979 ap_lua_server_cfg *cfg = apr_pcalloc(p, sizeof(ap_lua_server_cfg));
1980 cfg->root_path = NULL;
1985 static int lua_request_hook(lua_State *L, request_rec *r)
1987 ap_lua_push_request(L, r);
1991 static int lua_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
1994 ap_mutex_register(pconf, "lua-ivm-shm", NULL, APR_LOCK_DEFAULT, 0);
1998 static int lua_post_config(apr_pool_t *pconf, apr_pool_t *plog,
1999 apr_pool_t *ptemp, server_rec *s)
2004 lua_ssl_val = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
2005 lua_ssl_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
2007 if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG)
2010 /* Create ivm mutex */
2011 rs = ap_global_mutex_create(&lua_ivm_mutex, NULL, "lua-ivm-shm", NULL,
2013 if (APR_SUCCESS != rs) {
2014 return HTTP_INTERNAL_SERVER_ERROR;
2017 /* Create shared memory space, anonymous first if possible. */
2018 rs = apr_shm_create(&lua_ivm_shm, sizeof pool, NULL, pconf);
2019 if (APR_STATUS_IS_ENOTIMPL(rs)) {
2020 /* Fall back to filename-based; nuke any left-over first. */
2021 lua_ivm_shmfile = ap_runtime_dir_relative(pconf, DEFAULT_LUA_SHMFILE);
2023 apr_shm_remove(lua_ivm_shmfile, pconf);
2025 rs = apr_shm_create(&lua_ivm_shm, sizeof pool, lua_ivm_shmfile, pconf);
2027 if (rs != APR_SUCCESS) {
2028 ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, APLOGNO(02665)
2029 "mod_lua: Failed to create shared memory segment on file %s",
2030 lua_ivm_shmfile ? lua_ivm_shmfile : "(anonymous)");
2031 return HTTP_INTERNAL_SERVER_ERROR;
2033 pool = (apr_pool_t **)apr_shm_baseaddr_get(lua_ivm_shm);
2034 apr_pool_create(pool, pconf);
2035 apr_pool_cleanup_register(pconf, NULL, shm_cleanup_wrapper,
2036 apr_pool_cleanup_null);
2039 static void *overlay_hook_specs(apr_pool_t *p,
2042 const void *overlay_val,
2043 const void *base_val,
2046 const apr_array_header_t *overlay_info = (const apr_array_header_t*)overlay_val;
2047 const apr_array_header_t *base_info = (const apr_array_header_t*)base_val;
2048 return apr_array_append(p, base_info, overlay_info);
2051 static void *merge_dir_config(apr_pool_t *p, void *basev, void *overridesv)
2053 ap_lua_dir_cfg *a, *base, *overrides;
2055 a = (ap_lua_dir_cfg *)apr_pcalloc(p, sizeof(ap_lua_dir_cfg));
2056 base = (ap_lua_dir_cfg*)basev;
2057 overrides = (ap_lua_dir_cfg*)overridesv;
2059 a->pool = overrides->pool;
2060 a->dir = apr_pstrdup(p, overrides->dir);
2062 a->vm_scope = (overrides->vm_scope == AP_LUA_SCOPE_UNSET) ? base->vm_scope: overrides->vm_scope;
2063 a->inherit = (overrides->inherit == AP_LUA_INHERIT_UNSET) ? base->inherit : overrides->inherit;
2064 a->codecache = (overrides->codecache == AP_LUA_CACHE_UNSET) ? base->codecache : overrides->codecache;
2066 a->vm_min = (overrides->vm_min == 0) ? base->vm_min : overrides->vm_min;
2067 a->vm_max = (overrides->vm_max == 0) ? base->vm_max : overrides->vm_max;
2069 if (a->inherit == AP_LUA_INHERIT_UNSET || a->inherit == AP_LUA_INHERIT_PARENT_FIRST) {
2070 a->package_paths = apr_array_append(p, base->package_paths, overrides->package_paths);
2071 a->package_cpaths = apr_array_append(p, base->package_cpaths, overrides->package_cpaths);
2072 a->mapped_handlers = apr_array_append(p, base->mapped_handlers, overrides->mapped_handlers);
2073 a->mapped_filters = apr_array_append(p, base->mapped_filters, overrides->mapped_filters);
2074 a->hooks = apr_hash_merge(p, overrides->hooks, base->hooks, overlay_hook_specs, NULL);
2076 else if (a->inherit == AP_LUA_INHERIT_PARENT_LAST) {
2077 a->package_paths = apr_array_append(p, overrides->package_paths, base->package_paths);
2078 a->package_cpaths = apr_array_append(p, overrides->package_cpaths, base->package_cpaths);
2079 a->mapped_handlers = apr_array_append(p, overrides->mapped_handlers, base->mapped_handlers);
2080 a->mapped_filters = apr_array_append(p, overrides->mapped_filters, base->mapped_filters);
2081 a->hooks = apr_hash_merge(p, base->hooks, overrides->hooks, overlay_hook_specs, NULL);
2084 a->package_paths = overrides->package_paths;
2085 a->package_cpaths = overrides->package_cpaths;
2086 a->mapped_handlers= overrides->mapped_handlers;
2087 a->mapped_filters= overrides->mapped_filters;
2088 a->hooks= overrides->hooks;
2094 static void lua_register_hooks(apr_pool_t *p)
2096 /* ap_register_output_filter("luahood", luahood, NULL, AP_FTYPE_RESOURCE); */
2097 ap_hook_handler(lua_handler, NULL, NULL, APR_HOOK_MIDDLE);
2098 ap_hook_create_request(create_request_config, NULL, NULL,
2101 /* http_request.h hooks */
2102 ap_hook_translate_name(lua_translate_name_harness_first, NULL, NULL,
2104 ap_hook_translate_name(lua_translate_name_harness, NULL, NULL,
2106 ap_hook_translate_name(lua_translate_name_harness_last, NULL, NULL,
2109 ap_hook_fixups(lua_fixup_harness, NULL, NULL, APR_HOOK_MIDDLE);
2110 ap_hook_map_to_storage(lua_map_to_storage_harness, NULL, NULL,
2113 /* XXX: Does not work :(
2114 * ap_hook_check_user_id(lua_check_user_id_harness_first, NULL, NULL,
2117 ap_hook_check_user_id(lua_check_user_id_harness, NULL, NULL,
2119 /* XXX: Does not work :(
2120 * ap_hook_check_user_id(lua_check_user_id_harness_last, NULL, NULL,
2123 ap_hook_type_checker(lua_type_checker_harness, NULL, NULL,
2126 ap_hook_access_checker(lua_access_checker_harness_first, NULL, NULL,
2128 ap_hook_access_checker(lua_access_checker_harness, NULL, NULL,
2130 ap_hook_access_checker(lua_access_checker_harness_last, NULL, NULL,
2132 ap_hook_auth_checker(lua_auth_checker_harness_first, NULL, NULL,
2134 ap_hook_auth_checker(lua_auth_checker_harness, NULL, NULL,
2136 ap_hook_auth_checker(lua_auth_checker_harness_last, NULL, NULL,
2139 ap_hook_insert_filter(lua_insert_filter_harness, NULL, NULL,
2141 ap_hook_quick_handler(lua_quick_harness, NULL, NULL, APR_HOOK_FIRST);
2143 ap_hook_post_config(lua_post_config, NULL, NULL, APR_HOOK_MIDDLE);
2144 ap_hook_pre_config(lua_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
2146 APR_OPTIONAL_HOOK(ap_lua, lua_open, lua_open_hook, NULL, NULL,
2147 APR_HOOK_REALLY_FIRST);
2149 APR_OPTIONAL_HOOK(ap_lua, lua_request, lua_request_hook, NULL, NULL,
2150 APR_HOOK_REALLY_FIRST);
2151 ap_hook_handler(lua_map_handler, NULL, NULL, AP_LUA_HOOK_FIRST);
2153 /* Hook this right before FallbackResource kicks in */
2154 ap_hook_fixups(lua_map_handler_fixups, NULL, NULL, AP_LUA_HOOK_LAST-2);
2156 ap_hook_child_init(ap_lua_init_mutex, NULL, NULL, APR_HOOK_MIDDLE);
2159 lua_authz_providers = apr_hash_make(p);
2161 /* Logging catcher */
2162 ap_hook_log_transaction(lua_log_transaction_harness,NULL,NULL,
2166 AP_DECLARE_MODULE(lua) = {
2167 STANDARD20_MODULE_STUFF,
2168 create_dir_config, /* create per-dir config structures */
2169 merge_dir_config, /* merge per-dir config structures */
2170 create_server_config, /* create per-server config structures */
2171 NULL, /* merge per-server config structures */
2172 lua_commands, /* table of config file commands */
2173 lua_register_hooks /* register hooks */