]> granicus.if.org Git - apache/blob - modules/lua/mod_lua.c
C99 and unused variable warnings
[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
28 #ifdef APR_HAS_THREADS
29 #include "apr_thread_proc.h"
30 #endif
31
32 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap_lua, AP_LUA, int, lua_open,
33                                     (lua_State *L, apr_pool_t *p),
34                                     (L, p), OK, DECLINED)
35
36 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap_lua, AP_LUA, int, lua_request,
37                                     (lua_State *L, request_rec *r),
38                                     (L, r), OK, DECLINED)
39 static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *lua_ssl_val = NULL;
40 static APR_OPTIONAL_FN_TYPE(ssl_is_https) *lua_ssl_is_https = NULL;
41
42      module AP_MODULE_DECLARE_DATA lua_module;
43
44 #define AP_LUA_HOOK_FIRST (APR_HOOK_FIRST - 1)
45 #define AP_LUA_HOOK_LAST  (APR_HOOK_LAST  + 1)
46
47 /**
48  * error reporting if lua has an error.
49  * Extracts the error from lua stack and prints
50  */
51 static void report_lua_error(lua_State *L, request_rec *r)
52 {
53     const char *lua_response;
54     r->status = HTTP_INTERNAL_SERVER_ERROR;
55     r->content_type = "text/html";
56
57     ap_rputs("<b>Error!</b>\n", r);
58     ap_rputs("<p>", r);
59     lua_response = lua_tostring(L, -1);
60     ap_rputs(lua_response, r);
61     ap_rputs("</p>\n", r);
62
63     ap_log_perror(APLOG_MARK, APLOG_WARNING, 0, r->pool, "Lua error: %s",
64                   lua_response);
65 }
66
67 static void lua_open_callback(lua_State *L, apr_pool_t *p, void *ctx)
68 {
69     ap_lua_init(L, p);
70     ap_lua_load_apache2_lmodule(L);
71     ap_lua_load_request_lmodule(L, p);
72     ap_lua_load_config_lmodule(L);
73 }
74
75 static int lua_open_hook(lua_State *L, apr_pool_t *p)
76 {
77     lua_open_callback(L, p, NULL);
78     return OK;
79 }
80
81
82 /**
83  * "main"
84  */
85 static int lua_handler(request_rec *r)
86 {
87     ap_lua_dir_cfg *dcfg;
88     apr_pool_t *pool;
89     if (strcmp(r->handler, "lua-script")) {
90         return DECLINED;
91     }
92   
93     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "handling [%s] in mod_lua",
94                   r->filename);
95     dcfg = ap_get_module_config(r->per_dir_config, &lua_module);
96
97     if (!r->header_only) {
98         lua_State *L;
99         const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
100                                                          &lua_module);
101         ap_lua_vm_spec *spec = NULL;
102
103         spec = apr_pcalloc(r->pool, sizeof(ap_lua_vm_spec));
104         spec->scope = dcfg->vm_scope;
105         spec->pool = r->pool;
106         spec->file = r->filename;
107         spec->package_paths = cfg->package_paths;
108         spec->package_cpaths = cfg->package_cpaths;
109         spec->cb = &lua_open_callback;
110         spec->cb_arg = NULL;
111       
112         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
113                       "request details scope:%u, filename:%s, function:%s",
114                       spec->scope,
115                       spec->file,
116                       "handle");
117
118         switch (dcfg->vm_scope) {
119         case AP_LUA_SCOPE_ONCE:
120           apr_pool_create(&pool, r->pool);
121           break;
122         case AP_LUA_SCOPE_REQUEST:
123           pool = r->pool;
124           break;
125         case AP_LUA_SCOPE_CONN:
126           pool = r->connection->pool;
127           break;
128         case AP_LUA_SCOPE_THREAD:
129           #if APR_HAS_THREADS
130           pool = apr_thread_pool_get(r->connection->current_thread);
131           break;
132           #endif
133         }
134
135         L = ap_lua_get_lua_state(pool,
136                                  spec);
137         
138         if (!L) {
139             /* TODO annotate spec with failure reason */
140             r->status = HTTP_INTERNAL_SERVER_ERROR;
141             ap_rputs("Unable to compile VM, see logs", r);
142             return HTTP_INTERNAL_SERVER_ERROR;
143         }
144         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "got a vm!");
145         lua_getglobal(L, "handle");
146         if (!lua_isfunction(L, -1)) {
147             ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
148                           "lua: Unable to find function %s in %s",
149                           "handle",
150                           spec->file);
151             return HTTP_INTERNAL_SERVER_ERROR;
152         }
153         ap_lua_run_lua_request(L, r);
154         if (lua_pcall(L, 1, 0, 0)) {
155             report_lua_error(L, r);
156         }
157     }
158     return OK;
159 }
160
161
162
163
164 /* ---------------- Configury stuff --------------- */
165
166 /** harnesses for magic hooks **/
167
168 static int lua_request_rec_hook_harness(request_rec *r, const char *name, int apr_hook_when)
169 {
170     int rc;
171     lua_State *L;
172     ap_lua_vm_spec *spec;
173     ap_lua_server_cfg *server_cfg = ap_get_module_config(r->server->module_config,
174                                                          &lua_module);
175     const ap_lua_dir_cfg *cfg = ap_get_module_config(r->per_dir_config,
176                                                      &lua_module);
177     const char *key = apr_psprintf(r->pool, "%s_%d", name, apr_hook_when);
178     apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
179                                                   APR_HASH_KEY_STRING);
180     if (hook_specs) {
181         int i;
182         for (i = 0; i < hook_specs->nelts; i++) {
183             ap_lua_mapped_handler_spec *hook_spec =
184                 ((ap_lua_mapped_handler_spec **) hook_specs->elts)[i];
185
186             if (hook_spec == NULL) {
187                 continue;
188             }
189             spec = apr_pcalloc(r->pool, sizeof(ap_lua_vm_spec));
190
191             spec->file = hook_spec->file_name;
192             spec->scope = hook_spec->scope;
193             spec->bytecode = hook_spec->bytecode;
194             spec->bytecode_len = hook_spec->bytecode_len;
195             spec->pool = r->pool;
196             spec->package_paths = cfg->package_paths;
197             spec->package_cpaths = cfg->package_cpaths;
198             spec->cb = &lua_open_callback;
199             spec->cb_arg = NULL;
200
201             apr_filepath_merge(&spec->file, server_cfg->root_path,
202                                spec->file, APR_FILEPATH_NOTRELATIVE, r->pool);
203             L = ap_lua_get_lua_state(r->pool, spec);
204
205             if (!L) {
206                 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
207                               "lua: Failed to obtain lua interpreter for %s %s",
208                               hook_spec->function_name, hook_spec->file_name);
209                 return HTTP_INTERNAL_SERVER_ERROR;
210             }
211
212             if (hook_spec->function_name != NULL) {
213                 lua_getglobal(L, hook_spec->function_name);
214                 if (!lua_isfunction(L, -1)) {
215                     ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
216                                   "lua: Unable to find function %s in %s",
217                                   hook_spec->function_name,
218                                   hook_spec->file_name);
219                     return HTTP_INTERNAL_SERVER_ERROR;
220                 }
221
222                 ap_lua_run_lua_request(L, r);
223             }
224             else {
225                 int t;
226                 ap_lua_run_lua_request(L, r);
227
228                 t = lua_gettop(L);
229                 lua_setglobal(L, "r");
230                 lua_settop(L, t);
231             }
232
233             if (lua_pcall(L, 1, 1, 0)) {
234                 report_lua_error(L, r);
235                 return HTTP_INTERNAL_SERVER_ERROR;
236             }
237             rc = DECLINED;
238             if (lua_isnumber(L, -1)) {
239                 rc = lua_tointeger(L, -1);
240             }
241             if (rc != DECLINED) {
242                 return rc;
243             }
244         }
245     }
246     return DECLINED;
247 }
248
249
250 static apr_size_t config_getstr(ap_configfile_t *cfg, char *buf,
251                                 size_t bufsiz)
252 {
253     apr_size_t i = 0;
254
255     if (cfg->getstr) {
256         apr_status_t rc = (cfg->getstr) (buf, bufsiz, cfg->param);
257         if (rc == APR_SUCCESS) {
258             i = strlen(buf);
259             if (i && buf[i - 1] == '\n')
260                 ++cfg->line_number;
261         }
262         else {
263             buf[0] = '\0';
264             i = 0;
265         }
266     }
267     else {
268         while (i < bufsiz) {
269             char ch;
270             apr_status_t rc = (cfg->getch) (&ch, cfg->param);
271             if (rc != APR_SUCCESS)
272                 break;
273             buf[i++] = ch;
274             if (ch == '\n') {
275                 ++cfg->line_number;
276                 break;
277             }
278         }
279     }
280     return i;
281 }
282
283 typedef struct cr_ctx
284 {
285     cmd_parms *cmd;
286     ap_configfile_t *cfp;
287     size_t startline;
288     const char *endstr;
289     char buf[HUGE_STRING_LEN];
290 } cr_ctx;
291
292
293 /* Okay, this deserves a little explaination -- in order for the errors that lua
294  * generates to be 'accuarate', including line numbers, we basically inject
295  * N line number new lines into the 'top' of the chunk reader.....
296  *
297  * be happy. this is cool.
298  *
299  */
300 static const char *lf =
301     "\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";
302 #define N_LF 32
303
304 static const char *direct_chunkreader(lua_State *lvm, void *udata,
305                                       size_t *plen)
306 {
307     const char *p;
308     struct cr_ctx *ctx = udata;
309
310     if (ctx->startline) {
311         *plen = ctx->startline > N_LF ? N_LF : ctx->startline;
312         ctx->startline -= *plen;
313         return lf;
314     }
315     *plen = config_getstr(ctx->cfp, ctx->buf, HUGE_STRING_LEN);
316
317     for (p = ctx->buf; isspace(*p); ++p);
318     if (p[0] == '<' && p[1] == '/') {
319         apr_size_t i = 0;
320         while (i < strlen(ctx->endstr)) {
321             if (tolower(p[i + 2]) != ctx->endstr[i])
322                 return ctx->buf;
323             ++i;
324         }
325         *plen = 0;
326         return NULL;
327     }
328     /*fprintf(stderr, "buf read: %s\n", ctx->buf); */
329     return ctx->buf;
330 }
331
332 static int ldump_writer(lua_State *L, const void *b, size_t size, void *B)
333 {
334     (void) L;
335     luaL_addlstring((luaL_Buffer *) B, (const char *) b, size);
336     return 0;
337 }
338
339 typedef struct hack_section_baton
340 {
341     const char *name;
342     ap_lua_mapped_handler_spec *spec;
343     int apr_hook_when;
344 } hack_section_baton;
345
346 /* You can be unhappy now.
347  *
348  * This is uncool.
349  *
350  * When you create a <Section handler in httpd, the only 'easy' way to create
351  * a directory context is to parse the section, and convert it into a 'normal'
352  * Configureation option, and then collapse the entire section, in memory,
353  * back into the parent section -- from which you can then get the new directive
354  * invoked.... anyways. evil. Rici taught me how to do this hack :-)
355  */
356 static const char *hack_section_handler(cmd_parms *cmd, void *_cfg,
357                                         const char *arg)
358 {
359     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
360     ap_directive_t *directive = cmd->directive;
361     hack_section_baton *baton = directive->data;
362     const char *key = apr_psprintf(cmd->pool, "%s_%d", baton->name, baton->apr_hook_when);
363
364     apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
365                                                   APR_HASH_KEY_STRING);
366     if (!hook_specs) {
367         hook_specs = apr_array_make(cmd->pool, 2,
368                                     sizeof(ap_lua_mapped_handler_spec *));
369         apr_hash_set(cfg->hooks, key,
370                      APR_HASH_KEY_STRING, hook_specs);
371     }
372
373     baton->spec->scope = cfg->vm_scope;
374
375     *(ap_lua_mapped_handler_spec **) apr_array_push(hook_specs) = baton->spec;
376
377     return NULL;
378 }
379
380 static const char *register_named_block_function_hook(const char *name,
381                                                       cmd_parms *cmd,
382                                                       void *mconfig,
383                                                       const char *line)
384 {
385     const char *function = NULL;
386     ap_lua_mapped_handler_spec *spec;
387     int when = APR_HOOK_MIDDLE;
388     const char *endp = ap_strrchr_c(line, '>');
389
390     if (endp == NULL) {
391         return apr_pstrcat(cmd->pool, cmd->cmd->name,
392                            "> directive missing closing '>'", NULL);
393     }
394
395     line = apr_pstrndup(cmd->temp_pool, line, endp - line);
396
397     if (line[0]) { 
398         const char *word;
399         word = ap_getword_conf(cmd->temp_pool, &line);
400         if (word && *word) {
401             function = apr_pstrdup(cmd->pool, word);
402         }
403         word = ap_getword_conf(cmd->temp_pool, &line);
404         if (word && *word) {
405             if (!strcasecmp("early", word)) { 
406                 when = AP_LUA_HOOK_FIRST;
407             }
408             else if (!strcasecmp("late", word)) {
409                 when = AP_LUA_HOOK_LAST;
410             }
411             else { 
412                 return apr_pstrcat(cmd->pool, cmd->cmd->name,
413                                    "> 2nd argument must be 'early' or 'late'", NULL);
414             }
415         }
416     }
417
418     spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec));
419
420     {
421         cr_ctx ctx;
422         char buf[32];
423         lua_State *lvm;
424         char *tmp;
425         int rv;
426         ap_directive_t **current;
427         hack_section_baton *baton;
428
429         apr_snprintf(buf, sizeof(buf), "%u", cmd->config_file->line_number);
430         spec->file_name = apr_pstrcat(cmd->pool, cmd->config_file->name, ":",
431                                       buf, NULL);
432         if (function) {
433             spec->function_name = (char *) function;
434         }
435         else {
436             function = NULL;
437         }
438
439         ctx.cmd = cmd;
440         tmp = apr_pstrdup(cmd->pool, cmd->err_directive->directive + 1);
441         ap_str_tolower(tmp);
442         ctx.endstr = tmp;
443         ctx.cfp = cmd->config_file;
444         ctx.startline = cmd->config_file->line_number;
445
446         /* This lua State is used only to compile the input strings -> bytecode, so we don't need anything extra. */
447         lvm = luaL_newstate();
448
449         lua_settop(lvm, 0);
450
451         rv = lua_load(lvm, direct_chunkreader, &ctx, spec->file_name);
452
453         if (rv != 0) {
454             const char *errstr = apr_pstrcat(cmd->pool, "Lua Error:",
455                                              lua_tostring(lvm, -1), NULL);
456             lua_close(lvm);
457             return errstr;
458         }
459         else {
460             luaL_Buffer b;
461             luaL_buffinit(lvm, &b);
462             lua_dump(lvm, ldump_writer, &b);
463             luaL_pushresult(&b);
464             spec->bytecode_len = lua_strlen(lvm, -1);
465             spec->bytecode = apr_pstrmemdup(cmd->pool, lua_tostring(lvm, -1),
466                                             spec->bytecode_len);
467             lua_close(lvm);
468         }
469
470         current = mconfig;
471
472         /* Here, we have to replace our current config node for the next pass */
473         if (!*current) {
474             *current = apr_pcalloc(cmd->pool, sizeof(**current));
475         }
476
477         baton = apr_pcalloc(cmd->pool, sizeof(hack_section_baton));
478         baton->name = name;
479         baton->spec = spec;
480         baton->apr_hook_when = when;
481
482         (*current)->filename = cmd->config_file->name;
483         (*current)->line_num = cmd->config_file->line_number;
484         (*current)->directive = apr_pstrdup(cmd->pool, "Lua_____ByteCodeHack");
485         (*current)->args = NULL;
486         (*current)->data = baton;
487     }
488
489     return NULL;
490 }
491
492 static const char *register_named_file_function_hook(const char *name,
493                                                      cmd_parms *cmd,
494                                                      void *_cfg,
495                                                      const char *file,
496                                                      const char *function,
497                                                      int apr_hook_when)
498 {
499     ap_lua_mapped_handler_spec *spec;
500     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
501     const char *key = apr_psprintf(cmd->pool, "%s_%d", name, apr_hook_when);
502     apr_array_header_t *hook_specs = apr_hash_get(cfg->hooks, key,
503                                                   APR_HASH_KEY_STRING);
504
505     if (!hook_specs) {
506         hook_specs = apr_array_make(cmd->pool, 2,
507                                     sizeof(ap_lua_mapped_handler_spec *));
508         apr_hash_set(cfg->hooks, key, APR_HASH_KEY_STRING, hook_specs);
509     }
510
511     spec = apr_pcalloc(cmd->pool, sizeof(ap_lua_mapped_handler_spec));
512     spec->file_name = apr_pstrdup(cmd->pool, file);
513     spec->function_name = apr_pstrdup(cmd->pool, function);
514     spec->scope = cfg->vm_scope;
515
516     *(ap_lua_mapped_handler_spec **) apr_array_push(hook_specs) = spec;
517     return NULL;
518 }
519
520 static int lua_check_user_id_harness_first(request_rec *r)
521 {
522     return lua_request_rec_hook_harness(r, "check_user_id", AP_LUA_HOOK_FIRST);
523 }
524 static int lua_check_user_id_harness(request_rec *r)
525 {
526     return lua_request_rec_hook_harness(r, "check_user_id", APR_HOOK_MIDDLE);
527 }
528 static int lua_check_user_id_harness_last(request_rec *r)
529 {
530     return lua_request_rec_hook_harness(r, "check_user_id", AP_LUA_HOOK_LAST);
531 }
532
533 static int lua_translate_name_harness_first(request_rec *r)
534 {
535     return lua_request_rec_hook_harness(r, "translate_name", AP_LUA_HOOK_FIRST);
536 }
537 static int lua_translate_name_harness(request_rec *r)
538 {
539     return lua_request_rec_hook_harness(r, "translate_name", APR_HOOK_MIDDLE);
540 }
541 static int lua_translate_name_harness_last(request_rec *r)
542 {
543     return lua_request_rec_hook_harness(r, "translate_name", AP_LUA_HOOK_LAST);
544 }
545
546 static int lua_fixup_harness(request_rec *r)
547 {
548     return lua_request_rec_hook_harness(r, "fixups", APR_HOOK_MIDDLE);
549 }
550
551 static int lua_map_to_storage_harness(request_rec *r)
552 {
553     return lua_request_rec_hook_harness(r, "map_to_storage", APR_HOOK_MIDDLE);
554 }
555
556 static int lua_type_checker_harness(request_rec *r)
557 {
558     return lua_request_rec_hook_harness(r, "type_checker", APR_HOOK_MIDDLE);
559 }
560
561 static int lua_access_checker_harness_first(request_rec *r)
562 {
563     return lua_request_rec_hook_harness(r, "access_checker", AP_LUA_HOOK_FIRST);
564 }
565 static int lua_access_checker_harness(request_rec *r)
566 {
567     return lua_request_rec_hook_harness(r, "access_checker", APR_HOOK_MIDDLE);
568 }
569 static int lua_access_checker_harness_last(request_rec *r)
570 {
571     return lua_request_rec_hook_harness(r, "access_checker", AP_LUA_HOOK_LAST);
572 }
573
574 static int lua_auth_checker_harness_first(request_rec *r)
575 {
576     return lua_request_rec_hook_harness(r, "auth_checker", AP_LUA_HOOK_FIRST);
577 }
578 static int lua_auth_checker_harness(request_rec *r)
579 {
580     return lua_request_rec_hook_harness(r, "auth_checker", APR_HOOK_MIDDLE);
581 }
582 static int lua_auth_checker_harness_last(request_rec *r)
583 {
584     return lua_request_rec_hook_harness(r, "auth_checker", AP_LUA_HOOK_LAST);
585 }
586 static void lua_insert_filter_harness(request_rec *r)
587 {
588     /* ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "LuaHookInsertFilter not yet implemented"); */
589 }
590
591 static int lua_quick_harness(request_rec *r, int lookup)
592 {
593     if (lookup) {
594         return DECLINED;
595     }
596     return lua_request_rec_hook_harness(r, "quick", APR_HOOK_MIDDLE);
597 }
598
599 static const char *register_translate_name_hook(cmd_parms *cmd, void *_cfg,
600                                                 const char *file,
601                                                 const char *function,
602                                                 const char *when)
603 {
604     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
605                                            NOT_IN_HTACCESS);
606     int apr_hook_when = APR_HOOK_MIDDLE;
607     if (err) {
608         return err;
609     }
610     
611     if (when) { 
612         if (!strcasecmp(when, "early")) { 
613             apr_hook_when = AP_LUA_HOOK_FIRST;
614         } 
615         else if (!strcasecmp(when, "late")) { 
616             apr_hook_when = AP_LUA_HOOK_LAST;
617         } 
618         else { 
619             return "Third argument must be 'early' or 'late'";
620         }
621     }
622
623     return register_named_file_function_hook("translate_name", cmd, _cfg,
624                                              file, function, apr_hook_when);
625 }
626
627 static const char *register_translate_name_block(cmd_parms *cmd, void *_cfg,
628                                                  const char *line)
629 {
630     return register_named_block_function_hook("translate_name", cmd, _cfg,
631                                               line);
632 }
633
634
635 static const char *register_fixups_hook(cmd_parms *cmd, void *_cfg,
636                                         const char *file,
637                                         const char *function)
638 {
639     return register_named_file_function_hook("fixups", cmd, _cfg, file,
640                                              function, APR_HOOK_MIDDLE);
641 }
642 static const char *register_fixups_block(cmd_parms *cmd, void *_cfg,
643                                          const char *line)
644 {
645     return register_named_block_function_hook("fixups", cmd, _cfg, line);
646 }
647
648 static const char *register_map_to_storage_hook(cmd_parms *cmd, void *_cfg,
649                                                 const char *file,
650                                                 const char *function)
651 {
652     return register_named_file_function_hook("map_to_storage", cmd, _cfg,
653                                              file, function, APR_HOOK_MIDDLE);
654 }
655 static const char *register_map_to_storage_block(cmd_parms *cmd, void *_cfg,
656                                                  const char *line)
657 {
658     return register_named_block_function_hook("map_to_storage", cmd, _cfg,
659                                               line);
660 }
661
662 static const char *register_check_user_id_hook(cmd_parms *cmd, void *_cfg,
663                                                const char *file,
664                                                const char *function,
665                                                const char *when)
666 {
667     int apr_hook_when = APR_HOOK_MIDDLE;
668
669     if (when) {
670         if (!strcasecmp(when, "early")) {
671             apr_hook_when = AP_LUA_HOOK_FIRST;
672         }
673         else if (!strcasecmp(when, "late")) {
674             apr_hook_when = AP_LUA_HOOK_LAST;
675         }
676         else {
677             return "Third argument must be 'early' or 'late'";
678         }
679     }
680
681     return register_named_file_function_hook("check_user_id", cmd, _cfg, file,
682                                              function, apr_hook_when);
683 }
684 static const char *register_check_user_id_block(cmd_parms *cmd, void *_cfg,
685                                                 const char *line)
686 {
687     return register_named_block_function_hook("check_user_id", cmd, _cfg,
688                                               line);
689 }
690
691 static const char *register_type_checker_hook(cmd_parms *cmd, void *_cfg,
692                                               const char *file,
693                                               const char *function)
694 {
695     return register_named_file_function_hook("type_checker", cmd, _cfg, file,
696                                              function, APR_HOOK_MIDDLE);
697 }
698 static const char *register_type_checker_block(cmd_parms *cmd, void *_cfg,
699                                                const char *line)
700 {
701     return register_named_block_function_hook("type_checker", cmd, _cfg,
702                                               line);
703 }
704
705 static const char *register_access_checker_hook(cmd_parms *cmd, void *_cfg,
706                                                 const char *file,
707                                                 const char *function,
708                                                 const char *when)
709 {
710     int apr_hook_when = APR_HOOK_MIDDLE;
711
712     if (when) {
713         if (!strcasecmp(when, "early")) {
714             apr_hook_when = AP_LUA_HOOK_FIRST;
715         }
716         else if (!strcasecmp(when, "late")) {
717             apr_hook_when = AP_LUA_HOOK_LAST;
718         }
719         else {
720             return "Third argument must be 'early' or 'late'";
721         }
722     }
723
724     return register_named_file_function_hook("access_checker", cmd, _cfg,
725                                              file, function, apr_hook_when);
726 }
727 static const char *register_access_checker_block(cmd_parms *cmd, void *_cfg,
728                                                  const char *line)
729 {
730
731     return register_named_block_function_hook("access_checker", cmd, _cfg,
732                                               line);
733 }
734
735 static const char *register_auth_checker_hook(cmd_parms *cmd, void *_cfg,
736                                               const char *file,
737                                               const char *function,
738                                               const char *when)
739 {
740     int apr_hook_when = APR_HOOK_MIDDLE;
741
742     if (when) {
743         if (!strcasecmp(when, "early")) {
744             apr_hook_when = AP_LUA_HOOK_FIRST;
745         }
746         else if (!strcasecmp(when, "late")) {
747             apr_hook_when = AP_LUA_HOOK_LAST;
748         }
749         else {
750             return "Third argument must be 'early' or 'late'";
751         }
752     }
753
754     return register_named_file_function_hook("auth_checker", cmd, _cfg, file,
755                                              function, apr_hook_when);
756 }
757 static const char *register_auth_checker_block(cmd_parms *cmd, void *_cfg,
758                                                const char *line)
759 {
760     return register_named_block_function_hook("auth_checker", cmd, _cfg,
761                                               line);
762 }
763
764 static const char *register_insert_filter_hook(cmd_parms *cmd, void *_cfg,
765                                                const char *file,
766                                                const char *function)
767 {
768     return "LuaHookInsertFilter not yet implemented";
769 }
770
771 static const char *register_quick_hook(cmd_parms *cmd, void *_cfg,
772                                        const char *file, const char *function)
773 {
774     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIRECTORY|NOT_IN_FILES|
775                                                 NOT_IN_HTACCESS);
776     if (err) {
777         return err;
778     }
779     return register_named_file_function_hook("quick", cmd, _cfg, file,
780                                              function, APR_HOOK_MIDDLE);
781 }
782 static const char *register_quick_block(cmd_parms *cmd, void *_cfg,
783                                         const char *line)
784 {
785     return register_named_block_function_hook("quick", cmd, _cfg,
786                                               line);
787 }
788
789
790
791 static const char *register_package_helper(cmd_parms *cmd, 
792                                            const char *arg,
793                                            apr_array_header_t *dir_array)
794 {
795     apr_status_t rv;
796
797     ap_lua_server_cfg *server_cfg =
798         ap_get_module_config(cmd->server->module_config, &lua_module);
799
800     char *fixed_filename;
801     rv = apr_filepath_merge(&fixed_filename, 
802                             server_cfg->root_path, 
803                             arg,
804                             APR_FILEPATH_NOTRELATIVE, 
805                             cmd->pool);
806
807     if (rv != APR_SUCCESS) {
808         return apr_psprintf(cmd->pool,
809                             "Unable to build full path to file, %s", arg);
810     }
811
812     *(const char **) apr_array_push(dir_array) = fixed_filename;
813     return NULL;
814 }
815
816
817 /**
818  * Called for config directive which looks like
819  * LuaPackagePath /lua/package/path/mapped/thing/like/this/?.lua
820  */
821 static const char *register_package_dir(cmd_parms *cmd, void *_cfg,
822                                         const char *arg)
823 {
824     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
825
826     return register_package_helper(cmd, arg, cfg->package_paths);
827 }
828
829 /**
830  * Called for config directive which looks like
831  * LuaPackageCPath /lua/package/path/mapped/thing/like/this/?.so
832  */
833 static const char *register_package_cdir(cmd_parms *cmd, 
834                                          void *_cfg,
835                                          const char *arg)
836 {
837     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
838
839     return register_package_helper(cmd, arg, cfg->package_cpaths);
840 }
841
842
843 static const char *register_lua_scope(cmd_parms *cmd, 
844                                       void *_cfg,
845                                       const char *scope, 
846                                       const char *min,
847                                       const char *max)
848 {
849     ap_lua_dir_cfg *cfg = (ap_lua_dir_cfg *) _cfg;
850     if (strcmp("once", scope) == 0) {
851         cfg->vm_scope = AP_LUA_SCOPE_ONCE;
852     }
853     else if (strcmp("request", scope) == 0) {
854         cfg->vm_scope = AP_LUA_SCOPE_REQUEST;
855     }
856     else if (strcmp("conn", scope) == 0) {
857         cfg->vm_scope = AP_LUA_SCOPE_CONN;
858     }
859     else if (strcmp("thread", scope) == 0) {
860         cfg->vm_scope = AP_LUA_SCOPE_THREAD;
861     }
862     else {
863         return apr_psprintf(cmd->pool,
864                             "Invalid value for LuaScope, '%s', acceptable "
865                             "values are 'once', 'request', 'conn', and "
866                             "'server'",
867                             scope);
868     }
869     return NULL;
870 }
871
872
873
874 static const char *register_lua_root(cmd_parms *cmd, void *_cfg,
875                                      const char *root)
876 {
877     /* ap_lua_dir_cfg* cfg = (ap_lua_dir_cfg*)_cfg; */
878     ap_lua_server_cfg *cfg = ap_get_module_config(cmd->server->module_config,
879                                                   &lua_module);
880
881     cfg->root_path = root;
882     return NULL;
883 }
884 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)
885 {
886     if (lua_ssl_val) { 
887         return (const char *)lua_ssl_val(p, s, c, r, (char *)var);
888     }
889     return NULL;
890 }
891
892 AP_LUA_DECLARE(int) ap_lua_ssl_is_https(conn_rec *c)
893 {
894     return lua_ssl_is_https ? lua_ssl_is_https(c) : 0;
895 }
896
897 /*******************************/
898
899 command_rec lua_commands[] = {
900
901     AP_INIT_TAKE1("LuaRoot", register_lua_root, NULL, OR_ALL,
902                   "Specify the base path for resolving relative paths for mod_lua directives"),
903
904     AP_INIT_TAKE1("LuaPackagePath", register_package_dir, NULL, OR_ALL,
905                   "Add a directory to lua's package.path"),
906
907     AP_INIT_TAKE1("LuaPackageCPath", register_package_cdir, NULL, OR_ALL,
908                   "Add a directory to lua's package.cpath"),
909
910
911     AP_INIT_TAKE23("LuaHookTranslateName", register_translate_name_hook, NULL,
912                   OR_ALL,
913                   "Provide a hook for the translate name phase of request processing"),
914
915     AP_INIT_RAW_ARGS("<LuaHookTranslateName", register_translate_name_block,
916                      NULL,
917                      EXEC_ON_READ | OR_ALL,
918                      "Provide a hook for the translate name phase of request processing"),
919
920     AP_INIT_TAKE2("LuaHookFixups", register_fixups_hook, NULL, OR_ALL,
921                   "Provide a hook for the fixups phase of request processing"),
922     AP_INIT_RAW_ARGS("<LuaHookFixups", register_fixups_block, NULL,
923                      EXEC_ON_READ | OR_ALL,
924                      "Provide a inline hook for the fixups phase of request processing"),
925
926     /* todo: test */
927     AP_INIT_TAKE2("LuaHookMapToStorage", register_map_to_storage_hook, NULL,
928                   OR_ALL,
929                   "Provide a hook for the map_to_storage phase of request processing"),
930     AP_INIT_RAW_ARGS("<LuaHookMapToStorage", register_map_to_storage_block,
931                      NULL,
932                      EXEC_ON_READ | OR_ALL,
933                      "Provide a hook for the map_to_storage phase of request processing"),
934
935     /* todo: test */
936     AP_INIT_TAKE23("LuaHookCheckUserID", register_check_user_id_hook, NULL,
937                   OR_ALL,
938                   "Provide a hook for the check_user_id phase of request processing"),
939     AP_INIT_RAW_ARGS("<LuaHookCheckUserID", register_check_user_id_block,
940                      NULL,
941                      EXEC_ON_READ | OR_ALL,
942                      "Provide a hook for the check_user_id phase of request processing"),
943
944     /* todo: test */
945     AP_INIT_TAKE2("LuaHookTypeChecker", register_type_checker_hook, NULL,
946                   OR_ALL,
947                   "Provide a hook for the type_checker phase of request processing"),
948     AP_INIT_RAW_ARGS("<LuaHookTypeChecker", register_type_checker_block, NULL,
949                      EXEC_ON_READ | OR_ALL,
950                      "Provide a hook for the type_checker phase of request processing"),
951
952     /* todo: test */
953     AP_INIT_TAKE23("LuaHookAccessChecker", register_access_checker_hook, NULL,
954                   OR_ALL,
955                   "Provide a hook for the access_checker phase of request processing"),
956     AP_INIT_RAW_ARGS("<LuaHookAccessChecker", register_access_checker_block,
957                      NULL,
958                      EXEC_ON_READ | OR_ALL,
959                      "Provide a hook for the access_checker phase of request processing"),
960
961     /* todo: test */
962     AP_INIT_TAKE23("LuaHookAuthChecker", register_auth_checker_hook, NULL,
963                   OR_ALL,
964                   "Provide a hook for the auth_checker phase of request processing"),
965     AP_INIT_RAW_ARGS("<LuaHookAuthChecker", register_auth_checker_block, NULL,
966                      EXEC_ON_READ | OR_ALL,
967                      "Provide a hook for the auth_checker phase of request processing"),
968
969     /* todo: test */
970     AP_INIT_TAKE2("LuaHookInsertFilter", register_insert_filter_hook, NULL,
971                   OR_ALL,
972                   "Provide a hook for the insert_filter phase of request processing"),
973
974     AP_INIT_TAKE123("LuaScope", register_lua_scope, NULL, OR_ALL,
975                     "One of once, request, conn, server -- default is once"),
976
977     AP_INIT_TAKE2("LuaQuickHandler", register_quick_hook, NULL, OR_ALL,
978                   "Provide a hook for the quick handler of request processing"),
979     AP_INIT_RAW_ARGS("<LuaQuickHandler", register_quick_block, NULL,
980                      EXEC_ON_READ | OR_ALL,
981                      "Provide a hook for the quick handler of request processing"),
982     AP_INIT_RAW_ARGS("Lua_____ByteCodeHack", hack_section_handler, NULL,
983                      OR_ALL,
984                      "(internal) Byte code handler"),
985     {NULL}
986 };
987
988
989 static void *create_dir_config(apr_pool_t *p, char *dir)
990 {
991     ap_lua_dir_cfg *cfg = apr_pcalloc(p, sizeof(ap_lua_dir_cfg));
992     cfg->package_paths = apr_array_make(p, 2, sizeof(char *));
993     cfg->package_cpaths = apr_array_make(p, 2, sizeof(char *));
994     cfg->mapped_handlers =
995         apr_array_make(p, 1, sizeof(ap_lua_mapped_handler_spec *));
996     cfg->pool = p;
997     cfg->hooks = apr_hash_make(p);
998     cfg->dir = apr_pstrdup(p, dir);
999     cfg->vm_scope = AP_LUA_SCOPE_ONCE;
1000     return cfg;
1001 }
1002
1003 static int create_request_config(request_rec *r)
1004 {
1005     ap_lua_request_cfg *cfg = apr_palloc(r->pool, sizeof(ap_lua_request_cfg));
1006     cfg->mapped_request_details = NULL;
1007     cfg->request_scoped_vms = apr_hash_make(r->pool);
1008     ap_set_module_config(r->request_config, &lua_module, cfg);
1009     return OK;
1010 }
1011
1012 static void *create_server_config(apr_pool_t *p, server_rec *s)
1013 {
1014
1015     ap_lua_server_cfg *cfg = apr_pcalloc(p, sizeof(ap_lua_server_cfg));
1016     cfg->vm_reslists = apr_hash_make(p);
1017     apr_thread_rwlock_create(&cfg->vm_reslists_lock, p);
1018     cfg->root_path = NULL;
1019
1020     return cfg;
1021 }
1022
1023 static int lua_request_hook(lua_State *L, request_rec *r)
1024 {
1025     ap_lua_push_request(L, r);
1026     return OK;
1027 }
1028
1029 static int lua_post_config(apr_pool_t *pconf, apr_pool_t *plog,
1030                              apr_pool_t *ptemp, server_rec *s)
1031 {
1032     lua_ssl_val = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
1033     lua_ssl_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);
1034     return OK;
1035 }
1036
1037 static void lua_register_hooks(apr_pool_t *p)
1038 {
1039     /* ap_register_output_filter("luahood", luahood, NULL, AP_FTYPE_RESOURCE); */
1040     ap_hook_handler(lua_handler, NULL, NULL, APR_HOOK_MIDDLE);
1041     ap_hook_create_request(create_request_config, NULL, NULL,
1042                            APR_HOOK_MIDDLE);
1043
1044     /* http_request.h hooks */
1045     ap_hook_translate_name(lua_translate_name_harness_first, NULL, NULL,
1046                            AP_LUA_HOOK_FIRST);
1047     ap_hook_translate_name(lua_translate_name_harness, NULL, NULL,
1048                            APR_HOOK_MIDDLE);
1049     ap_hook_translate_name(lua_translate_name_harness_last, NULL, NULL,
1050                            AP_LUA_HOOK_LAST);
1051
1052     ap_hook_fixups(lua_fixup_harness, NULL, NULL, APR_HOOK_MIDDLE);
1053     ap_hook_map_to_storage(lua_map_to_storage_harness, NULL, NULL,
1054                            APR_HOOK_MIDDLE);
1055
1056     ap_hook_check_user_id(lua_check_user_id_harness_first, NULL, NULL,
1057                           AP_LUA_HOOK_FIRST);
1058     ap_hook_check_user_id(lua_check_user_id_harness, NULL, NULL,
1059                            APR_HOOK_MIDDLE);
1060     ap_hook_check_user_id(lua_check_user_id_harness_last, NULL, NULL,
1061                           AP_LUA_HOOK_LAST);
1062
1063     ap_hook_type_checker(lua_type_checker_harness, NULL, NULL,
1064                          APR_HOOK_MIDDLE);
1065
1066     ap_hook_access_checker(lua_access_checker_harness_first, NULL, NULL,
1067                            AP_LUA_HOOK_FIRST);
1068     ap_hook_access_checker(lua_access_checker_harness, NULL, NULL,
1069                            APR_HOOK_MIDDLE);
1070     ap_hook_access_checker(lua_access_checker_harness_last, NULL, NULL,
1071                            AP_LUA_HOOK_LAST);
1072     ap_hook_auth_checker(lua_auth_checker_harness_first, NULL, NULL,
1073                          AP_LUA_HOOK_FIRST);
1074     ap_hook_auth_checker(lua_auth_checker_harness, NULL, NULL,
1075                          APR_HOOK_MIDDLE);
1076     ap_hook_auth_checker(lua_auth_checker_harness_last, NULL, NULL,
1077                          AP_LUA_HOOK_LAST);
1078
1079     ap_hook_insert_filter(lua_insert_filter_harness, NULL, NULL,
1080                           APR_HOOK_MIDDLE);
1081     ap_hook_quick_handler(lua_quick_harness, NULL, NULL, APR_HOOK_FIRST);
1082
1083     ap_hook_post_config(lua_post_config, NULL, NULL, APR_HOOK_MIDDLE);
1084
1085     APR_OPTIONAL_HOOK(ap_lua, lua_open, lua_open_hook, NULL, NULL,
1086                       APR_HOOK_REALLY_FIRST);
1087
1088     APR_OPTIONAL_HOOK(ap_lua, lua_request, lua_request_hook, NULL, NULL,
1089                       APR_HOOK_REALLY_FIRST);
1090 }
1091
1092 AP_DECLARE_MODULE(lua) = {
1093     STANDARD20_MODULE_STUFF,
1094     create_dir_config,          /* create per-dir    config structures */
1095     NULL,                       /* merge  per-dir    config structures */
1096     create_server_config,       /* create per-server config structures */
1097     NULL,                       /* merge  per-server config structures */
1098     lua_commands,               /* table of config file commands       */
1099     lua_register_hooks          /* register hooks                      */
1100 };