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