]> granicus.if.org Git - apache/blob - modules/lua/mod_lua.c
mod_lua: Add a lot of core httpd/apr functionality to mod_lua
[apache] / modules / lua / mod_lua.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
18 #include "mod_lua.h"
19 #include <string.h>
20 #include <stdlib.h>
21 #include <ctype.h>
22
23 #include "lua_apr.h"
24 #include "lua_config.h"
25 #include "apr_optional.h"
26 #include "mod_ssl.h"
27 #include "mod_auth.h"
28
29 #ifdef APR_HAS_THREADS
30 #include "apr_thread_proc.h"
31 #endif
32
33 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap_lua, AP_LUA, int, lua_open,
34                                     (lua_State *L, apr_pool_t *p),
35                                     (L, p), OK, DECLINED)
36
37 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap_lua, AP_LUA, int, lua_request,
38                                     (lua_State *L, request_rec *r),
39                                     (L, r), OK, DECLINED)
40 static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *lua_ssl_val = NULL;
41 static APR_OPTIONAL_FN_TYPE(ssl_is_https) *lua_ssl_is_https = NULL;
42
43 module AP_MODULE_DECLARE_DATA lua_module;
44
45 #define AP_LUA_HOOK_FIRST (APR_HOOK_FIRST - 1)
46 #define AP_LUA_HOOK_LAST  (APR_HOOK_LAST  + 1)
47
48 typedef struct {
49     const char *name;
50     const char *file_name;
51     const char *function_name;
52     ap_lua_vm_spec *spec;
53     apr_array_header_t *args;
54 } lua_authz_provider_spec;
55
56 apr_hash_t *lua_authz_providers;
57
58 typedef struct
59 {
60     apr_bucket_brigade *tmpBucket;
61     lua_State *L;
62     ap_lua_vm_spec *spec;
63     int broken;
64 } lua_filter_ctx;
65
66
67 /**
68  * error reporting if lua has an error.
69  * Extracts the error from lua stack and prints
70  */
71 static void report_lua_error(lua_State *L, request_rec *r)
72 {
73     const char *lua_response;
74     r->status = HTTP_INTERNAL_SERVER_ERROR;
75     r->content_type = "text/html";
76     ap_rputs("<b>Error!</b>\n", r);
77     ap_rputs("<p>", r);
78     lua_response = lua_tostring(L, -1);
79     ap_rputs(lua_response, r);
80     ap_rputs("</p>\n", r);
81
82     ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, r->pool, APLOGNO(01471) "Lua error: %s",
83                   lua_response);
84 }
85
86 static void lua_open_callback(lua_State *L, apr_pool_t *p, void *ctx)
87 {
88     ap_lua_init(L, p);
89     ap_lua_load_apache2_lmodule(L);
90     ap_lua_load_request_lmodule(L, p);
91     ap_lua_load_httpd_functions(L);
92     ap_lua_load_config_lmodule(L);
93 }
94
95 static int lua_open_hook(lua_State *L, apr_pool_t *p)
96 {
97     lua_open_callback(L, p, NULL);
98     return OK;
99 }
100
101 static const char *scope_to_string(unsigned int scope)
102 {
103     switch (scope) {
104     case AP_LUA_SCOPE_ONCE:
105     case AP_LUA_SCOPE_UNSET:
106         return "once";
107     case AP_LUA_SCOPE_REQUEST:
108         return "request";
109     case AP_LUA_SCOPE_CONN:
110         return "conn";
111 #if APR_HAS_THREADS
112     case AP_LUA_SCOPE_THREAD:
113         return "thread";
114     case AP_LUA_SCOPE_SERVER:
115         return "server";
116 #endif
117     default:
118         ap_assert(0);
119     }
120 }
121
122 static void ap_lua_release_state(lua_State* L, ap_lua_vm_spec* spec, request_rec* r) {
123     char *hash;
124     apr_reslist_t* reslist = NULL;
125     if (spec->scope == AP_LUA_SCOPE_SERVER) {
126         ap_lua_server_spec* sspec = NULL;
127         lua_settop(L, 0);
128         lua_getfield(L, LUA_REGISTRYINDEX, "Apache2.Lua.server_spec");
129         sspec = (ap_lua_server_spec*) lua_touserdata(L, 1);
130         hash = apr_psprintf(r->pool, "reslist:%s", spec->file);
131         if (apr_pool_userdata_get((void **)&reslist, hash,
132                                 r->server->process->pool) == APR_SUCCESS) {
133             AP_DEBUG_ASSERT(sspec != NULL);
134             if (reslist != NULL) {
135                 apr_reslist_release(reslist, sspec);
136             }
137         }
138     }
139 }
140
141 static ap_lua_vm_spec *create_vm_spec(apr_pool_t **lifecycle_pool,
142                                       request_rec *r,
143                                       const ap_lua_dir_cfg *cfg,
144                                       const ap_lua_server_cfg *server_cfg,
145                                       const char *filename,
146                                       const char *bytecode,
147                                       apr_size_t bytecode_len,
148                                       const char *function,
149                                       const char *what)
150 {
151     apr_pool_t *pool;
152     ap_lua_vm_spec *spec = apr_pcalloc(r->pool, sizeof(ap_lua_vm_spec));
153
154     spec->scope = cfg->vm_scope;
155     spec->pool = r->pool;
156     spec->package_paths = cfg->package_paths;
157     spec->package_cpaths = cfg->package_cpaths;
158     spec->cb = &lua_open_callback;
159     spec->cb_arg = NULL;
160     spec->bytecode = bytecode;
161     spec->bytecode_len = bytecode_len;
162     spec->codecache = (cfg->codecache == AP_LUA_CACHE_UNSET) ? AP_LUA_CACHE_STAT : cfg->codecache;
163     spec->vm_min = cfg->vm_min ? cfg->vm_min : 1;
164     spec->vm_max = cfg->vm_max ? cfg->vm_max : 1;
165     
166     if (filename) {
167         char *file;
168         apr_filepath_merge(&file, server_cfg->root_path,
169                            filename, APR_FILEPATH_NOTRELATIVE, r->pool);
170         spec->file = file;
171     }
172     else {
173         spec->file = r->filename;
174     }
175     ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, APLOGNO(02313)
176                   "%s details: scope: %s, file: %s, func: %s",
177                   what, scope_to_string(spec->scope), spec->file,
178                   function ? function : "-");
179
180     switch (spec->scope) {
181     case AP_LUA_SCOPE_ONCE:
182     case AP_LUA_SCOPE_UNSET:
183         apr_pool_create(&pool, r->pool);
184         break;
185     case AP_LUA_SCOPE_REQUEST:
186         pool = r->pool;
187         break;
188     case AP_LUA_SCOPE_CONN:
189         pool = r->connection->pool;
190         break;
191 #if APR_HAS_THREADS
192     case AP_LUA_SCOPE_THREAD:
193         pool = apr_thread_pool_get(r->connection->current_thread);
194         break;
195     case AP_LUA_SCOPE_SERVER:
196         pool = r->server->process->pool;
197         break;
198 #endif
199     default:
200         ap_assert(0);
201     }
202
203     *lifecycle_pool = pool;
204     return spec;
205 }
206
207 static const char* ap_lua_interpolate_string(apr_pool_t* pool, const char* string, const char** values)
208 {
209     char *stringBetween;
210     const char* ret;
211     int srclen,x,y;
212     srclen = strlen(string);
213     ret = "";
214     y = 0;
215     for (x=0; x < srclen; x++) {
216         if (string[x] == '$' && x != srclen-1 && string[x+1] >= '0' && string[x+1] <= '9') {
217             int v = *(string+x+1) - '0';
218             if (x-y > 0) {
219                 stringBetween = apr_pstrndup(pool, string+y, x-y);
220             }
221             else {
222                 stringBetween = "";
223             }
224             ret = apr_pstrcat(pool, ret, stringBetween, values[v], NULL);
225             y = ++x+1;
226         }
227     }
228     
229     if (x-y > 0 && y > 0) {
230         stringBetween = apr_pstrndup(pool, string+y, x-y);
231         ret = apr_pstrcat(pool, ret, stringBetween, NULL);
232     }
233     /* If no replacement was made, just return the original string */
234     else if (y == 0) {
235         return string;
236     }
237     return ret;
238 }
239
240
241
242 /**
243  * "main"
244  */
245 static int lua_handler(request_rec *r)
246 {
247     int rc = OK;
248     if (strcmp(r->handler, "lua-script")) {
249         return DECLINED;
250     }
251     /* Decline the request if the script does not exist (or is a directory),
252      * rather than just returning internal server error */
253     if (
254             (r->finfo.filetype == APR_NOFILE)
255             || (r->finfo.filetype & APR_DIR)
256         ) {
257         return DECLINED;
258     }
259     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(01472)
260                   "handling [%s] in mod_lua", r->filename);
261
262     /* XXX: This seems wrong because it may generate wrong headers for HEAD requests */
263     if (!r->header_only) {
264         lua_State *L;
265         apr_pool_t *pool;
266         const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
267                                                          &lua_module);
268         ap_lua_vm_spec *spec = create_vm_spec(&pool, r, cfg, NULL, NULL, NULL,
269                                               0, "handle", "request handler");
270
271         L = ap_lua_get_lua_state(pool, spec, r);
272         if (!L) {
273             /* TODO annotate spec with failure reason */
274             r->status = HTTP_INTERNAL_SERVER_ERROR;
275             ap_rputs("Unable to compile VM, see logs", r);
276             ap_lua_release_state(L, spec, r);
277             return HTTP_INTERNAL_SERVER_ERROR;
278         }
279         ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, APLOGNO(01474) "got a vm!");
280         lua_getglobal(L, "handle");
281         if (!lua_isfunction(L, -1)) {
282             ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01475)
283                           "lua: Unable to find function %s in %s",
284                           "handle",
285                           spec->file);
286             ap_lua_release_state(L, spec, r);
287             return HTTP_INTERNAL_SERVER_ERROR;
288         }
289         ap_lua_run_lua_request(L, r);
290         if (lua_pcall(L, 1, 1, 0)) {
291             report_lua_error(L, r);
292         }
293         if (lua_isnumber(L, -1)) {
294             rc = lua_tointeger(L, -1);
295         }
296         ap_lua_release_state(L, spec, r);
297     }
298     return rc;
299 }
300
301
302 /* ------------------- Input/output content filters ------------------- */
303
304
305 static apr_status_t lua_setup_filter_ctx(ap_filter_t* f, request_rec* r, lua_filter_ctx** c) {
306     apr_pool_t *pool;
307     ap_lua_vm_spec *spec;
308     int n, rc;
309     lua_State *L;
310     lua_filter_ctx *ctx;    
311     ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
312                                                         &lua_module);
313     const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
314                                                     &lua_module);
315     
316     ctx = apr_pcalloc(r->pool, sizeof(lua_filter_ctx));
317     ctx->broken = 0;
318     *c = ctx;
319     /* Find the filter that was called */
320     for (n = 0; n < cfg->mapped_filters->nelts; n++) {
321         ap_lua_filter_handler_spec *hook_spec =
322             ((ap_lua_filter_handler_spec **) cfg->mapped_filters->elts)[n];
323
324         if (hook_spec == NULL) {
325             continue;
326         }
327         if (!strcasecmp(hook_spec->filter_name, f->frec->name)) {
328             spec = create_vm_spec(&pool, r, cfg, server_cfg,
329                                     hook_spec->file_name,
330                                     NULL,
331                                     0,
332                                     hook_spec->function_name,
333                                     "filter");
334             L = ap_lua_get_lua_state(pool, spec, r);
335             if (L) {
336                 L = lua_newthread(L);
337             }
338
339             if (!L) {
340                 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02328)
341                                 "lua: Failed to obtain lua interpreter for %s %s",
342                                 hook_spec->function_name, hook_spec->file_name);
343                 ap_lua_release_state(L, spec, r);
344                 return APR_EGENERAL;
345             }
346             if (hook_spec->function_name != NULL) {
347                 lua_getglobal(L, hook_spec->function_name);
348                 if (!lua_isfunction(L, -1)) {
349                     ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02329)
350                                     "lua: Unable to find function %s in %s",
351                                     hook_spec->function_name,
352                                     hook_spec->file_name);
353                     ap_lua_release_state(L, spec, r);
354                     return APR_EGENERAL;
355                 }
356
357                 ap_lua_run_lua_request(L, r);
358             }
359             else {
360                 int t;
361                 ap_lua_run_lua_request(L, r);
362
363                 t = lua_gettop(L);
364                 lua_setglobal(L, "r");
365                 lua_settop(L, t);
366             }
367             ctx->L = L;
368             ctx->spec = spec;
369             
370             /* If a Lua filter is interested in filtering a request, it must first do a yield, 
371              * otherwise we'll assume that it's not interested and pretend we didn't find it.
372              */
373             rc = lua_resume(L, 1);
374             if (rc == LUA_YIELD) {
375                 return OK;
376             }
377             else {
378                 ap_lua_release_state(L, spec, r);
379                 return APR_ENOENT;
380             }
381         }
382     }
383     return APR_ENOENT;
384 }
385
386 static apr_status_t lua_output_filter_handle(ap_filter_t *f, apr_bucket_brigade *pbbIn) {
387     request_rec *r = f->r;
388     int rc;
389     lua_State *L;
390     lua_filter_ctx* ctx;
391     conn_rec *c = r->connection;
392     apr_bucket *pbktIn;
393     apr_status_t rv;
394     
395     /* Set up the initial filter context and acquire the function.
396      * The corresponding Lua function should yield here.
397      */
398     if (!f->ctx) {
399         rc = lua_setup_filter_ctx(f,r,&ctx);
400         if (rc == APR_EGENERAL) {
401             return HTTP_INTERNAL_SERVER_ERROR;
402         }
403         if (rc == APR_ENOENT) {
404             /* No filter entry found (or the script declined to filter), just pass on the buckets */
405             ap_remove_output_filter(f);
406             return ap_pass_brigade(f->next,pbbIn);
407         }
408         f->ctx = ctx;
409         ctx->tmpBucket = apr_brigade_create(r->pool, c->bucket_alloc);
410     }
411     ctx = (lua_filter_ctx*) f->ctx;
412     L = ctx->L;
413     /* While the Lua function is still yielding, pass in buckets to the coroutine */
414     if (!ctx->broken) {
415         for (pbktIn = APR_BRIGADE_FIRST(pbbIn);
416             pbktIn != APR_BRIGADE_SENTINEL(pbbIn);
417             pbktIn = APR_BUCKET_NEXT(pbktIn))
418             {
419             const char *data;
420             apr_size_t len;
421             apr_bucket *pbktOut;
422
423             /* read the bucket */
424             apr_bucket_read(pbktIn,&data,&len,APR_BLOCK_READ);
425
426             /* Push the bucket onto the Lua stack as a global var */
427             lua_pushlstring(L, data, len);
428             lua_setglobal(L, "bucket");
429             
430             /* If Lua yielded, it means we have something to pass on */
431             if (lua_resume(L, 0) == LUA_YIELD) {
432                 size_t olen;
433                 const char* output = lua_tolstring(L, 1, &olen);
434                 pbktOut = apr_bucket_heap_create(output, olen, NULL,
435                                         c->bucket_alloc);
436                 APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut);
437                 rv = ap_pass_brigade(f->next, ctx->tmpBucket);
438                 apr_brigade_cleanup(ctx->tmpBucket);
439                 if (rv != APR_SUCCESS) {
440                     return rv;
441                 }
442             }
443             else {
444                 ctx->broken = 1;
445                 ap_lua_release_state(L, ctx->spec, r);
446                 ap_remove_output_filter(f);
447                 apr_brigade_cleanup(pbbIn);
448                 apr_brigade_cleanup(ctx->tmpBucket);
449                 return HTTP_INTERNAL_SERVER_ERROR;
450             }
451         }
452         /* If we've safely reached the end, do a final call to Lua to allow for any 
453         finishing moves by the script, such as appending a tail. */
454         if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(pbbIn))) {
455             apr_bucket *pbktEOS;
456             lua_pushnil(L);
457             lua_setglobal(L, "bucket");
458             if (lua_resume(L, 0) == LUA_YIELD) {
459                 apr_bucket *pbktOut;
460                 size_t olen;
461                 const char* output = lua_tolstring(L, 1, &olen);
462                 pbktOut = apr_bucket_heap_create(output, olen, NULL,
463                                         c->bucket_alloc);
464                 APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut);
465             }
466             pbktEOS = apr_bucket_eos_create(c->bucket_alloc);
467             APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktEOS);
468             ap_lua_release_state(L, ctx->spec, r);
469             rv = ap_pass_brigade(f->next, ctx->tmpBucket);
470             apr_brigade_cleanup(ctx->tmpBucket);
471             if (rv != APR_SUCCESS) {
472                 return rv;
473             }
474         }
475     }
476     /* Clean up */
477     apr_brigade_cleanup(pbbIn);
478     return APR_SUCCESS;    
479 }
480
481
482
483 static apr_status_t lua_input_filter_handle(ap_filter_t *f,
484                                        apr_bucket_brigade *pbbOut,
485                                        ap_input_mode_t eMode,
486                                        apr_read_type_e eBlock,
487                                        apr_off_t nBytes) 
488 {
489     request_rec *r = f->r;
490     int rc, lastCall = 0;
491     lua_State *L;
492     lua_filter_ctx* ctx;
493     conn_rec *c = r->connection;
494     apr_status_t ret;
495     
496     /* Set up the initial filter context and acquire the function.
497      * The corresponding Lua function should yield here.
498      */
499     if (!f->ctx) {
500         rc = lua_setup_filter_ctx(f,r,&ctx);
501         f->ctx = ctx;
502         if (rc == APR_EGENERAL) {
503             ctx->broken = 1;
504             ap_remove_input_filter(f); 
505             return HTTP_INTERNAL_SERVER_ERROR;
506         }
507         if (rc == APR_ENOENT ) {
508             ap_remove_input_filter(f);
509             ctx->broken = 1;
510         }
511         if (rc == APR_SUCCESS) {
512             ctx->tmpBucket = apr_brigade_create(r->pool, c->bucket_alloc);
513         }
514     }
515     ctx = (lua_filter_ctx*) f->ctx;
516     L = ctx->L;
517     /* If the Lua script broke or denied serving the request, just pass the buckets through */
518     if (ctx->broken) {
519         return ap_get_brigade(f->next, pbbOut, eMode, eBlock, nBytes);
520     }
521     
522     if (APR_BRIGADE_EMPTY(ctx->tmpBucket)) {
523         ret = ap_get_brigade(f->next, ctx->tmpBucket, eMode, eBlock, nBytes);
524         if (eMode == AP_MODE_EATCRLF || ret != APR_SUCCESS)
525             return ret;
526     }
527     
528     /* While the Lua function is still yielding, pass buckets to the coroutine */
529     if (!ctx->broken) {
530         lastCall = 0;
531         while(!APR_BRIGADE_EMPTY(ctx->tmpBucket)) {
532             apr_bucket *pbktIn = APR_BRIGADE_FIRST(ctx->tmpBucket);
533             apr_bucket *pbktOut;
534             const char *data;
535             apr_size_t len;
536             
537             if (APR_BUCKET_IS_EOS(pbktIn)) {
538                 APR_BUCKET_REMOVE(pbktIn);
539                 break;
540             }
541
542             /* read the bucket */
543             ret = apr_bucket_read(pbktIn, &data, &len, eBlock);
544             if (ret != APR_SUCCESS)
545                 return ret;
546
547             /* Push the bucket onto the Lua stack as a global var */
548             lastCall++;
549             lua_pushlstring(L, data, len);
550             lua_setglobal(L, "bucket");
551             
552             /* If Lua yielded, it means we have something to pass on */
553             if (lua_resume(L, 0) == LUA_YIELD) {
554                 size_t olen;
555                 const char* output = lua_tolstring(L, 1, &olen);
556                 pbktOut = apr_bucket_heap_create(output, olen, 0, c->bucket_alloc);
557                 APR_BRIGADE_INSERT_TAIL(pbbOut, pbktOut);
558                 apr_bucket_delete(pbktIn);
559                 return APR_SUCCESS;
560             }
561             else {
562                 ctx->broken = 1;
563                 ap_lua_release_state(L, ctx->spec, r);
564                 ap_remove_input_filter(f); 
565                 apr_bucket_delete(pbktIn);
566                 return HTTP_INTERNAL_SERVER_ERROR;
567             }
568         }
569         /* If we've safely reached the end, do a final call to Lua to allow for any 
570         finishing moves by the script, such as appending a tail. */
571         if (lastCall == 0) {
572             apr_bucket *pbktEOS = apr_bucket_eos_create(c->bucket_alloc);
573             lua_pushnil(L);
574             lua_setglobal(L, "bucket");
575             if (lua_resume(L, 0) == LUA_YIELD) {
576                 apr_bucket *pbktOut;
577                 size_t olen;
578                 const char* output = lua_tolstring(L, 1, &olen);
579                 pbktOut = apr_bucket_heap_create(output, olen, 0, c->bucket_alloc);
580                 APR_BRIGADE_INSERT_TAIL(pbbOut, pbktOut);
581             }
582             APR_BRIGADE_INSERT_TAIL(pbbOut,pbktEOS);
583             ap_lua_release_state(L, ctx->spec, r);
584         }
585     }
586     return APR_SUCCESS;
587 }
588
589
590 /* ---------------- Configury stuff --------------- */
591
592 /** harnesses for magic hooks **/
593
594 static int lua_request_rec_hook_harness(request_rec *r, const char *name, int apr_hook_when)
595 {
596     int rc;
597     apr_pool_t *pool;
598     lua_State *L;
599     ap_lua_vm_spec *spec;
600     ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
601                                                          &lua_module);
602     const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
603                                                      &lua_module);
604     const char *key = apr_psprintf(r->pool, "%s_%d", name, apr_hook_when);
605     apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
606                                                   APR_HASH_KEY_STRING);
607     if (hook_specs) {
608         int i;
609         for (i = 0; i < hook_specs->nelts; i++) {
610             ap_lua_mapped_handler_spec *hook_spec =
611                 ((ap_lua_mapped_handler_spec **) hook_specs->elts)[i];
612
613             if (hook_spec == NULL) {
614                 continue;
615             }
616             spec = create_vm_spec(&pool, r, cfg, server_cfg,
617                                   hook_spec->file_name,
618                                   hook_spec->bytecode,
619                                   hook_spec->bytecode_len,
620                                   hook_spec->function_name,
621                                   "request hook");
622
623             L = ap_lua_get_lua_state(pool, spec, r);
624
625             if (!L) {
626                 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01477)
627                               "lua: Failed to obtain lua interpreter for %s %s",
628                               hook_spec->function_name, hook_spec->file_name);
629                 return HTTP_INTERNAL_SERVER_ERROR;
630             }
631
632             if (hook_spec->function_name != NULL) {
633                 lua_getglobal(L, hook_spec->function_name);
634                 if (!lua_isfunction(L, -1)) {
635                     ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01478)
636                                   "lua: Unable to find function %s in %s",
637                                   hook_spec->function_name,
638                                   hook_spec->file_name);
639                     ap_lua_release_state(L, spec, r);
640                     return HTTP_INTERNAL_SERVER_ERROR;
641                 }
642
643                 ap_lua_run_lua_request(L, r);
644             }
645             else {
646                 int t;
647                 ap_lua_run_lua_request(L, r);
648
649                 t = lua_gettop(L);
650                 lua_setglobal(L, "r");
651                 lua_settop(L, t);
652             }
653
654             if (lua_pcall(L, 1, 1, 0)) {
655                 report_lua_error(L, r);
656                 ap_lua_release_state(L, spec, r);
657                 return HTTP_INTERNAL_SERVER_ERROR;
658             }
659             rc = DECLINED;
660             if (lua_isnumber(L, -1)) {
661                 rc = lua_tointeger(L, -1);
662             }
663             if (rc != DECLINED) {
664                 ap_lua_release_state(L, spec, r);
665                 return rc;
666             }
667             ap_lua_release_state(L, spec, r);
668         }
669     }
670     return DECLINED;
671 }
672
673
674 static int lua_map_handler(request_rec *r)
675 {
676     int rc, n = 0;
677     apr_pool_t *pool;
678     lua_State *L;
679     const char *filename, *function_name;
680     const char *values[10];
681     ap_lua_vm_spec *spec;
682     ap_regmatch_t match[10];
683     ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
684                                                          &lua_module);
685     const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
686                                                      &lua_module);
687     for (n = 0; n < cfg->mapped_handlers->nelts; n++) {
688         ap_lua_mapped_handler_spec *hook_spec =
689             ((ap_lua_mapped_handler_spec **) cfg->mapped_handlers->elts)[n];
690
691         if (hook_spec == NULL) {
692             continue;
693         }
694         if (!ap_regexec(hook_spec->uri_pattern, r->uri, 10, match, 0)) {
695             int i;
696             for (i=0 ; i < 10; i++) {
697                 if (match[i].rm_eo >= 0) {
698                     values[i] = apr_pstrndup(r->pool, r->uri+match[i].rm_so, match[i].rm_eo - match[i].rm_so);
699                 }
700                 else values[i] = "";
701             }
702             filename = ap_lua_interpolate_string(r->pool, hook_spec->file_name, values);
703             function_name = ap_lua_interpolate_string(r->pool, hook_spec->function_name, values);
704             spec = create_vm_spec(&pool, r, cfg, server_cfg,
705                                     filename,
706                                     hook_spec->bytecode,
707                                     hook_spec->bytecode_len,
708                                     function_name,
709                                     "mapped handler");
710             L = ap_lua_get_lua_state(pool, spec, r);
711
712             if (!L) {
713                 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02330)
714                                 "lua: Failed to obtain lua interpreter for %s %s",
715                                 function_name, filename);
716                 ap_lua_release_state(L, spec, r);
717                 return HTTP_INTERNAL_SERVER_ERROR;
718             }
719
720             if (function_name != NULL) {
721                 lua_getglobal(L, function_name);
722                 if (!lua_isfunction(L, -1)) {
723                     ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02331)
724                                     "lua: Unable to find function %s in %s",
725                                     function_name,
726                                     filename);
727                     ap_lua_release_state(L, spec, r);
728                     return HTTP_INTERNAL_SERVER_ERROR;
729                 }
730
731                 ap_lua_run_lua_request(L, r);
732             }
733             else {
734                 int t;
735                 ap_lua_run_lua_request(L, r);
736
737                 t = lua_gettop(L);
738                 lua_setglobal(L, "r");
739                 lua_settop(L, t);
740             }
741
742             if (lua_pcall(L, 1, 1, 0)) {
743                 report_lua_error(L, r);
744                 ap_lua_release_state(L, spec, r);
745                 return HTTP_INTERNAL_SERVER_ERROR;
746             }
747             rc = DECLINED;
748             if (lua_isnumber(L, -1)) {
749                 rc = lua_tointeger(L, -1);
750             }
751             if (rc != DECLINED) {
752                 ap_lua_release_state(L, spec, r);
753                 return rc;
754             }
755             ap_lua_release_state(L, spec, r);
756         }
757     }
758     return DECLINED;
759 }
760
761
762 static apr_size_t config_getstr(ap_configfile_t *cfg, char *buf,
763                                 size_t bufsiz)
764 {
765     apr_size_t i = 0;
766
767     if (cfg->getstr) {
768         apr_status_t rc = (cfg->getstr) (buf, bufsiz, cfg->param);
769         if (rc == APR_SUCCESS) {
770             i = strlen(buf);
771             if (i && buf[i - 1] == '\n')
772                 ++cfg->line_number;
773         }
774         else {
775             buf[0] = '\0';
776             i = 0;
777         }
778     }
779     else {
780         while (i < bufsiz) {
781             char ch;
782             apr_status_t rc = (cfg->getch) (&ch, cfg->param);
783             if (rc != APR_SUCCESS)
784                 break;
785             buf[i++] = ch;
786             if (ch == '\n') {
787                 ++cfg->line_number;
788                 break;
789             }
790         }
791     }
792     return i;
793 }
794
795 typedef struct cr_ctx
796 {
797     cmd_parms *cmd;
798     ap_configfile_t *cfp;
799     size_t startline;
800     const char *endstr;
801     char buf[HUGE_STRING_LEN];
802 } cr_ctx;
803
804
805 /* Okay, this deserves a little explaination -- in order for the errors that lua
806  * generates to be 'accuarate', including line numbers, we basically inject
807  * N line number new lines into the 'top' of the chunk reader.....
808  *
809  * be happy. this is cool.
810  *
811  */
812 static const char *lf =
813     "\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";
814 #define N_LF 32
815
816 static const char *direct_chunkreader(lua_State *lvm, void *udata,
817                                       size_t *plen)
818 {
819     const char *p;
820     struct cr_ctx *ctx = udata;
821
822     if (ctx->startline) {
823         *plen = ctx->startline > N_LF ? N_LF : ctx->startline;
824         ctx->startline -= *plen;
825         return lf;
826     }
827     *plen = config_getstr(ctx->cfp, ctx->buf, HUGE_STRING_LEN);
828
829     for (p = ctx->buf; isspace(*p); ++p);
830     if (p[0] == '<' && p[1] == '/') {
831         apr_size_t i = 0;
832         while (i < strlen(ctx->endstr)) {
833             if (tolower(p[i + 2]) != ctx->endstr[i])
834                 return ctx->buf;
835             ++i;
836         }
837         *plen = 0;
838         return NULL;
839     }
840     /*fprintf(stderr, "buf read: %s\n", ctx->buf); */
841     return ctx->buf;
842 }
843
844 static int ldump_writer(lua_State *L, const void *b, size_t size, void *B)
845 {
846     (void) L;
847     luaL_addlstring((luaL_Buffer *) B, (const char *) b, size);
848     return 0;
849 }
850
851 typedef struct hack_section_baton
852 {
853     const char *name;
854     ap_lua_mapped_handler_spec *spec;
855     int apr_hook_when;
856 } hack_section_baton;
857
858 /* You can be unhappy now.
859  *
860  * This is uncool.
861  *
862  * When you create a <Section handler in httpd, the only 'easy' way to create
863  * a directory context is to parse the section, and convert it into a 'normal'
864  * Configureation option, and then collapse the entire section, in memory,
865  * back into the parent section -- from which you can then get the new directive
866  * invoked.... anyways. evil. Rici taught me how to do this hack :-)
867  */
868 static const char *hack_section_handler(cmd_parms *cmd, void *_cfg,
869                                         const char *arg)
870 {
871     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
872     ap_directive_t *directive = cmd->directive;
873     hack_section_baton *baton = directive->data;
874     const char *key = apr_psprintf(cmd->pool, "%s_%d", baton->name, baton->apr_hook_when);
875
876     apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
877                                                   APR_HASH_KEY_STRING);
878     if (!hook_specs) {
879         hook_specs = apr_array_make(cmd->pool, 2,
880                                     sizeof(ap_lua_mapped_handler_spec *));
881         apr_hash_set(cfg->hooks, key,
882                      APR_HASH_KEY_STRING, hook_specs);
883     }
884
885     baton->spec->scope = cfg->vm_scope;
886
887     *(ap_lua_mapped_handler_spec **) apr_array_push(hook_specs) = baton->spec;
888
889     return NULL;
890 }
891
892 static const char *register_named_block_function_hook(const char *name,
893                                                       cmd_parms *cmd,
894                                                       void *mconfig,
895                                                       const char *line)
896 {
897     const char *function = NULL;
898     ap_lua_mapped_handler_spec *spec;
899     int when = APR_HOOK_MIDDLE;
900     const char *endp = ap_strrchr_c(line, '>');
901
902     if (endp == NULL) {
903         return apr_pstrcat(cmd->pool, cmd->cmd->name,
904                            "> directive missing closing '>'", NULL);
905     }
906
907     line = apr_pstrndup(cmd->temp_pool, line, endp - line);
908
909     if (line[0]) { 
910         const char *word;
911         word = ap_getword_conf(cmd->temp_pool, &line);
912         if (word && *word) {
913             function = apr_pstrdup(cmd->pool, word);
914         }
915         word = ap_getword_conf(cmd->temp_pool, &line);
916         if (word && *word) {
917             if (!strcasecmp("early", word)) { 
918                 when = AP_LUA_HOOK_FIRST;
919             }
920             else if (!strcasecmp("late", word)) {
921                 when = AP_LUA_HOOK_LAST;
922             }
923             else { 
924                 return apr_pstrcat(cmd->pool, cmd->cmd->name,
925                                    "> 2nd argument must be 'early' or 'late'", NULL);
926             }
927         }
928     }
929
930     spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec));
931
932     {
933         cr_ctx ctx;
934         lua_State *lvm;
935         char *tmp;
936         int rv;
937         ap_directive_t **current;
938         hack_section_baton *baton;
939
940         spec->file_name = apr_psprintf(cmd->pool, "%s:%u",
941                                        cmd->config_file->name,
942                                        cmd->config_file->line_number);
943         if (function) {
944             spec->function_name = (char *) function;
945         }
946         else {
947             function = NULL;
948         }
949
950         ctx.cmd = cmd;
951         tmp = apr_pstrdup(cmd->pool, cmd->err_directive->directive + 1);
952         ap_str_tolower(tmp);
953         ctx.endstr = tmp;
954         ctx.cfp = cmd->config_file;
955         ctx.startline = cmd->config_file->line_number;
956
957         /* This lua State is used only to compile the input strings -> bytecode, so we don't need anything extra. */
958         lvm = luaL_newstate();
959
960         lua_settop(lvm, 0);
961
962         rv = lua_load(lvm, direct_chunkreader, &ctx, spec->file_name);
963
964         if (rv != 0) {
965             const char *errstr = apr_pstrcat(cmd->pool, "Lua Error:",
966                                              lua_tostring(lvm, -1), NULL);
967             lua_close(lvm);
968             return errstr;
969         }
970         else {
971             luaL_Buffer b;
972             luaL_buffinit(lvm, &b);
973             lua_dump(lvm, ldump_writer, &b);
974             luaL_pushresult(&b);
975             spec->bytecode_len = lua_strlen(lvm, -1);
976             spec->bytecode = apr_pstrmemdup(cmd->pool, lua_tostring(lvm, -1),
977                                             spec->bytecode_len);
978             lua_close(lvm);
979         }
980
981         current = mconfig;
982
983         /* Here, we have to replace our current config node for the next pass */
984         if (!*current) {
985             *current = apr_pcalloc(cmd->pool, sizeof(**current));
986         }
987
988         baton = apr_pcalloc(cmd->pool, sizeof(hack_section_baton));
989         baton->name = name;
990         baton->spec = spec;
991         baton->apr_hook_when = when;
992
993         (*current)->filename = cmd->config_file->name;
994         (*current)->line_num = cmd->config_file->line_number;
995         (*current)->directive = apr_pstrdup(cmd->pool, "Lua_____ByteCodeHack");
996         (*current)->args = NULL;
997         (*current)->data = baton;
998     }
999
1000     return NULL;
1001 }
1002
1003 static const char *register_named_file_function_hook(const char *name,
1004                                                      cmd_parms *cmd,
1005                                                      void *_cfg,
1006                                                      const char *file,
1007                                                      const char *function,
1008                                                      int apr_hook_when)
1009 {
1010     ap_lua_mapped_handler_spec *spec;
1011     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1012     const char *key = apr_psprintf(cmd->pool, "%s_%d", name, apr_hook_when);
1013     apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
1014                                                   APR_HASH_KEY_STRING);
1015
1016     if (!hook_specs) {
1017         hook_specs = apr_array_make(cmd->pool, 2,
1018                                     sizeof(ap_lua_mapped_handler_spec *));
1019         apr_hash_set(cfg->hooks, key, APR_HASH_KEY_STRING, hook_specs);
1020     }
1021
1022     spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec));
1023     spec->file_name = apr_pstrdup(cmd->pool, file);
1024     spec->function_name = apr_pstrdup(cmd->pool, function);
1025     spec->scope = cfg->vm_scope;
1026
1027     *(ap_lua_mapped_handler_spec **) apr_array_push(hook_specs) = spec;
1028     return NULL;
1029 }
1030 static const char *register_mapped_file_function_hook(const char *pattern,
1031                                                      cmd_parms *cmd,
1032                                                      void *_cfg,
1033                                                      const char *file,
1034                                                      const char *function)
1035 {
1036     ap_lua_mapped_handler_spec *spec;
1037     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1038     ap_regex_t *regex = apr_pcalloc(cmd->pool, sizeof(ap_regex_t));
1039     if (ap_regcomp(regex, pattern,0)) {
1040         return "Invalid regex pattern!";
1041     }
1042
1043     spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec));
1044     spec->file_name = apr_pstrdup(cmd->pool, file);
1045     spec->function_name = apr_pstrdup(cmd->pool, function);
1046     spec->scope = cfg->vm_scope;
1047     spec->uri_pattern = regex;
1048
1049     *(ap_lua_mapped_handler_spec **) apr_array_push(cfg->mapped_handlers) = spec;
1050     return NULL;
1051 }
1052 static const char *register_filter_function_hook(const char *filter,
1053                                                      cmd_parms *cmd,
1054                                                      void *_cfg,
1055                                                      const char *file,
1056                                                      const char *function,
1057                                                      int direction)
1058 {
1059     ap_lua_filter_handler_spec *spec;
1060     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1061    
1062     spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_filter_handler_spec));
1063     spec->file_name = apr_pstrdup(cmd->pool, file);
1064     spec->function_name = apr_pstrdup(cmd->pool, function);
1065     spec->filter_name = filter;
1066
1067     *(ap_lua_filter_handler_spec **) apr_array_push(cfg->mapped_filters) = spec;
1068     /* TODO: Make it work on other types than just AP_FTYPE_RESOURCE? */
1069     if (direction == AP_LUA_FILTER_OUTPUT) {
1070         spec->direction = AP_LUA_FILTER_OUTPUT;
1071         ap_register_output_filter(filter, lua_output_filter_handle, NULL, AP_FTYPE_RESOURCE);
1072     }
1073     else {
1074         spec->direction = AP_LUA_FILTER_INPUT;
1075         ap_register_input_filter(filter, lua_input_filter_handle, NULL, AP_FTYPE_RESOURCE);
1076     }
1077     return NULL;
1078 }
1079 static int lua_check_user_id_harness_first(request_rec *r)
1080 {
1081     return lua_request_rec_hook_harness(r, "check_user_id", AP_LUA_HOOK_FIRST);
1082 }
1083 static int lua_check_user_id_harness(request_rec *r)
1084 {
1085     return lua_request_rec_hook_harness(r, "check_user_id", APR_HOOK_MIDDLE);
1086 }
1087 static int lua_check_user_id_harness_last(request_rec *r)
1088 {
1089     return lua_request_rec_hook_harness(r, "check_user_id", AP_LUA_HOOK_LAST);
1090 }
1091
1092 static int lua_translate_name_harness_first(request_rec *r)
1093 {
1094     return lua_request_rec_hook_harness(r, "translate_name", AP_LUA_HOOK_FIRST);
1095 }
1096 static int lua_translate_name_harness(request_rec *r)
1097 {
1098     return lua_request_rec_hook_harness(r, "translate_name", APR_HOOK_MIDDLE);
1099 }
1100 static int lua_translate_name_harness_last(request_rec *r)
1101 {
1102     return lua_request_rec_hook_harness(r, "translate_name", AP_LUA_HOOK_LAST);
1103 }
1104
1105 static int lua_fixup_harness(request_rec *r)
1106 {
1107     return lua_request_rec_hook_harness(r, "fixups", APR_HOOK_MIDDLE);
1108 }
1109
1110 static int lua_map_to_storage_harness(request_rec *r)
1111 {
1112     return lua_request_rec_hook_harness(r, "map_to_storage", APR_HOOK_MIDDLE);
1113 }
1114
1115 static int lua_type_checker_harness(request_rec *r)
1116 {
1117     return lua_request_rec_hook_harness(r, "type_checker", APR_HOOK_MIDDLE);
1118 }
1119
1120 static int lua_access_checker_harness_first(request_rec *r)
1121 {
1122     return lua_request_rec_hook_harness(r, "access_checker", AP_LUA_HOOK_FIRST);
1123 }
1124 static int lua_access_checker_harness(request_rec *r)
1125 {
1126     return lua_request_rec_hook_harness(r, "access_checker", APR_HOOK_MIDDLE);
1127 }
1128 static int lua_access_checker_harness_last(request_rec *r)
1129 {
1130     return lua_request_rec_hook_harness(r, "access_checker", AP_LUA_HOOK_LAST);
1131 }
1132
1133 static int lua_auth_checker_harness_first(request_rec *r)
1134 {
1135     return lua_request_rec_hook_harness(r, "auth_checker", AP_LUA_HOOK_FIRST);
1136 }
1137 static int lua_auth_checker_harness(request_rec *r)
1138 {
1139     return lua_request_rec_hook_harness(r, "auth_checker", APR_HOOK_MIDDLE);
1140 }
1141 static int lua_auth_checker_harness_last(request_rec *r)
1142 {
1143     return lua_request_rec_hook_harness(r, "auth_checker", AP_LUA_HOOK_LAST);
1144 }
1145 static void lua_insert_filter_harness(request_rec *r)
1146 {
1147     /* ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "LuaHookInsertFilter not yet implemented"); */
1148 }
1149
1150 static int lua_quick_harness(request_rec *r, int lookup)
1151 {
1152     if (lookup) {
1153         return DECLINED;
1154     }
1155     return lua_request_rec_hook_harness(r, "quick", APR_HOOK_MIDDLE);
1156 }
1157
1158 static const char *register_translate_name_hook(cmd_parms *cmd, void *_cfg,
1159                                                 const char *file,
1160                                                 const char *function,
1161                                                 const char *when)
1162 {
1163     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
1164                                            NOT_IN_HTACCESS);
1165     int apr_hook_when = APR_HOOK_MIDDLE;
1166     if (err) {
1167         return err;
1168     }
1169     
1170     if (when) { 
1171         if (!strcasecmp(when, "early")) { 
1172             apr_hook_when = AP_LUA_HOOK_FIRST;
1173         } 
1174         else if (!strcasecmp(when, "late")) { 
1175             apr_hook_when = AP_LUA_HOOK_LAST;
1176         } 
1177         else { 
1178             return "Third argument must be 'early' or 'late'";
1179         }
1180     }
1181
1182     return register_named_file_function_hook("translate_name", cmd, _cfg,
1183                                              file, function, apr_hook_when);
1184 }
1185
1186 static const char *register_translate_name_block(cmd_parms *cmd, void *_cfg,
1187                                                  const char *line)
1188 {
1189     return register_named_block_function_hook("translate_name", cmd, _cfg,
1190                                               line);
1191 }
1192
1193
1194 static const char *register_fixups_hook(cmd_parms *cmd, void *_cfg,
1195                                         const char *file,
1196                                         const char *function)
1197 {
1198     return register_named_file_function_hook("fixups", cmd, _cfg, file,
1199                                              function, APR_HOOK_MIDDLE);
1200 }
1201 static const char *register_fixups_block(cmd_parms *cmd, void *_cfg,
1202                                          const char *line)
1203 {
1204     return register_named_block_function_hook("fixups", cmd, _cfg, line);
1205 }
1206
1207 static const char *register_map_to_storage_hook(cmd_parms *cmd, void *_cfg,
1208                                                 const char *file,
1209                                                 const char *function)
1210 {
1211     return register_named_file_function_hook("map_to_storage", cmd, _cfg,
1212                                              file, function, APR_HOOK_MIDDLE);
1213 }
1214 static const char *register_map_to_storage_block(cmd_parms *cmd, void *_cfg,
1215                                                  const char *line)
1216 {
1217     return register_named_block_function_hook("map_to_storage", cmd, _cfg,
1218                                               line);
1219 }
1220
1221 static const char *register_check_user_id_hook(cmd_parms *cmd, void *_cfg,
1222                                                const char *file,
1223                                                const char *function,
1224                                                const char *when)
1225 {
1226     int apr_hook_when = APR_HOOK_MIDDLE;
1227
1228     if (when) {
1229         if (!strcasecmp(when, "early")) {
1230             apr_hook_when = AP_LUA_HOOK_FIRST;
1231         }
1232         else if (!strcasecmp(when, "late")) {
1233             apr_hook_when = AP_LUA_HOOK_LAST;
1234         }
1235         else {
1236             return "Third argument must be 'early' or 'late'";
1237         }
1238     }
1239
1240     return register_named_file_function_hook("check_user_id", cmd, _cfg, file,
1241                                              function, apr_hook_when);
1242 }
1243 static const char *register_check_user_id_block(cmd_parms *cmd, void *_cfg,
1244                                                 const char *line)
1245 {
1246     return register_named_block_function_hook("check_user_id", cmd, _cfg,
1247                                               line);
1248 }
1249
1250 static const char *register_type_checker_hook(cmd_parms *cmd, void *_cfg,
1251                                               const char *file,
1252                                               const char *function)
1253 {
1254     return register_named_file_function_hook("type_checker", cmd, _cfg, file,
1255                                              function, APR_HOOK_MIDDLE);
1256 }
1257 static const char *register_type_checker_block(cmd_parms *cmd, void *_cfg,
1258                                                const char *line)
1259 {
1260     return register_named_block_function_hook("type_checker", cmd, _cfg,
1261                                               line);
1262 }
1263
1264 static const char *register_access_checker_hook(cmd_parms *cmd, void *_cfg,
1265                                                 const char *file,
1266                                                 const char *function,
1267                                                 const char *when)
1268 {
1269     int apr_hook_when = APR_HOOK_MIDDLE;
1270
1271     if (when) {
1272         if (!strcasecmp(when, "early")) {
1273             apr_hook_when = AP_LUA_HOOK_FIRST;
1274         }
1275         else if (!strcasecmp(when, "late")) {
1276             apr_hook_when = AP_LUA_HOOK_LAST;
1277         }
1278         else {
1279             return "Third argument must be 'early' or 'late'";
1280         }
1281     }
1282
1283     return register_named_file_function_hook("access_checker", cmd, _cfg,
1284                                              file, function, apr_hook_when);
1285 }
1286 static const char *register_access_checker_block(cmd_parms *cmd, void *_cfg,
1287                                                  const char *line)
1288 {
1289
1290     return register_named_block_function_hook("access_checker", cmd, _cfg,
1291                                               line);
1292 }
1293
1294 static const char *register_auth_checker_hook(cmd_parms *cmd, void *_cfg,
1295                                               const char *file,
1296                                               const char *function,
1297                                               const char *when)
1298 {
1299     int apr_hook_when = APR_HOOK_MIDDLE;
1300
1301     if (when) {
1302         if (!strcasecmp(when, "early")) {
1303             apr_hook_when = AP_LUA_HOOK_FIRST;
1304         }
1305         else if (!strcasecmp(when, "late")) {
1306             apr_hook_when = AP_LUA_HOOK_LAST;
1307         }
1308         else {
1309             return "Third argument must be 'early' or 'late'";
1310         }
1311     }
1312
1313     return register_named_file_function_hook("auth_checker", cmd, _cfg, file,
1314                                              function, apr_hook_when);
1315 }
1316 static const char *register_auth_checker_block(cmd_parms *cmd, void *_cfg,
1317                                                const char *line)
1318 {
1319     return register_named_block_function_hook("auth_checker", cmd, _cfg,
1320                                               line);
1321 }
1322
1323 static const char *register_insert_filter_hook(cmd_parms *cmd, void *_cfg,
1324                                                const char *file,
1325                                                const char *function)
1326 {
1327     return "LuaHookInsertFilter not yet implemented";
1328 }
1329
1330 static const char *register_quick_hook(cmd_parms *cmd, void *_cfg,
1331                                        const char *file, const char *function)
1332 {
1333     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
1334                                                 NOT_IN_HTACCESS);
1335     if (err) {
1336         return err;
1337     }
1338     return register_named_file_function_hook("quick", cmd, _cfg, file,
1339                                              function, APR_HOOK_MIDDLE);
1340 }
1341 static const char *register_map_handler(cmd_parms *cmd, void *_cfg,
1342                                        const char* match, const char *file, const char *function)
1343 {
1344     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
1345                                                 NOT_IN_HTACCESS);
1346     if (err) {
1347         return err;
1348     }
1349     if (!function) function = "handle";
1350     return register_mapped_file_function_hook(match, cmd, _cfg, file,
1351                                              function);
1352 }
1353 static const char *register_output_filter(cmd_parms *cmd, void *_cfg,
1354                                        const char* filter, const char *file, const char *function)
1355 {
1356     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
1357                                                 NOT_IN_HTACCESS);
1358     if (err) {
1359         return err;
1360     }
1361     if (!function) function = "handle";
1362     return register_filter_function_hook(filter, cmd, _cfg, file,
1363                                              function, AP_LUA_FILTER_OUTPUT);
1364 }
1365 static const char *register_input_filter(cmd_parms *cmd, void *_cfg,
1366                                        const char* filter, const char *file, const char *function)
1367 {
1368     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
1369                                                 NOT_IN_HTACCESS);
1370     if (err) {
1371         return err;
1372     }
1373     if (!function) function = "handle";
1374     return register_filter_function_hook(filter, cmd, _cfg, file,
1375                                              function, AP_LUA_FILTER_INPUT);
1376 }
1377 static const char *register_quick_block(cmd_parms *cmd, void *_cfg,
1378                                         const char *line)
1379 {
1380     return register_named_block_function_hook("quick", cmd, _cfg,
1381                                               line);
1382 }
1383
1384
1385
1386 static const char *register_package_helper(cmd_parms *cmd, 
1387                                            const char *arg,
1388                                            apr_array_header_t *dir_array)
1389 {
1390     apr_status_t rv;
1391
1392     ap_lua_server_cfg *server_cfg =
1393         ap_get_module_config(cmd->server->module_config, &lua_module);
1394
1395     char *fixed_filename;
1396     rv = apr_filepath_merge(&fixed_filename, 
1397                             server_cfg->root_path, 
1398                             arg,
1399                             APR_FILEPATH_NOTRELATIVE, 
1400                             cmd->pool);
1401
1402     if (rv != APR_SUCCESS) {
1403         return apr_psprintf(cmd->pool,
1404                             "Unable to build full path to file, %s", arg);
1405     }
1406
1407     *(const char **) apr_array_push(dir_array) = fixed_filename;
1408     return NULL;
1409 }
1410
1411
1412 /**
1413  * Called for config directive which looks like
1414  * LuaPackagePath /lua/package/path/mapped/thing/like/this/?.lua
1415  */
1416 static const char *register_package_dir(cmd_parms *cmd, void *_cfg,
1417                                         const char *arg)
1418 {
1419     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1420
1421     return register_package_helper(cmd, arg, cfg->package_paths);
1422 }
1423
1424 /**
1425  * Called for config directive which looks like
1426  * LuaPackageCPath /lua/package/path/mapped/thing/like/this/?.so
1427  */
1428 static const char *register_package_cdir(cmd_parms *cmd, 
1429                                          void *_cfg,
1430                                          const char *arg)
1431 {
1432     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1433
1434     return register_package_helper(cmd, arg, cfg->package_cpaths);
1435 }
1436
1437 static const char *register_lua_inherit(cmd_parms *cmd, 
1438                                       void *_cfg,
1439                                       const char *arg)
1440 {
1441     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1442     
1443     if (strcasecmp("none", arg) == 0) {
1444         cfg->inherit = AP_LUA_INHERIT_NONE;
1445     }
1446     else if (strcasecmp("parent-first", arg) == 0) {
1447         cfg->inherit = AP_LUA_INHERIT_PARENT_FIRST;
1448     }
1449     else if (strcasecmp("parent-last", arg) == 0) {
1450         cfg->inherit = AP_LUA_INHERIT_PARENT_LAST;
1451     }
1452     else { 
1453         return apr_psprintf(cmd->pool,
1454                             "LuaInherit type of '%s' not recognized, valid "
1455                             "options are 'none', 'parent-first', and 'parent-last'", 
1456                             arg);
1457     }
1458     return NULL;
1459 }
1460 static const char *register_lua_codecache(cmd_parms *cmd, 
1461                                       void *_cfg,
1462                                       const char *arg)
1463 {
1464     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1465     
1466     if (strcasecmp("never", arg) == 0) {
1467         cfg->codecache = AP_LUA_CACHE_NEVER;
1468     }
1469     else if (strcasecmp("stat", arg) == 0) {
1470         cfg->codecache = AP_LUA_CACHE_STAT;
1471     }
1472     else if (strcasecmp("forever", arg) == 0) {
1473         cfg->codecache = AP_LUA_CACHE_FOREVER;
1474     }
1475     else { 
1476         return apr_psprintf(cmd->pool,
1477                             "LuaCodeCache type of '%s' not recognized, valid "
1478                             "options are 'never', 'stat', and 'forever'", 
1479                             arg);
1480     }
1481     return NULL;
1482 }
1483 static const char *register_lua_scope(cmd_parms *cmd, 
1484                                       void *_cfg,
1485                                       const char *scope, 
1486                                       const char *min,
1487                                       const char *max)
1488 {
1489     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
1490     if (strcmp("once", scope) == 0) {
1491         cfg->vm_scope = AP_LUA_SCOPE_ONCE;
1492     }
1493     else if (strcmp("request", scope) == 0) {
1494         cfg->vm_scope = AP_LUA_SCOPE_REQUEST;
1495     }
1496     else if (strcmp("conn", scope) == 0) {
1497         cfg->vm_scope = AP_LUA_SCOPE_CONN;
1498     }
1499     else if (strcmp("thread", scope) == 0) {
1500 #if !APR_HAS_THREADS
1501         return apr_psprintf(cmd->pool,
1502                             "Scope type of '%s' cannot be used because this "
1503                             "server does not have threading support "
1504                             "(APR_HAS_THREADS)" 
1505                             scope);
1506 #endif
1507         cfg->vm_scope = AP_LUA_SCOPE_THREAD;
1508     }
1509     else if (strcmp("server", scope) == 0) {
1510         unsigned int vmin, vmax;
1511 #if !APR_HAS_THREADS
1512         return apr_psprintf(cmd->pool,
1513                             "Scope type of '%s' cannot be used because this "
1514                             "server does not have threading support "
1515                             "(APR_HAS_THREADS)" 
1516                             scope);
1517 #endif
1518         cfg->vm_scope = AP_LUA_SCOPE_SERVER;
1519         vmin = min ? atoi(min) : 1;
1520         vmax = max ? atoi(max) : 1;
1521         if (vmin == 0) {
1522             vmin = 1;
1523         }
1524         if (vmax < vmin) {
1525             vmax = vmin;
1526         }
1527         cfg->vm_min = vmin;
1528         cfg->vm_max = vmax;
1529     }
1530     else {
1531         return apr_psprintf(cmd->pool,
1532                             "Invalid value for LuaScope, '%s', acceptable "
1533                             "values are: 'once', 'request', 'conn'"
1534 #if APR_HAS_THREADS
1535                             ", 'thread', 'server'"
1536 #endif
1537                             ,scope);
1538     }
1539
1540     return NULL;
1541 }
1542
1543
1544
1545 static const char *register_lua_root(cmd_parms *cmd, void *_cfg,
1546                                      const char *root)
1547 {
1548     /* ap_lua_dir_cfg* cfg = (ap_lua_dir_cfg*)_cfg; */
1549     ap_lua_server_cfg *cfg = ap_get_module_config(cmd->server->module_config,
1550                                                   &lua_module);
1551
1552     cfg->root_path = root;
1553     return NULL;
1554 }
1555 AP_LUA_DECLARE(const char *) ap_lua_ssl_val(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *var)
1556 {
1557     if (lua_ssl_val) { 
1558         return (const char *)lua_ssl_val(p, s, c, r, (char *)var);
1559     }
1560     return NULL;
1561 }
1562
1563 AP_LUA_DECLARE(int) ap_lua_ssl_is_https(conn_rec *c)
1564 {
1565     return lua_ssl_is_https ? lua_ssl_is_https(c) : 0;
1566 }
1567
1568 /*******************************/
1569
1570 static const char *lua_authz_parse(cmd_parms *cmd, const char *require_line,
1571                                    const void **parsed_require_line)
1572 {
1573     const char *provider_name;
1574     lua_authz_provider_spec *spec;
1575
1576     apr_pool_userdata_get((void**)&provider_name, AUTHZ_PROVIDER_NAME_NOTE,
1577                           cmd->temp_pool);
1578     ap_assert(provider_name != NULL);
1579
1580     spec = apr_hash_get(lua_authz_providers, provider_name, APR_HASH_KEY_STRING);
1581     ap_assert(spec != NULL);
1582
1583     if (require_line && *require_line) {
1584         const char *arg;
1585         spec->args = apr_array_make(cmd->pool, 2, sizeof(const char *));
1586         while ((arg = ap_getword_conf(cmd->pool, &require_line)) && *arg) {
1587             APR_ARRAY_PUSH(spec->args, const char *) = arg;
1588         }
1589     }
1590
1591     *parsed_require_line = spec;
1592     return NULL;
1593 }
1594
1595 static authz_status lua_authz_check(request_rec *r, const char *require_line,
1596                                     const void *parsed_require_line)
1597 {
1598     apr_pool_t *pool;
1599     ap_lua_vm_spec *spec;
1600     lua_State *L;
1601     ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
1602                                                          &lua_module);
1603     const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
1604                                                      &lua_module);
1605     const lua_authz_provider_spec *prov_spec = parsed_require_line;
1606     int result;
1607     int nargs = 0;
1608
1609     spec = create_vm_spec(&pool, r, cfg, server_cfg, prov_spec->file_name,
1610                           NULL, 0, prov_spec->function_name, "authz provider");
1611
1612     L = ap_lua_get_lua_state(pool, spec, r);
1613     if (L == NULL) {
1614         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02314)
1615                       "Unable to compile VM for authz provider %s", prov_spec->name);
1616         return AUTHZ_GENERAL_ERROR;
1617     }
1618     lua_getglobal(L, prov_spec->function_name);
1619     if (!lua_isfunction(L, -1)) {
1620         ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02319)
1621                       "Unable to find function %s in %s",
1622                       prov_spec->function_name, prov_spec->file_name);
1623         ap_lua_release_state(L, spec, r);
1624         return AUTHZ_GENERAL_ERROR;
1625     }
1626     ap_lua_run_lua_request(L, r);
1627     if (prov_spec->args) {
1628         int i;
1629         if (!lua_checkstack(L, prov_spec->args->nelts)) {
1630             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02315)
1631                           "Error: authz provider %s: too many arguments", prov_spec->name);
1632             ap_lua_release_state(L, spec, r);
1633             return AUTHZ_GENERAL_ERROR;
1634         }
1635         for (i = 0; i < prov_spec->args->nelts; i++) {
1636             const char *arg = APR_ARRAY_IDX(prov_spec->args, i, const char *);
1637             lua_pushstring(L, arg);
1638         }
1639         nargs = prov_spec->args->nelts;
1640     }
1641     if (lua_pcall(L, 1 + nargs, 1, 0)) {
1642         const char *err = lua_tostring(L, -1);
1643         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02316)
1644                       "Error executing authz provider %s: %s", prov_spec->name, err);
1645         ap_lua_release_state(L, spec, r);
1646         return AUTHZ_GENERAL_ERROR;
1647     }
1648     if (!lua_isnumber(L, -1)) {
1649         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02317)
1650                       "Error: authz provider %s did not return integer", prov_spec->name);
1651         ap_lua_release_state(L, spec, r);
1652         return AUTHZ_GENERAL_ERROR;
1653     }
1654     result = lua_tointeger(L, -1);
1655     ap_lua_release_state(L, spec, r);
1656     switch (result) {
1657         case AUTHZ_DENIED:
1658         case AUTHZ_GRANTED:
1659         case AUTHZ_NEUTRAL:
1660         case AUTHZ_GENERAL_ERROR:
1661         case AUTHZ_DENIED_NO_USER:
1662             return result;
1663         default:
1664             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02318)
1665                           "Error: authz provider %s: invalid return value %d",
1666                           prov_spec->name, result);
1667     }
1668     return AUTHZ_GENERAL_ERROR;
1669 }
1670
1671 static const authz_provider lua_authz_provider =
1672 {
1673     &lua_authz_check,
1674     &lua_authz_parse,
1675 };
1676
1677 static const char *register_authz_provider(cmd_parms *cmd, void *_cfg,
1678                                            const char *name, const char *file,
1679                                            const char *function)
1680 {
1681     lua_authz_provider_spec *spec;
1682     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1683     if (err)
1684         return err;
1685
1686     spec = apr_pcalloc(cmd->pool, sizeof(*spec));
1687     spec->name = name;
1688     spec->file_name = file;
1689     spec->function_name = function;
1690
1691     apr_hash_set(lua_authz_providers, name, APR_HASH_KEY_STRING, spec);
1692     ap_register_auth_provider(cmd->pool, AUTHZ_PROVIDER_GROUP, name,
1693                               AUTHZ_PROVIDER_VERSION,
1694                               &lua_authz_provider,
1695                               AP_AUTH_INTERNAL_PER_CONF);
1696     return NULL;
1697 }
1698
1699
1700 command_rec lua_commands[] = {
1701
1702     AP_INIT_TAKE1("LuaRoot", register_lua_root, NULL, OR_ALL,
1703                   "Specify the base path for resolving relative paths for mod_lua directives"),
1704
1705     AP_INIT_TAKE1("LuaPackagePath", register_package_dir, NULL, OR_ALL,
1706                   "Add a directory to lua's package.path"),
1707
1708     AP_INIT_TAKE1("LuaPackageCPath", register_package_cdir, NULL, OR_ALL,
1709                   "Add a directory to lua's package.cpath"),
1710
1711     AP_INIT_TAKE3("LuaAuthzProvider", register_authz_provider, NULL, RSRC_CONF|EXEC_ON_READ,
1712                   "Provide an authorization provider"),
1713
1714     AP_INIT_TAKE23("LuaHookTranslateName", register_translate_name_hook, NULL,
1715                   OR_ALL,
1716                   "Provide a hook for the translate name phase of request processing"),
1717
1718     AP_INIT_RAW_ARGS("<LuaHookTranslateName", register_translate_name_block,
1719                      NULL,
1720                      EXEC_ON_READ | OR_ALL,
1721                      "Provide a hook for the translate name phase of request processing"),
1722
1723     AP_INIT_TAKE2("LuaHookFixups", register_fixups_hook, NULL, OR_ALL,
1724                   "Provide a hook for the fixups phase of request processing"),
1725     AP_INIT_RAW_ARGS("<LuaHookFixups", register_fixups_block, NULL,
1726                      EXEC_ON_READ | OR_ALL,
1727                      "Provide a inline hook for the fixups phase of request processing"),
1728
1729     /* todo: test */
1730     AP_INIT_TAKE2("LuaHookMapToStorage", register_map_to_storage_hook, NULL,
1731                   OR_ALL,
1732                   "Provide a hook for the map_to_storage phase of request processing"),
1733     AP_INIT_RAW_ARGS("<LuaHookMapToStorage", register_map_to_storage_block,
1734                      NULL,
1735                      EXEC_ON_READ | OR_ALL,
1736                      "Provide a hook for the map_to_storage phase of request processing"),
1737
1738     /* todo: test */
1739     AP_INIT_TAKE23("LuaHookCheckUserID", register_check_user_id_hook, NULL,
1740                   OR_ALL,
1741                   "Provide a hook for the check_user_id phase of request processing"),
1742     AP_INIT_RAW_ARGS("<LuaHookCheckUserID", register_check_user_id_block,
1743                      NULL,
1744                      EXEC_ON_READ | OR_ALL,
1745                      "Provide a hook for the check_user_id phase of request processing"),
1746
1747     /* todo: test */
1748     AP_INIT_TAKE2("LuaHookTypeChecker", register_type_checker_hook, NULL,
1749                   OR_ALL,
1750                   "Provide a hook for the type_checker phase of request processing"),
1751     AP_INIT_RAW_ARGS("<LuaHookTypeChecker", register_type_checker_block, NULL,
1752                      EXEC_ON_READ | OR_ALL,
1753                      "Provide a hook for the type_checker phase of request processing"),
1754
1755     /* todo: test */
1756     AP_INIT_TAKE23("LuaHookAccessChecker", register_access_checker_hook, NULL,
1757                   OR_ALL,
1758                   "Provide a hook for the access_checker phase of request processing"),
1759     AP_INIT_RAW_ARGS("<LuaHookAccessChecker", register_access_checker_block,
1760                      NULL,
1761                      EXEC_ON_READ | OR_ALL,
1762                      "Provide a hook for the access_checker phase of request processing"),
1763
1764     /* todo: test */
1765     AP_INIT_TAKE23("LuaHookAuthChecker", register_auth_checker_hook, NULL,
1766                   OR_ALL,
1767                   "Provide a hook for the auth_checker phase of request processing"),
1768     AP_INIT_RAW_ARGS("<LuaHookAuthChecker", register_auth_checker_block, NULL,
1769                      EXEC_ON_READ | OR_ALL,
1770                      "Provide a hook for the auth_checker phase of request processing"),
1771
1772     /* todo: test */
1773     AP_INIT_TAKE2("LuaHookInsertFilter", register_insert_filter_hook, NULL,
1774                   OR_ALL,
1775                   "Provide a hook for the insert_filter phase of request processing"),
1776
1777     AP_INIT_TAKE123("LuaScope", register_lua_scope, NULL, OR_ALL,
1778                     "One of once, request, conn, server -- default is once"),
1779
1780     AP_INIT_TAKE1("LuaInherit", register_lua_inherit, NULL, OR_ALL,
1781      "Controls how Lua scripts in parent contexts are merged with the current " 
1782      " context: none|parent-last|parent-first (default: parent-first) "),
1783     
1784     AP_INIT_TAKE1("LuaCodeCache", register_lua_codecache, NULL, OR_ALL,
1785      "Controls the behavior of the in-memory code cache " 
1786      " context: stat|forever|never (default: stat) "),
1787
1788     AP_INIT_TAKE2("LuaQuickHandler", register_quick_hook, NULL, OR_ALL,
1789                   "Provide a hook for the quick handler of request processing"),
1790     AP_INIT_RAW_ARGS("<LuaQuickHandler", register_quick_block, NULL,
1791                      EXEC_ON_READ | OR_ALL,
1792                      "Provide a hook for the quick handler of request processing"),
1793     AP_INIT_RAW_ARGS("Lua_____ByteCodeHack", hack_section_handler, NULL,
1794                      OR_ALL,
1795                      "(internal) Byte code handler"),
1796     AP_INIT_TAKE23("LuaMapHandler", register_map_handler, NULL, OR_ALL,
1797                   "Maps a path to a lua handler"),
1798     AP_INIT_TAKE3("LuaOutputFilter", register_output_filter, NULL, OR_ALL,
1799                   "Registers a Lua function as an output filter"),
1800     AP_INIT_TAKE3("LuaInputFilter", register_input_filter, NULL, OR_ALL,
1801                   "Registers a Lua function as an input filter"),
1802     {NULL}
1803 };
1804
1805
1806 static void *create_dir_config(apr_pool_t *p, char *dir)
1807 {
1808     ap_lua_dir_cfg *cfg = apr_pcalloc(p, sizeof(ap_lua_dir_cfg));
1809     cfg->package_paths = apr_array_make(p, 2, sizeof(char *));
1810     cfg->package_cpaths = apr_array_make(p, 2, sizeof(char *));
1811     cfg->mapped_handlers =
1812         apr_array_make(p, 1, sizeof(ap_lua_mapped_handler_spec *));
1813     cfg->mapped_filters =
1814         apr_array_make(p, 1, sizeof(ap_lua_filter_handler_spec *));
1815     cfg->pool = p;
1816     cfg->hooks = apr_hash_make(p);
1817     cfg->dir = apr_pstrdup(p, dir);
1818     cfg->vm_scope = AP_LUA_SCOPE_UNSET;
1819     cfg->codecache = AP_LUA_CACHE_UNSET;
1820     cfg->vm_min = 0;
1821     cfg->vm_max = 0;
1822
1823     return cfg;
1824 }
1825
1826 static int create_request_config(request_rec *r)
1827 {
1828     ap_lua_request_cfg *cfg = apr_palloc(r->pool, sizeof(ap_lua_request_cfg));
1829     cfg->mapped_request_details = NULL;
1830     cfg->request_scoped_vms = apr_hash_make(r->pool);
1831     ap_set_module_config(r->request_config, &lua_module, cfg);
1832     return OK;
1833 }
1834
1835 static void *create_server_config(apr_pool_t *p, server_rec *s)
1836 {
1837
1838     ap_lua_server_cfg *cfg = apr_pcalloc(p, sizeof(ap_lua_server_cfg));
1839     cfg->vm_reslists = apr_hash_make(p);
1840     apr_thread_rwlock_create(&cfg->vm_reslists_lock, p);
1841     cfg->root_path = NULL;
1842
1843     return cfg;
1844 }
1845
1846 static int lua_request_hook(lua_State *L, request_rec *r)
1847 {
1848     ap_lua_push_request(L, r);
1849     return OK;
1850 }
1851
1852 static int lua_post_config(apr_pool_t *pconf, apr_pool_t *plog,
1853                              apr_pool_t *ptemp, server_rec *s)
1854 {
1855     lua_ssl_val = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
1856     lua_ssl_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
1857     return OK;
1858 }
1859 static void *overlay_hook_specs(apr_pool_t *p,
1860                                         const void *key,
1861                                         apr_ssize_t klen,
1862                                         const void *overlay_val,
1863                                         const void *base_val,
1864                                         const void *data)
1865 {
1866     const apr_array_header_t *overlay_info = (const apr_array_header_t*)overlay_val;
1867     const apr_array_header_t *base_info = (const apr_array_header_t*)base_val;
1868     return apr_array_append(p, base_info, overlay_info);
1869 }
1870
1871 static void *merge_dir_config(apr_pool_t *p, void *basev, void *overridesv)
1872 {
1873     ap_lua_dir_cfg *a, *base, *overrides;
1874
1875     a         = (ap_lua_dir_cfg *)apr_pcalloc(p, sizeof(ap_lua_dir_cfg));
1876     base      = (ap_lua_dir_cfg*)basev;
1877     overrides = (ap_lua_dir_cfg*)overridesv;
1878
1879     a->pool = overrides->pool;
1880     a->dir = apr_pstrdup(p, overrides->dir);
1881
1882     a->vm_scope = (overrides->vm_scope == AP_LUA_SCOPE_UNSET) ? base->vm_scope: overrides->vm_scope;
1883     a->inherit = (overrides->inherit == AP_LUA_INHERIT_UNSET) ? base->inherit : overrides->inherit;
1884     a->codecache = (overrides->codecache == AP_LUA_CACHE_UNSET) ? base->codecache : overrides->codecache;
1885     
1886     a->vm_min = (overrides->vm_min == 0) ? base->vm_min : overrides->vm_min;
1887     a->vm_max = (overrides->vm_max == 0) ? base->vm_max : overrides->vm_max;
1888
1889     if (a->inherit == AP_LUA_INHERIT_UNSET || a->inherit == AP_LUA_INHERIT_PARENT_FIRST) { 
1890         a->package_paths = apr_array_append(p, base->package_paths, overrides->package_paths);
1891         a->package_cpaths = apr_array_append(p, base->package_cpaths, overrides->package_cpaths);
1892         a->mapped_handlers = apr_array_append(p, base->mapped_handlers, overrides->mapped_handlers);
1893         a->mapped_filters = apr_array_append(p, base->mapped_filters, overrides->mapped_filters);
1894         a->hooks = apr_hash_merge(p, overrides->hooks, base->hooks, overlay_hook_specs, NULL);
1895     }
1896     else if (a->inherit == AP_LUA_INHERIT_PARENT_LAST) { 
1897         a->package_paths = apr_array_append(p, overrides->package_paths, base->package_paths);
1898         a->package_cpaths = apr_array_append(p, overrides->package_cpaths, base->package_cpaths);
1899         a->mapped_handlers = apr_array_append(p, overrides->mapped_handlers, base->mapped_handlers);
1900         a->mapped_filters = apr_array_append(p, overrides->mapped_filters, base->mapped_filters);
1901         a->hooks = apr_hash_merge(p, base->hooks, overrides->hooks, overlay_hook_specs, NULL);
1902     }
1903     else { 
1904         a->package_paths = overrides->package_paths;
1905         a->package_cpaths = overrides->package_cpaths;
1906         a->mapped_handlers= overrides->mapped_handlers;
1907         a->mapped_filters= overrides->mapped_filters;
1908         a->hooks= overrides->hooks;
1909     }
1910
1911     return a;
1912 }
1913
1914 static void lua_register_hooks(apr_pool_t *p)
1915 {
1916     /* ap_register_output_filter("luahood", luahood, NULL, AP_FTYPE_RESOURCE); */
1917     ap_hook_handler(lua_handler, NULL, NULL, APR_HOOK_MIDDLE);
1918     ap_hook_create_request(create_request_config, NULL, NULL,
1919                            APR_HOOK_MIDDLE);
1920
1921     /* http_request.h hooks */
1922     ap_hook_translate_name(lua_translate_name_harness_first, NULL, NULL,
1923                            AP_LUA_HOOK_FIRST);
1924     ap_hook_translate_name(lua_translate_name_harness, NULL, NULL,
1925                            APR_HOOK_MIDDLE);
1926     ap_hook_translate_name(lua_translate_name_harness_last, NULL, NULL,
1927                            AP_LUA_HOOK_LAST);
1928
1929     ap_hook_fixups(lua_fixup_harness, NULL, NULL, APR_HOOK_MIDDLE);
1930     ap_hook_map_to_storage(lua_map_to_storage_harness, NULL, NULL,
1931                            APR_HOOK_MIDDLE);
1932
1933     ap_hook_check_user_id(lua_check_user_id_harness_first, NULL, NULL,
1934                           AP_LUA_HOOK_FIRST);
1935     ap_hook_check_user_id(lua_check_user_id_harness, NULL, NULL,
1936                            APR_HOOK_MIDDLE);
1937     ap_hook_check_user_id(lua_check_user_id_harness_last, NULL, NULL,
1938                           AP_LUA_HOOK_LAST);
1939
1940     ap_hook_type_checker(lua_type_checker_harness, NULL, NULL,
1941                          APR_HOOK_MIDDLE);
1942
1943     ap_hook_access_checker(lua_access_checker_harness_first, NULL, NULL,
1944                            AP_LUA_HOOK_FIRST);
1945     ap_hook_access_checker(lua_access_checker_harness, NULL, NULL,
1946                            APR_HOOK_MIDDLE);
1947     ap_hook_access_checker(lua_access_checker_harness_last, NULL, NULL,
1948                            AP_LUA_HOOK_LAST);
1949     ap_hook_auth_checker(lua_auth_checker_harness_first, NULL, NULL,
1950                          AP_LUA_HOOK_FIRST);
1951     ap_hook_auth_checker(lua_auth_checker_harness, NULL, NULL,
1952                          APR_HOOK_MIDDLE);
1953     ap_hook_auth_checker(lua_auth_checker_harness_last, NULL, NULL,
1954                          AP_LUA_HOOK_LAST);
1955
1956     ap_hook_insert_filter(lua_insert_filter_harness, NULL, NULL,
1957                           APR_HOOK_MIDDLE);
1958     ap_hook_quick_handler(lua_quick_harness, NULL, NULL, APR_HOOK_FIRST);
1959
1960     ap_hook_post_config(lua_post_config, NULL, NULL, APR_HOOK_MIDDLE);
1961
1962     APR_OPTIONAL_HOOK(ap_lua, lua_open, lua_open_hook, NULL, NULL,
1963                       APR_HOOK_REALLY_FIRST);
1964
1965     APR_OPTIONAL_HOOK(ap_lua, lua_request, lua_request_hook, NULL, NULL,
1966                       APR_HOOK_REALLY_FIRST);
1967     ap_hook_handler(lua_map_handler, NULL, NULL, AP_LUA_HOOK_FIRST);
1968 #if APR_HAS_THREADS
1969     ap_hook_child_init(ap_lua_init_mutex, NULL, NULL, APR_HOOK_MIDDLE);
1970 #endif
1971     /* providers */
1972     lua_authz_providers = apr_hash_make(p);
1973 }
1974
1975 AP_DECLARE_MODULE(lua) = {
1976     STANDARD20_MODULE_STUFF,
1977     create_dir_config,          /* create per-dir    config structures */
1978     merge_dir_config,           /* merge  per-dir    config structures */
1979     create_server_config,       /* create per-server config structures */
1980     NULL,                       /* merge  per-server config structures */
1981     lua_commands,               /* table of config file commands       */
1982     lua_register_hooks          /* register hooks                      */
1983 };