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