]> granicus.if.org Git - apache/blob - modules/lua/mod_lua.c
mod_lua: Remember to set cfg->codecache to AP_LUA_CACHE_UNSET when creating a config
[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
59 /**
60  * error reporting if lua has an error.
61  * Extracts the error from lua stack and prints
62  */
63 static void report_lua_error(lua_State *L, request_rec *r)
64 {
65     const char *lua_response;
66     r->status = HTTP_INTERNAL_SERVER_ERROR;
67     r->content_type = "text/html";
68
69     ap_rputs("<b>Error!</b>\n", r);
70     ap_rputs("<p>", r);
71     lua_response = lua_tostring(L, -1);
72     ap_rputs(lua_response, r);
73     ap_rputs("</p>\n", r);
74
75     ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, r->pool, APLOGNO(01471) "Lua error: %s",
76                   lua_response);
77 }
78
79 static void lua_open_callback(lua_State *L, apr_pool_t *p, void *ctx)
80 {
81     ap_lua_init(L, p);
82     ap_lua_load_apache2_lmodule(L);
83     ap_lua_load_request_lmodule(L, p);
84     ap_lua_load_config_lmodule(L);
85 }
86
87 static int lua_open_hook(lua_State *L, apr_pool_t *p)
88 {
89     lua_open_callback(L, p, NULL);
90     return OK;
91 }
92
93 static const char *scope_to_string(unsigned int scope)
94 {
95     switch (scope) {
96     case AP_LUA_SCOPE_ONCE:
97     case AP_LUA_SCOPE_UNSET:
98         return "once";
99     case AP_LUA_SCOPE_REQUEST:
100         return "request";
101     case AP_LUA_SCOPE_CONN:
102         return "conn";
103 #if APR_HAS_THREADS
104     case AP_LUA_SCOPE_THREAD:
105         return "thread";
106 #endif
107     default:
108         ap_assert(0);
109     }
110 }
111
112 static ap_lua_vm_spec *create_vm_spec(apr_pool_t **lifecycle_pool,
113                                       request_rec *r,
114                                       const ap_lua_dir_cfg *cfg,
115                                       const ap_lua_server_cfg *server_cfg,
116                                       const char *filename,
117                                       const char *bytecode,
118                                       apr_size_t bytecode_len,
119                                       const char *function,
120                                       const char *what)
121 {
122     apr_pool_t *pool;
123     ap_lua_vm_spec *spec = apr_pcalloc(r->pool, sizeof(ap_lua_vm_spec));
124
125     spec->scope = cfg->vm_scope;
126     spec->pool = r->pool;
127     spec->package_paths = cfg->package_paths;
128     spec->package_cpaths = cfg->package_cpaths;
129     spec->cb = &lua_open_callback;
130     spec->cb_arg = NULL;
131     spec->bytecode = bytecode;
132     spec->bytecode_len = bytecode_len;
133     spec->codecache = (cfg->codecache == AP_LUA_CACHE_UNSET) ? AP_LUA_CACHE_STAT : cfg->codecache;
134
135     if (filename) {
136         char *file;
137         apr_filepath_merge(&file, server_cfg->root_path,
138                            filename, APR_FILEPATH_NOTRELATIVE, r->pool);
139         spec->file = file;
140     }
141     else {
142         spec->file = r->filename;
143     }
144     ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, APLOGNO(02313)
145                   "%s details: scope: %s, file: %s, func: %s",
146                   what, scope_to_string(spec->scope), spec->file,
147                   function ? function : "-");
148
149     switch (spec->scope) {
150     case AP_LUA_SCOPE_ONCE:
151     case AP_LUA_SCOPE_UNSET:
152         apr_pool_create(&pool, r->pool);
153         break;
154     case AP_LUA_SCOPE_REQUEST:
155         pool = r->pool;
156         break;
157     case AP_LUA_SCOPE_CONN:
158         pool = r->connection->pool;
159         break;
160 #if APR_HAS_THREADS
161     case AP_LUA_SCOPE_THREAD:
162         pool = apr_thread_pool_get(r->connection->current_thread);
163         break;
164 #endif
165     default:
166         ap_assert(0);
167     }
168
169     *lifecycle_pool = pool;
170     return spec;
171 }
172
173
174 /**
175  * "main"
176  */
177 static int lua_handler(request_rec *r)
178 {
179     if (strcmp(r->handler, "lua-script")) {
180         return DECLINED;
181     }
182     ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(01472)
183                   "handling [%s] in mod_lua", r->filename);
184
185     /* XXX: This seems wrong because it may generate wrong headers for HEAD requests */
186     if (!r->header_only) {
187         lua_State *L;
188         apr_pool_t *pool;
189         const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
190                                                          &lua_module);
191         ap_lua_vm_spec *spec = create_vm_spec(&pool, r, cfg, NULL, NULL, NULL,
192                                               0, "handle", "request handler");
193
194         L = ap_lua_get_lua_state(pool, spec, r);
195         if (!L) {
196             /* TODO annotate spec with failure reason */
197             r->status = HTTP_INTERNAL_SERVER_ERROR;
198             ap_rputs("Unable to compile VM, see logs", r);
199             return HTTP_INTERNAL_SERVER_ERROR;
200         }
201         ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, APLOGNO(01474) "got a vm!");
202         lua_getglobal(L, "handle");
203         if (!lua_isfunction(L, -1)) {
204             ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01475)
205                           "lua: Unable to find function %s in %s",
206                           "handle",
207                           spec->file);
208             return HTTP_INTERNAL_SERVER_ERROR;
209         }
210         ap_lua_run_lua_request(L, r);
211         if (lua_pcall(L, 1, 0, 0)) {
212             report_lua_error(L, r);
213         }
214     }
215     return OK;
216 }
217
218
219
220 /* ---------------- Configury stuff --------------- */
221
222 /** harnesses for magic hooks **/
223
224 static int lua_request_rec_hook_harness(request_rec *r, const char *name, int apr_hook_when)
225 {
226     int rc;
227     apr_pool_t *pool;
228     lua_State *L;
229     ap_lua_vm_spec *spec;
230     ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
231                                                          &lua_module);
232     const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
233                                                      &lua_module);
234     const char *key = apr_psprintf(r->pool, "%s_%d", name, apr_hook_when);
235     apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
236                                                   APR_HASH_KEY_STRING);
237     if (hook_specs) {
238         int i;
239         for (i = 0; i < hook_specs->nelts; i++) {
240             ap_lua_mapped_handler_spec *hook_spec =
241                 ((ap_lua_mapped_handler_spec **) hook_specs->elts)[i];
242
243             if (hook_spec == NULL) {
244                 continue;
245             }
246             spec = create_vm_spec(&pool, r, cfg, server_cfg,
247                                   hook_spec->file_name,
248                                   hook_spec->bytecode,
249                                   hook_spec->bytecode_len,
250                                   hook_spec->function_name,
251                                   "request hook");
252
253             L = ap_lua_get_lua_state(pool, spec, r);
254
255             if (!L) {
256                 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01477)
257                               "lua: Failed to obtain lua interpreter for %s %s",
258                               hook_spec->function_name, hook_spec->file_name);
259                 return HTTP_INTERNAL_SERVER_ERROR;
260             }
261
262             if (hook_spec->function_name != NULL) {
263                 lua_getglobal(L, hook_spec->function_name);
264                 if (!lua_isfunction(L, -1)) {
265                     ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01478)
266                                   "lua: Unable to find function %s in %s",
267                                   hook_spec->function_name,
268                                   hook_spec->file_name);
269                     return HTTP_INTERNAL_SERVER_ERROR;
270                 }
271
272                 ap_lua_run_lua_request(L, r);
273             }
274             else {
275                 int t;
276                 ap_lua_run_lua_request(L, r);
277
278                 t = lua_gettop(L);
279                 lua_setglobal(L, "r");
280                 lua_settop(L, t);
281             }
282
283             if (lua_pcall(L, 1, 1, 0)) {
284                 report_lua_error(L, r);
285                 return HTTP_INTERNAL_SERVER_ERROR;
286             }
287             rc = DECLINED;
288             if (lua_isnumber(L, -1)) {
289                 rc = lua_tointeger(L, -1);
290             }
291             if (rc != DECLINED) {
292                 return rc;
293             }
294         }
295     }
296     return DECLINED;
297 }
298
299
300 static apr_size_t config_getstr(ap_configfile_t *cfg, char *buf,
301                                 size_t bufsiz)
302 {
303     apr_size_t i = 0;
304
305     if (cfg->getstr) {
306         apr_status_t rc = (cfg->getstr) (buf, bufsiz, cfg->param);
307         if (rc == APR_SUCCESS) {
308             i = strlen(buf);
309             if (i && buf[i - 1] == '\n')
310                 ++cfg->line_number;
311         }
312         else {
313             buf[0] = '\0';
314             i = 0;
315         }
316     }
317     else {
318         while (i < bufsiz) {
319             char ch;
320             apr_status_t rc = (cfg->getch) (&ch, cfg->param);
321             if (rc != APR_SUCCESS)
322                 break;
323             buf[i++] = ch;
324             if (ch == '\n') {
325                 ++cfg->line_number;
326                 break;
327             }
328         }
329     }
330     return i;
331 }
332
333 typedef struct cr_ctx
334 {
335     cmd_parms *cmd;
336     ap_configfile_t *cfp;
337     size_t startline;
338     const char *endstr;
339     char buf[HUGE_STRING_LEN];
340 } cr_ctx;
341
342
343 /* Okay, this deserves a little explaination -- in order for the errors that lua
344  * generates to be 'accuarate', including line numbers, we basically inject
345  * N line number new lines into the 'top' of the chunk reader.....
346  *
347  * be happy. this is cool.
348  *
349  */
350 static const char *lf =
351     "\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";
352 #define N_LF 32
353
354 static const char *direct_chunkreader(lua_State *lvm, void *udata,
355                                       size_t *plen)
356 {
357     const char *p;
358     struct cr_ctx *ctx = udata;
359
360     if (ctx->startline) {
361         *plen = ctx->startline > N_LF ? N_LF : ctx->startline;
362         ctx->startline -= *plen;
363         return lf;
364     }
365     *plen = config_getstr(ctx->cfp, ctx->buf, HUGE_STRING_LEN);
366
367     for (p = ctx->buf; isspace(*p); ++p);
368     if (p[0] == '<' && p[1] == '/') {
369         apr_size_t i = 0;
370         while (i < strlen(ctx->endstr)) {
371             if (tolower(p[i + 2]) != ctx->endstr[i])
372                 return ctx->buf;
373             ++i;
374         }
375         *plen = 0;
376         return NULL;
377     }
378     /*fprintf(stderr, "buf read: %s\n", ctx->buf); */
379     return ctx->buf;
380 }
381
382 static int ldump_writer(lua_State *L, const void *b, size_t size, void *B)
383 {
384     (void) L;
385     luaL_addlstring((luaL_Buffer *) B, (const char *) b, size);
386     return 0;
387 }
388
389 typedef struct hack_section_baton
390 {
391     const char *name;
392     ap_lua_mapped_handler_spec *spec;
393     int apr_hook_when;
394 } hack_section_baton;
395
396 /* You can be unhappy now.
397  *
398  * This is uncool.
399  *
400  * When you create a <Section handler in httpd, the only 'easy' way to create
401  * a directory context is to parse the section, and convert it into a 'normal'
402  * Configureation option, and then collapse the entire section, in memory,
403  * back into the parent section -- from which you can then get the new directive
404  * invoked.... anyways. evil. Rici taught me how to do this hack :-)
405  */
406 static const char *hack_section_handler(cmd_parms *cmd, void *_cfg,
407                                         const char *arg)
408 {
409     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
410     ap_directive_t *directive = cmd->directive;
411     hack_section_baton *baton = directive->data;
412     const char *key = apr_psprintf(cmd->pool, "%s_%d", baton->name, baton->apr_hook_when);
413
414     apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
415                                                   APR_HASH_KEY_STRING);
416     if (!hook_specs) {
417         hook_specs = apr_array_make(cmd->pool, 2,
418                                     sizeof(ap_lua_mapped_handler_spec *));
419         apr_hash_set(cfg->hooks, key,
420                      APR_HASH_KEY_STRING, hook_specs);
421     }
422
423     baton->spec->scope = cfg->vm_scope;
424
425     *(ap_lua_mapped_handler_spec **) apr_array_push(hook_specs) = baton->spec;
426
427     return NULL;
428 }
429
430 static const char *register_named_block_function_hook(const char *name,
431                                                       cmd_parms *cmd,
432                                                       void *mconfig,
433                                                       const char *line)
434 {
435     const char *function = NULL;
436     ap_lua_mapped_handler_spec *spec;
437     int when = APR_HOOK_MIDDLE;
438     const char *endp = ap_strrchr_c(line, '>');
439
440     if (endp == NULL) {
441         return apr_pstrcat(cmd->pool, cmd->cmd->name,
442                            "> directive missing closing '>'", NULL);
443     }
444
445     line = apr_pstrndup(cmd->temp_pool, line, endp - line);
446
447     if (line[0]) { 
448         const char *word;
449         word = ap_getword_conf(cmd->temp_pool, &line);
450         if (word && *word) {
451             function = apr_pstrdup(cmd->pool, word);
452         }
453         word = ap_getword_conf(cmd->temp_pool, &line);
454         if (word && *word) {
455             if (!strcasecmp("early", word)) { 
456                 when = AP_LUA_HOOK_FIRST;
457             }
458             else if (!strcasecmp("late", word)) {
459                 when = AP_LUA_HOOK_LAST;
460             }
461             else { 
462                 return apr_pstrcat(cmd->pool, cmd->cmd->name,
463                                    "> 2nd argument must be 'early' or 'late'", NULL);
464             }
465         }
466     }
467
468     spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec));
469
470     {
471         cr_ctx ctx;
472         lua_State *lvm;
473         char *tmp;
474         int rv;
475         ap_directive_t **current;
476         hack_section_baton *baton;
477
478         spec->file_name = apr_psprintf(cmd->pool, "%s:%u",
479                                        cmd->config_file->name,
480                                        cmd->config_file->line_number);
481         if (function) {
482             spec->function_name = (char *) function;
483         }
484         else {
485             function = NULL;
486         }
487
488         ctx.cmd = cmd;
489         tmp = apr_pstrdup(cmd->pool, cmd->err_directive->directive + 1);
490         ap_str_tolower(tmp);
491         ctx.endstr = tmp;
492         ctx.cfp = cmd->config_file;
493         ctx.startline = cmd->config_file->line_number;
494
495         /* This lua State is used only to compile the input strings -> bytecode, so we don't need anything extra. */
496         lvm = luaL_newstate();
497
498         lua_settop(lvm, 0);
499
500         rv = lua_load(lvm, direct_chunkreader, &ctx, spec->file_name);
501
502         if (rv != 0) {
503             const char *errstr = apr_pstrcat(cmd->pool, "Lua Error:",
504                                              lua_tostring(lvm, -1), NULL);
505             lua_close(lvm);
506             return errstr;
507         }
508         else {
509             luaL_Buffer b;
510             luaL_buffinit(lvm, &b);
511             lua_dump(lvm, ldump_writer, &b);
512             luaL_pushresult(&b);
513             spec->bytecode_len = lua_strlen(lvm, -1);
514             spec->bytecode = apr_pstrmemdup(cmd->pool, lua_tostring(lvm, -1),
515                                             spec->bytecode_len);
516             lua_close(lvm);
517         }
518
519         current = mconfig;
520
521         /* Here, we have to replace our current config node for the next pass */
522         if (!*current) {
523             *current = apr_pcalloc(cmd->pool, sizeof(**current));
524         }
525
526         baton = apr_pcalloc(cmd->pool, sizeof(hack_section_baton));
527         baton->name = name;
528         baton->spec = spec;
529         baton->apr_hook_when = when;
530
531         (*current)->filename = cmd->config_file->name;
532         (*current)->line_num = cmd->config_file->line_number;
533         (*current)->directive = apr_pstrdup(cmd->pool, "Lua_____ByteCodeHack");
534         (*current)->args = NULL;
535         (*current)->data = baton;
536     }
537
538     return NULL;
539 }
540
541 static const char *register_named_file_function_hook(const char *name,
542                                                      cmd_parms *cmd,
543                                                      void *_cfg,
544                                                      const char *file,
545                                                      const char *function,
546                                                      int apr_hook_when)
547 {
548     ap_lua_mapped_handler_spec *spec;
549     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
550     const char *key = apr_psprintf(cmd->pool, "%s_%d", name, apr_hook_when);
551     apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
552                                                   APR_HASH_KEY_STRING);
553
554     if (!hook_specs) {
555         hook_specs = apr_array_make(cmd->pool, 2,
556                                     sizeof(ap_lua_mapped_handler_spec *));
557         apr_hash_set(cfg->hooks, key, APR_HASH_KEY_STRING, hook_specs);
558     }
559
560     spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec));
561     spec->file_name = apr_pstrdup(cmd->pool, file);
562     spec->function_name = apr_pstrdup(cmd->pool, function);
563     spec->scope = cfg->vm_scope;
564
565     *(ap_lua_mapped_handler_spec **) apr_array_push(hook_specs) = spec;
566     return NULL;
567 }
568
569 static int lua_check_user_id_harness_first(request_rec *r)
570 {
571     return lua_request_rec_hook_harness(r, "check_user_id", AP_LUA_HOOK_FIRST);
572 }
573 static int lua_check_user_id_harness(request_rec *r)
574 {
575     return lua_request_rec_hook_harness(r, "check_user_id", APR_HOOK_MIDDLE);
576 }
577 static int lua_check_user_id_harness_last(request_rec *r)
578 {
579     return lua_request_rec_hook_harness(r, "check_user_id", AP_LUA_HOOK_LAST);
580 }
581
582 static int lua_translate_name_harness_first(request_rec *r)
583 {
584     return lua_request_rec_hook_harness(r, "translate_name", AP_LUA_HOOK_FIRST);
585 }
586 static int lua_translate_name_harness(request_rec *r)
587 {
588     return lua_request_rec_hook_harness(r, "translate_name", APR_HOOK_MIDDLE);
589 }
590 static int lua_translate_name_harness_last(request_rec *r)
591 {
592     return lua_request_rec_hook_harness(r, "translate_name", AP_LUA_HOOK_LAST);
593 }
594
595 static int lua_fixup_harness(request_rec *r)
596 {
597     return lua_request_rec_hook_harness(r, "fixups", APR_HOOK_MIDDLE);
598 }
599
600 static int lua_map_to_storage_harness(request_rec *r)
601 {
602     return lua_request_rec_hook_harness(r, "map_to_storage", APR_HOOK_MIDDLE);
603 }
604
605 static int lua_type_checker_harness(request_rec *r)
606 {
607     return lua_request_rec_hook_harness(r, "type_checker", APR_HOOK_MIDDLE);
608 }
609
610 static int lua_access_checker_harness_first(request_rec *r)
611 {
612     return lua_request_rec_hook_harness(r, "access_checker", AP_LUA_HOOK_FIRST);
613 }
614 static int lua_access_checker_harness(request_rec *r)
615 {
616     return lua_request_rec_hook_harness(r, "access_checker", APR_HOOK_MIDDLE);
617 }
618 static int lua_access_checker_harness_last(request_rec *r)
619 {
620     return lua_request_rec_hook_harness(r, "access_checker", AP_LUA_HOOK_LAST);
621 }
622
623 static int lua_auth_checker_harness_first(request_rec *r)
624 {
625     return lua_request_rec_hook_harness(r, "auth_checker", AP_LUA_HOOK_FIRST);
626 }
627 static int lua_auth_checker_harness(request_rec *r)
628 {
629     return lua_request_rec_hook_harness(r, "auth_checker", APR_HOOK_MIDDLE);
630 }
631 static int lua_auth_checker_harness_last(request_rec *r)
632 {
633     return lua_request_rec_hook_harness(r, "auth_checker", AP_LUA_HOOK_LAST);
634 }
635 static void lua_insert_filter_harness(request_rec *r)
636 {
637     /* ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "LuaHookInsertFilter not yet implemented"); */
638 }
639
640 static int lua_quick_harness(request_rec *r, int lookup)
641 {
642     if (lookup) {
643         return DECLINED;
644     }
645     return lua_request_rec_hook_harness(r, "quick", APR_HOOK_MIDDLE);
646 }
647
648 static const char *register_translate_name_hook(cmd_parms *cmd, void *_cfg,
649                                                 const char *file,
650                                                 const char *function,
651                                                 const char *when)
652 {
653     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
654                                            NOT_IN_HTACCESS);
655     int apr_hook_when = APR_HOOK_MIDDLE;
656     if (err) {
657         return err;
658     }
659     
660     if (when) { 
661         if (!strcasecmp(when, "early")) { 
662             apr_hook_when = AP_LUA_HOOK_FIRST;
663         } 
664         else if (!strcasecmp(when, "late")) { 
665             apr_hook_when = AP_LUA_HOOK_LAST;
666         } 
667         else { 
668             return "Third argument must be 'early' or 'late'";
669         }
670     }
671
672     return register_named_file_function_hook("translate_name", cmd, _cfg,
673                                              file, function, apr_hook_when);
674 }
675
676 static const char *register_translate_name_block(cmd_parms *cmd, void *_cfg,
677                                                  const char *line)
678 {
679     return register_named_block_function_hook("translate_name", cmd, _cfg,
680                                               line);
681 }
682
683
684 static const char *register_fixups_hook(cmd_parms *cmd, void *_cfg,
685                                         const char *file,
686                                         const char *function)
687 {
688     return register_named_file_function_hook("fixups", cmd, _cfg, file,
689                                              function, APR_HOOK_MIDDLE);
690 }
691 static const char *register_fixups_block(cmd_parms *cmd, void *_cfg,
692                                          const char *line)
693 {
694     return register_named_block_function_hook("fixups", cmd, _cfg, line);
695 }
696
697 static const char *register_map_to_storage_hook(cmd_parms *cmd, void *_cfg,
698                                                 const char *file,
699                                                 const char *function)
700 {
701     return register_named_file_function_hook("map_to_storage", cmd, _cfg,
702                                              file, function, APR_HOOK_MIDDLE);
703 }
704 static const char *register_map_to_storage_block(cmd_parms *cmd, void *_cfg,
705                                                  const char *line)
706 {
707     return register_named_block_function_hook("map_to_storage", cmd, _cfg,
708                                               line);
709 }
710
711 static const char *register_check_user_id_hook(cmd_parms *cmd, void *_cfg,
712                                                const char *file,
713                                                const char *function,
714                                                const char *when)
715 {
716     int apr_hook_when = APR_HOOK_MIDDLE;
717
718     if (when) {
719         if (!strcasecmp(when, "early")) {
720             apr_hook_when = AP_LUA_HOOK_FIRST;
721         }
722         else if (!strcasecmp(when, "late")) {
723             apr_hook_when = AP_LUA_HOOK_LAST;
724         }
725         else {
726             return "Third argument must be 'early' or 'late'";
727         }
728     }
729
730     return register_named_file_function_hook("check_user_id", cmd, _cfg, file,
731                                              function, apr_hook_when);
732 }
733 static const char *register_check_user_id_block(cmd_parms *cmd, void *_cfg,
734                                                 const char *line)
735 {
736     return register_named_block_function_hook("check_user_id", cmd, _cfg,
737                                               line);
738 }
739
740 static const char *register_type_checker_hook(cmd_parms *cmd, void *_cfg,
741                                               const char *file,
742                                               const char *function)
743 {
744     return register_named_file_function_hook("type_checker", cmd, _cfg, file,
745                                              function, APR_HOOK_MIDDLE);
746 }
747 static const char *register_type_checker_block(cmd_parms *cmd, void *_cfg,
748                                                const char *line)
749 {
750     return register_named_block_function_hook("type_checker", cmd, _cfg,
751                                               line);
752 }
753
754 static const char *register_access_checker_hook(cmd_parms *cmd, void *_cfg,
755                                                 const char *file,
756                                                 const char *function,
757                                                 const char *when)
758 {
759     int apr_hook_when = APR_HOOK_MIDDLE;
760
761     if (when) {
762         if (!strcasecmp(when, "early")) {
763             apr_hook_when = AP_LUA_HOOK_FIRST;
764         }
765         else if (!strcasecmp(when, "late")) {
766             apr_hook_when = AP_LUA_HOOK_LAST;
767         }
768         else {
769             return "Third argument must be 'early' or 'late'";
770         }
771     }
772
773     return register_named_file_function_hook("access_checker", cmd, _cfg,
774                                              file, function, apr_hook_when);
775 }
776 static const char *register_access_checker_block(cmd_parms *cmd, void *_cfg,
777                                                  const char *line)
778 {
779
780     return register_named_block_function_hook("access_checker", cmd, _cfg,
781                                               line);
782 }
783
784 static const char *register_auth_checker_hook(cmd_parms *cmd, void *_cfg,
785                                               const char *file,
786                                               const char *function,
787                                               const char *when)
788 {
789     int apr_hook_when = APR_HOOK_MIDDLE;
790
791     if (when) {
792         if (!strcasecmp(when, "early")) {
793             apr_hook_when = AP_LUA_HOOK_FIRST;
794         }
795         else if (!strcasecmp(when, "late")) {
796             apr_hook_when = AP_LUA_HOOK_LAST;
797         }
798         else {
799             return "Third argument must be 'early' or 'late'";
800         }
801     }
802
803     return register_named_file_function_hook("auth_checker", cmd, _cfg, file,
804                                              function, apr_hook_when);
805 }
806 static const char *register_auth_checker_block(cmd_parms *cmd, void *_cfg,
807                                                const char *line)
808 {
809     return register_named_block_function_hook("auth_checker", cmd, _cfg,
810                                               line);
811 }
812
813 static const char *register_insert_filter_hook(cmd_parms *cmd, void *_cfg,
814                                                const char *file,
815                                                const char *function)
816 {
817     return "LuaHookInsertFilter not yet implemented";
818 }
819
820 static const char *register_quick_hook(cmd_parms *cmd, void *_cfg,
821                                        const char *file, const char *function)
822 {
823     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
824                                                 NOT_IN_HTACCESS);
825     if (err) {
826         return err;
827     }
828     return register_named_file_function_hook("quick", cmd, _cfg, file,
829                                              function, APR_HOOK_MIDDLE);
830 }
831 static const char *register_quick_block(cmd_parms *cmd, void *_cfg,
832                                         const char *line)
833 {
834     return register_named_block_function_hook("quick", cmd, _cfg,
835                                               line);
836 }
837
838
839
840 static const char *register_package_helper(cmd_parms *cmd, 
841                                            const char *arg,
842                                            apr_array_header_t *dir_array)
843 {
844     apr_status_t rv;
845
846     ap_lua_server_cfg *server_cfg =
847         ap_get_module_config(cmd->server->module_config, &lua_module);
848
849     char *fixed_filename;
850     rv = apr_filepath_merge(&fixed_filename, 
851                             server_cfg->root_path, 
852                             arg,
853                             APR_FILEPATH_NOTRELATIVE, 
854                             cmd->pool);
855
856     if (rv != APR_SUCCESS) {
857         return apr_psprintf(cmd->pool,
858                             "Unable to build full path to file, %s", arg);
859     }
860
861     *(const char **) apr_array_push(dir_array) = fixed_filename;
862     return NULL;
863 }
864
865
866 /**
867  * Called for config directive which looks like
868  * LuaPackagePath /lua/package/path/mapped/thing/like/this/?.lua
869  */
870 static const char *register_package_dir(cmd_parms *cmd, void *_cfg,
871                                         const char *arg)
872 {
873     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
874
875     return register_package_helper(cmd, arg, cfg->package_paths);
876 }
877
878 /**
879  * Called for config directive which looks like
880  * LuaPackageCPath /lua/package/path/mapped/thing/like/this/?.so
881  */
882 static const char *register_package_cdir(cmd_parms *cmd, 
883                                          void *_cfg,
884                                          const char *arg)
885 {
886     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
887
888     return register_package_helper(cmd, arg, cfg->package_cpaths);
889 }
890
891 static const char *register_lua_inherit(cmd_parms *cmd, 
892                                       void *_cfg,
893                                       const char *arg)
894 {
895     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
896     
897     if (strcasecmp("none", arg) == 0) {
898         cfg->inherit = AP_LUA_INHERIT_NONE;
899     }
900     else if (strcasecmp("parent-first", arg) == 0) {
901         cfg->inherit = AP_LUA_INHERIT_PARENT_FIRST;
902     }
903     else if (strcasecmp("parent-last", arg) == 0) {
904         cfg->inherit = AP_LUA_INHERIT_PARENT_LAST;
905     }
906     else { 
907         return apr_psprintf(cmd->pool,
908                             "LuaInherit type of '%s' not recognized, valid "
909                             "options are 'none', 'parent-first', and 'parent-last'", 
910                             arg);
911     }
912     return NULL;
913 }
914 static const char *register_lua_codecache(cmd_parms *cmd, 
915                                       void *_cfg,
916                                       const char *arg)
917 {
918     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
919     
920     if (strcasecmp("never", arg) == 0) {
921         cfg->codecache = AP_LUA_CACHE_NEVER;
922     }
923     else if (strcasecmp("stat", arg) == 0) {
924         cfg->codecache = AP_LUA_CACHE_STAT;
925     }
926     else if (strcasecmp("forever", arg) == 0) {
927         cfg->codecache = AP_LUA_CACHE_FOREVER;
928     }
929     else { 
930         return apr_psprintf(cmd->pool,
931                             "LuaCodeCache type of '%s' not recognized, valid "
932                             "options are 'never', 'stat', and 'forever'", 
933                             arg);
934     }
935     return NULL;
936 }
937 static const char *register_lua_scope(cmd_parms *cmd, 
938                                       void *_cfg,
939                                       const char *scope, 
940                                       const char *min,
941                                       const char *max)
942 {
943     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
944     if (strcmp("once", scope) == 0) {
945         cfg->vm_scope = AP_LUA_SCOPE_ONCE;
946     }
947     else if (strcmp("request", scope) == 0) {
948         cfg->vm_scope = AP_LUA_SCOPE_REQUEST;
949     }
950     else if (strcmp("conn", scope) == 0) {
951         cfg->vm_scope = AP_LUA_SCOPE_CONN;
952     }
953     else if (strcmp("thread", scope) == 0) {
954 #if !APR_HAS_THREADS
955         return apr_psprintf(cmd->pool,
956                             "Scope type of '%s' cannot be used because this "
957                             "server does not have threading support "
958                             "(APR_HAS_THREADS)" 
959                             scope);
960 #endif
961         cfg->vm_scope = AP_LUA_SCOPE_THREAD;
962     }
963     else {
964         return apr_psprintf(cmd->pool,
965                             "Invalid value for LuaScope, '%s', acceptable "
966                             "values are: 'once', 'request', 'conn', 'server'"
967 #if APR_HAS_THREADS
968                             ", 'thread'"
969 #endif
970                             ,scope);
971     }
972
973     return NULL;
974 }
975
976
977
978 static const char *register_lua_root(cmd_parms *cmd, void *_cfg,
979                                      const char *root)
980 {
981     /* ap_lua_dir_cfg* cfg = (ap_lua_dir_cfg*)_cfg; */
982     ap_lua_server_cfg *cfg = ap_get_module_config(cmd->server->module_config,
983                                                   &lua_module);
984
985     cfg->root_path = root;
986     return NULL;
987 }
988 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)
989 {
990     if (lua_ssl_val) { 
991         return (const char *)lua_ssl_val(p, s, c, r, (char *)var);
992     }
993     return NULL;
994 }
995
996 AP_LUA_DECLARE(int) ap_lua_ssl_is_https(conn_rec *c)
997 {
998     return lua_ssl_is_https ? lua_ssl_is_https(c) : 0;
999 }
1000
1001 /*******************************/
1002
1003 static const char *lua_authz_parse(cmd_parms *cmd, const char *require_line,
1004                                    const void **parsed_require_line)
1005 {
1006     const char *provider_name;
1007     lua_authz_provider_spec *spec;
1008
1009     apr_pool_userdata_get((void**)&provider_name, AUTHZ_PROVIDER_NAME_NOTE,
1010                           cmd->temp_pool);
1011     ap_assert(provider_name != NULL);
1012
1013     spec = apr_hash_get(lua_authz_providers, provider_name, APR_HASH_KEY_STRING);
1014     ap_assert(spec != NULL);
1015
1016     if (require_line && *require_line) {
1017         const char *arg;
1018         spec->args = apr_array_make(cmd->pool, 2, sizeof(const char *));
1019         while ((arg = ap_getword_conf(cmd->pool, &require_line)) && *arg) {
1020             APR_ARRAY_PUSH(spec->args, const char *) = arg;
1021         }
1022     }
1023
1024     *parsed_require_line = spec;
1025     return NULL;
1026 }
1027
1028 static authz_status lua_authz_check(request_rec *r, const char *require_line,
1029                                     const void *parsed_require_line)
1030 {
1031     apr_pool_t *pool;
1032     ap_lua_vm_spec *spec;
1033     lua_State *L;
1034     ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
1035                                                          &lua_module);
1036     const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
1037                                                      &lua_module);
1038     const lua_authz_provider_spec *prov_spec = parsed_require_line;
1039     int result;
1040     int nargs = 0;
1041
1042     spec = create_vm_spec(&pool, r, cfg, server_cfg, prov_spec->file_name,
1043                           NULL, 0, prov_spec->function_name, "authz provider");
1044
1045     L = ap_lua_get_lua_state(pool, spec, r);
1046     if (L == NULL) {
1047         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02314)
1048                       "Unable to compile VM for authz provider %s", prov_spec->name);
1049         return AUTHZ_GENERAL_ERROR;
1050     }
1051     lua_getglobal(L, prov_spec->function_name);
1052     if (!lua_isfunction(L, -1)) {
1053         ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(02319)
1054                       "Unable to find function %s in %s",
1055                       prov_spec->function_name, prov_spec->file_name);
1056         return AUTHZ_GENERAL_ERROR;
1057     }
1058     ap_lua_run_lua_request(L, r);
1059     if (prov_spec->args) {
1060         int i;
1061         if (!lua_checkstack(L, prov_spec->args->nelts)) {
1062             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02315)
1063                           "Error: authz provider %s: too many arguments", prov_spec->name);
1064             return AUTHZ_GENERAL_ERROR;
1065         }
1066         for (i = 0; i < prov_spec->args->nelts; i++) {
1067             const char *arg = APR_ARRAY_IDX(prov_spec->args, i, const char *);
1068             lua_pushstring(L, arg);
1069         }
1070         nargs = prov_spec->args->nelts;
1071     }
1072     if (lua_pcall(L, 1 + nargs, 1, 0)) {
1073         const char *err = lua_tostring(L, -1);
1074         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02316)
1075                       "Error executing authz provider %s: %s", prov_spec->name, err);
1076         return AUTHZ_GENERAL_ERROR;
1077     }
1078     if (!lua_isnumber(L, -1)) {
1079         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02317)
1080                       "Error: authz provider %s did not return integer", prov_spec->name);
1081         return AUTHZ_GENERAL_ERROR;
1082     }
1083     result = lua_tointeger(L, -1);
1084     switch (result) {
1085         case AUTHZ_DENIED:
1086         case AUTHZ_GRANTED:
1087         case AUTHZ_NEUTRAL:
1088         case AUTHZ_GENERAL_ERROR:
1089         case AUTHZ_DENIED_NO_USER:
1090             return result;
1091         default:
1092             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02318)
1093                           "Error: authz provider %s: invalid return value %d",
1094                           prov_spec->name, result);
1095     }
1096     return AUTHZ_GENERAL_ERROR;
1097 }
1098
1099 static const authz_provider lua_authz_provider =
1100 {
1101     &lua_authz_check,
1102     &lua_authz_parse,
1103 };
1104
1105 static const char *register_authz_provider(cmd_parms *cmd, void *_cfg,
1106                                            const char *name, const char *file,
1107                                            const char *function)
1108 {
1109     lua_authz_provider_spec *spec;
1110     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
1111     if (err)
1112         return err;
1113
1114     spec = apr_pcalloc(cmd->pool, sizeof(*spec));
1115     spec->name = name;
1116     spec->file_name = file;
1117     spec->function_name = function;
1118
1119     apr_hash_set(lua_authz_providers, name, APR_HASH_KEY_STRING, spec);
1120     ap_register_auth_provider(cmd->pool, AUTHZ_PROVIDER_GROUP, name,
1121                               AUTHZ_PROVIDER_VERSION,
1122                               &lua_authz_provider,
1123                               AP_AUTH_INTERNAL_PER_CONF);
1124     return NULL;
1125 }
1126
1127
1128 command_rec lua_commands[] = {
1129
1130     AP_INIT_TAKE1("LuaRoot", register_lua_root, NULL, OR_ALL,
1131                   "Specify the base path for resolving relative paths for mod_lua directives"),
1132
1133     AP_INIT_TAKE1("LuaPackagePath", register_package_dir, NULL, OR_ALL,
1134                   "Add a directory to lua's package.path"),
1135
1136     AP_INIT_TAKE1("LuaPackageCPath", register_package_cdir, NULL, OR_ALL,
1137                   "Add a directory to lua's package.cpath"),
1138
1139     AP_INIT_TAKE3("LuaAuthzProvider", register_authz_provider, NULL, RSRC_CONF|EXEC_ON_READ,
1140                   "Provide an authorization provider"),
1141
1142     AP_INIT_TAKE23("LuaHookTranslateName", register_translate_name_hook, NULL,
1143                   OR_ALL,
1144                   "Provide a hook for the translate name phase of request processing"),
1145
1146     AP_INIT_RAW_ARGS("<LuaHookTranslateName", register_translate_name_block,
1147                      NULL,
1148                      EXEC_ON_READ | OR_ALL,
1149                      "Provide a hook for the translate name phase of request processing"),
1150
1151     AP_INIT_TAKE2("LuaHookFixups", register_fixups_hook, NULL, OR_ALL,
1152                   "Provide a hook for the fixups phase of request processing"),
1153     AP_INIT_RAW_ARGS("<LuaHookFixups", register_fixups_block, NULL,
1154                      EXEC_ON_READ | OR_ALL,
1155                      "Provide a inline hook for the fixups phase of request processing"),
1156
1157     /* todo: test */
1158     AP_INIT_TAKE2("LuaHookMapToStorage", register_map_to_storage_hook, NULL,
1159                   OR_ALL,
1160                   "Provide a hook for the map_to_storage phase of request processing"),
1161     AP_INIT_RAW_ARGS("<LuaHookMapToStorage", register_map_to_storage_block,
1162                      NULL,
1163                      EXEC_ON_READ | OR_ALL,
1164                      "Provide a hook for the map_to_storage phase of request processing"),
1165
1166     /* todo: test */
1167     AP_INIT_TAKE23("LuaHookCheckUserID", register_check_user_id_hook, NULL,
1168                   OR_ALL,
1169                   "Provide a hook for the check_user_id phase of request processing"),
1170     AP_INIT_RAW_ARGS("<LuaHookCheckUserID", register_check_user_id_block,
1171                      NULL,
1172                      EXEC_ON_READ | OR_ALL,
1173                      "Provide a hook for the check_user_id phase of request processing"),
1174
1175     /* todo: test */
1176     AP_INIT_TAKE2("LuaHookTypeChecker", register_type_checker_hook, NULL,
1177                   OR_ALL,
1178                   "Provide a hook for the type_checker phase of request processing"),
1179     AP_INIT_RAW_ARGS("<LuaHookTypeChecker", register_type_checker_block, NULL,
1180                      EXEC_ON_READ | OR_ALL,
1181                      "Provide a hook for the type_checker phase of request processing"),
1182
1183     /* todo: test */
1184     AP_INIT_TAKE23("LuaHookAccessChecker", register_access_checker_hook, NULL,
1185                   OR_ALL,
1186                   "Provide a hook for the access_checker phase of request processing"),
1187     AP_INIT_RAW_ARGS("<LuaHookAccessChecker", register_access_checker_block,
1188                      NULL,
1189                      EXEC_ON_READ | OR_ALL,
1190                      "Provide a hook for the access_checker phase of request processing"),
1191
1192     /* todo: test */
1193     AP_INIT_TAKE23("LuaHookAuthChecker", register_auth_checker_hook, NULL,
1194                   OR_ALL,
1195                   "Provide a hook for the auth_checker phase of request processing"),
1196     AP_INIT_RAW_ARGS("<LuaHookAuthChecker", register_auth_checker_block, NULL,
1197                      EXEC_ON_READ | OR_ALL,
1198                      "Provide a hook for the auth_checker phase of request processing"),
1199
1200     /* todo: test */
1201     AP_INIT_TAKE2("LuaHookInsertFilter", register_insert_filter_hook, NULL,
1202                   OR_ALL,
1203                   "Provide a hook for the insert_filter phase of request processing"),
1204
1205     AP_INIT_TAKE123("LuaScope", register_lua_scope, NULL, OR_ALL,
1206                     "One of once, request, conn, server -- default is once"),
1207
1208     AP_INIT_TAKE1("LuaInherit", register_lua_inherit, NULL, OR_ALL,
1209      "Controls how Lua scripts in parent contexts are merged with the current " 
1210      " context: none|parent-last|parent-first (default: parent-first) "),
1211     
1212     AP_INIT_TAKE1("LuaCodeCache", register_lua_codecache, NULL, OR_ALL,
1213      "Controls the behavior of the in-memory code cache " 
1214      " context: stat|forever|never (default: stat) "),
1215
1216     AP_INIT_TAKE2("LuaQuickHandler", register_quick_hook, NULL, OR_ALL,
1217                   "Provide a hook for the quick handler of request processing"),
1218     AP_INIT_RAW_ARGS("<LuaQuickHandler", register_quick_block, NULL,
1219                      EXEC_ON_READ | OR_ALL,
1220                      "Provide a hook for the quick handler of request processing"),
1221     AP_INIT_RAW_ARGS("Lua_____ByteCodeHack", hack_section_handler, NULL,
1222                      OR_ALL,
1223                      "(internal) Byte code handler"),
1224     {NULL}
1225 };
1226
1227
1228 static void *create_dir_config(apr_pool_t *p, char *dir)
1229 {
1230     ap_lua_dir_cfg *cfg = apr_pcalloc(p, sizeof(ap_lua_dir_cfg));
1231     cfg->package_paths = apr_array_make(p, 2, sizeof(char *));
1232     cfg->package_cpaths = apr_array_make(p, 2, sizeof(char *));
1233     cfg->mapped_handlers =
1234         apr_array_make(p, 1, sizeof(ap_lua_mapped_handler_spec *));
1235     cfg->pool = p;
1236     cfg->hooks = apr_hash_make(p);
1237     cfg->dir = apr_pstrdup(p, dir);
1238     cfg->vm_scope = AP_LUA_SCOPE_UNSET;
1239     cfg->codecache = AP_LUA_CACHE_UNSET;
1240
1241     return cfg;
1242 }
1243
1244 static int create_request_config(request_rec *r)
1245 {
1246     ap_lua_request_cfg *cfg = apr_palloc(r->pool, sizeof(ap_lua_request_cfg));
1247     cfg->mapped_request_details = NULL;
1248     cfg->request_scoped_vms = apr_hash_make(r->pool);
1249     ap_set_module_config(r->request_config, &lua_module, cfg);
1250     return OK;
1251 }
1252
1253 static void *create_server_config(apr_pool_t *p, server_rec *s)
1254 {
1255
1256     ap_lua_server_cfg *cfg = apr_pcalloc(p, sizeof(ap_lua_server_cfg));
1257     cfg->vm_reslists = apr_hash_make(p);
1258     apr_thread_rwlock_create(&cfg->vm_reslists_lock, p);
1259     cfg->root_path = NULL;
1260
1261     return cfg;
1262 }
1263
1264 static int lua_request_hook(lua_State *L, request_rec *r)
1265 {
1266     ap_lua_push_request(L, r);
1267     return OK;
1268 }
1269
1270 static int lua_post_config(apr_pool_t *pconf, apr_pool_t *plog,
1271                              apr_pool_t *ptemp, server_rec *s)
1272 {
1273     lua_ssl_val = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
1274     lua_ssl_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
1275     return OK;
1276 }
1277 static void *overlay_hook_specs(apr_pool_t *p,
1278                                         const void *key,
1279                                         apr_ssize_t klen,
1280                                         const void *overlay_val,
1281                                         const void *base_val,
1282                                         const void *data)
1283 {
1284     const apr_array_header_t *overlay_info = (const apr_array_header_t*)overlay_val;
1285     const apr_array_header_t *base_info = (const apr_array_header_t*)base_val;
1286     return apr_array_append(p, base_info, overlay_info);
1287 }
1288
1289 static void *merge_dir_config(apr_pool_t *p, void *basev, void *overridesv)
1290 {
1291     ap_lua_dir_cfg *a, *base, *overrides;
1292
1293     a         = (ap_lua_dir_cfg *)apr_pcalloc(p, sizeof(ap_lua_dir_cfg));
1294     base      = (ap_lua_dir_cfg*)basev;
1295     overrides = (ap_lua_dir_cfg*)overridesv;
1296
1297     a->pool = overrides->pool;
1298     a->dir = apr_pstrdup(p, overrides->dir);
1299
1300     a->vm_scope = (overrides->vm_scope == AP_LUA_SCOPE_UNSET) ? base->vm_scope: overrides->vm_scope;
1301     a->inherit = (overrides->inherit== AP_LUA_INHERIT_UNSET) ? base->inherit : overrides->inherit;
1302     a->codecache = (overrides->codecache== AP_LUA_CACHE_UNSET) ? base->codecache : overrides->codecache;
1303
1304     if (a->inherit == AP_LUA_INHERIT_UNSET || a->inherit == AP_LUA_INHERIT_PARENT_FIRST) { 
1305         a->package_paths = apr_array_append(p, base->package_paths, overrides->package_paths);
1306         a->package_cpaths = apr_array_append(p, base->package_cpaths, overrides->package_cpaths);
1307         a->mapped_handlers = apr_array_append(p, base->mapped_handlers, overrides->mapped_handlers);
1308         a->hooks = apr_hash_merge(p, overrides->hooks, base->hooks, overlay_hook_specs, NULL);
1309     }
1310     else if (a->inherit == AP_LUA_INHERIT_PARENT_LAST) { 
1311         a->package_paths = apr_array_append(p, overrides->package_paths, base->package_paths);
1312         a->package_cpaths = apr_array_append(p, overrides->package_cpaths, base->package_cpaths);
1313         a->mapped_handlers = apr_array_append(p, overrides->mapped_handlers, base->mapped_handlers);
1314         a->hooks = apr_hash_merge(p, base->hooks, overrides->hooks, overlay_hook_specs, NULL);
1315     }
1316     else { 
1317         a->package_paths = overrides->package_paths;
1318         a->package_cpaths = overrides->package_cpaths;
1319         a->mapped_handlers= overrides->mapped_handlers;
1320         a->hooks= overrides->hooks;
1321     }
1322
1323     return a;
1324 }
1325
1326 static void lua_register_hooks(apr_pool_t *p)
1327 {
1328     /* ap_register_output_filter("luahood", luahood, NULL, AP_FTYPE_RESOURCE); */
1329     ap_hook_handler(lua_handler, NULL, NULL, APR_HOOK_MIDDLE);
1330     ap_hook_create_request(create_request_config, NULL, NULL,
1331                            APR_HOOK_MIDDLE);
1332
1333     /* http_request.h hooks */
1334     ap_hook_translate_name(lua_translate_name_harness_first, NULL, NULL,
1335                            AP_LUA_HOOK_FIRST);
1336     ap_hook_translate_name(lua_translate_name_harness, NULL, NULL,
1337                            APR_HOOK_MIDDLE);
1338     ap_hook_translate_name(lua_translate_name_harness_last, NULL, NULL,
1339                            AP_LUA_HOOK_LAST);
1340
1341     ap_hook_fixups(lua_fixup_harness, NULL, NULL, APR_HOOK_MIDDLE);
1342     ap_hook_map_to_storage(lua_map_to_storage_harness, NULL, NULL,
1343                            APR_HOOK_MIDDLE);
1344
1345     ap_hook_check_user_id(lua_check_user_id_harness_first, NULL, NULL,
1346                           AP_LUA_HOOK_FIRST);
1347     ap_hook_check_user_id(lua_check_user_id_harness, NULL, NULL,
1348                            APR_HOOK_MIDDLE);
1349     ap_hook_check_user_id(lua_check_user_id_harness_last, NULL, NULL,
1350                           AP_LUA_HOOK_LAST);
1351
1352     ap_hook_type_checker(lua_type_checker_harness, NULL, NULL,
1353                          APR_HOOK_MIDDLE);
1354
1355     ap_hook_access_checker(lua_access_checker_harness_first, NULL, NULL,
1356                            AP_LUA_HOOK_FIRST);
1357     ap_hook_access_checker(lua_access_checker_harness, NULL, NULL,
1358                            APR_HOOK_MIDDLE);
1359     ap_hook_access_checker(lua_access_checker_harness_last, NULL, NULL,
1360                            AP_LUA_HOOK_LAST);
1361     ap_hook_auth_checker(lua_auth_checker_harness_first, NULL, NULL,
1362                          AP_LUA_HOOK_FIRST);
1363     ap_hook_auth_checker(lua_auth_checker_harness, NULL, NULL,
1364                          APR_HOOK_MIDDLE);
1365     ap_hook_auth_checker(lua_auth_checker_harness_last, NULL, NULL,
1366                          AP_LUA_HOOK_LAST);
1367
1368     ap_hook_insert_filter(lua_insert_filter_harness, NULL, NULL,
1369                           APR_HOOK_MIDDLE);
1370     ap_hook_quick_handler(lua_quick_harness, NULL, NULL, APR_HOOK_FIRST);
1371
1372     ap_hook_post_config(lua_post_config, NULL, NULL, APR_HOOK_MIDDLE);
1373
1374     APR_OPTIONAL_HOOK(ap_lua, lua_open, lua_open_hook, NULL, NULL,
1375                       APR_HOOK_REALLY_FIRST);
1376
1377     APR_OPTIONAL_HOOK(ap_lua, lua_request, lua_request_hook, NULL, NULL,
1378                       APR_HOOK_REALLY_FIRST);
1379
1380     /* providers */
1381     lua_authz_providers = apr_hash_make(p);
1382 }
1383
1384 AP_DECLARE_MODULE(lua) = {
1385     STANDARD20_MODULE_STUFF,
1386     create_dir_config,          /* create per-dir    config structures */
1387     merge_dir_config,           /* merge  per-dir    config structures */
1388     create_server_config,       /* create per-server config structures */
1389     NULL,                       /* merge  per-server config structures */
1390     lua_commands,               /* table of config file commands       */
1391     lua_register_hooks          /* register hooks                      */
1392 };