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