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