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