]> granicus.if.org Git - apache/blob - modules/lua/lua_request.c
* modules/lua/config.m4: Use liblua paths from pkg-config if
[apache] / modules / lua / lua_request.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 "lua_apr.h"
20 #include "lua_dbd.h"
21 #include "lua_passwd.h"
22 #include "scoreboard.h"
23 #include "util_md5.h"
24 #include "util_script.h"
25 #include "util_varbuf.h"
26 #include "apr_date.h"
27 #include "apr_pools.h"
28 #include "apr_thread_mutex.h"
29 #include "apr_tables.h"
30 #include "util_cookies.h"
31
32 #define APR_WANT_BYTEFUNC
33 #include "apr_want.h"
34
35 extern apr_global_mutex_t* lua_ivm_mutex;
36 extern apr_shm_t *lua_ivm_shm;
37
38 APLOG_USE_MODULE(lua);
39 #define POST_MAX_VARS 500
40
41 #ifndef MODLUA_MAX_REG_MATCH
42 #define MODLUA_MAX_REG_MATCH 25
43 #endif
44
45 typedef char *(*req_field_string_f) (request_rec * r);
46 typedef int (*req_field_int_f) (request_rec * r);
47 typedef req_table_t *(*req_field_apr_table_f) (request_rec * r);
48
49
50 void ap_lua_rstack_dump(lua_State *L, request_rec *r, const char *msg)
51 {
52     int i;
53     int top = lua_gettop(L);
54     ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(01484) "Lua Stack Dump: [%s]", msg);
55     for (i = 1; i <= top; i++) {
56         int t = lua_type(L, i);
57         switch (t) {
58         case LUA_TSTRING:{
59                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03001)
60                               "%d:  '%s'", i, lua_tostring(L, i));
61                 break;
62             }
63         case LUA_TUSERDATA:{
64                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03002)
65                               "%d:  userdata", i);
66                 break;
67             }
68         case LUA_TLIGHTUSERDATA:{
69                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03003)
70                               "%d:  lightuserdata", i);
71                 break;
72             }
73         case LUA_TNIL:{
74                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03004)
75                               "%d:  NIL", i);
76                 break;
77             }
78         case LUA_TNONE:{
79                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03005)
80                               "%d:  None", i);
81                 break;
82             }
83         case LUA_TBOOLEAN:{
84                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03006)
85                               "%d:  %s", i,
86                               lua_toboolean(L, i) ? "true" : "false");
87                 break;
88             }
89         case LUA_TNUMBER:{
90                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03007)
91                               "%d:  %g", i, lua_tonumber(L, i));
92                 break;
93             }
94         case LUA_TTABLE:{
95                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03008)
96                               "%d:  <table>", i);
97                 break;
98             }
99         case LUA_TFUNCTION:{
100                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03009)
101                               "%d:  <function>", i);
102                 break;
103             }
104         default:{
105                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(03010)
106                               "%d:  unknown: -[%s]-", i, lua_typename(L, i));
107                 break;
108             }
109         }
110     }
111 }
112
113 /**
114  * Verify that the thing at index is a request_rec wrapping
115  * userdata thingamajig and return it if it is. if it is not
116  * lua will enter its error handling routine.
117  */
118 static request_rec *ap_lua_check_request_rec(lua_State *L, int index)
119 {
120     request_rec *r;
121     luaL_checkudata(L, index, "Apache2.Request");
122     r = (request_rec *) lua_unboxpointer(L, index);
123     return r;
124 }
125
126 /* ------------------ request methods -------------------- */
127 /* helper callback for req_parseargs */
128 static int req_aprtable2luatable_cb(void *l, const char *key,
129                                     const char *value)
130 {
131     int t;
132     lua_State *L = (lua_State *) l;     /* [table<s,t>, table<s,s>] */
133     /* rstack_dump(L, RRR, "start of cb"); */
134     /* L is [table<s,t>, table<s,s>] */
135     /* build complex */
136
137     lua_getfield(L, -1, key);   /* [VALUE, table<s,t>, table<s,s>] */
138     /* rstack_dump(L, RRR, "after getfield"); */
139     t = lua_type(L, -1);
140     switch (t) {
141     case LUA_TNIL:
142     case LUA_TNONE:{
143             lua_pop(L, 1);      /* [table<s,t>, table<s,s>] */
144             lua_newtable(L);    /* [array, table<s,t>, table<s,s>] */
145             lua_pushnumber(L, 1);       /* [1, array, table<s,t>, table<s,s>] */
146             lua_pushstring(L, value);   /* [string, 1, array, table<s,t>, table<s,s>] */
147             lua_settable(L, -3);        /* [array, table<s,t>, table<s,s>]  */
148             lua_setfield(L, -2, key);   /* [table<s,t>, table<s,s>] */
149             break;
150         }
151     case LUA_TTABLE:{
152             /* [array, table<s,t>, table<s,s>] */
153             int size = lua_rawlen(L, -1);
154             lua_pushnumber(L, size + 1);        /* [#, array, table<s,t>, table<s,s>] */
155             lua_pushstring(L, value);   /* [string, #, array, table<s,t>, table<s,s>] */
156             lua_settable(L, -3);        /* [array, table<s,t>, table<s,s>] */
157             lua_setfield(L, -2, key);   /* [table<s,t>, table<s,s>] */
158             break;
159         }
160     }
161
162     /* L is [table<s,t>, table<s,s>] */
163     /* build simple */
164     lua_getfield(L, -2, key);   /* [VALUE, table<s,s>, table<s,t>] */
165     if (lua_isnoneornil(L, -1)) {       /* only set if not already set */
166         lua_pop(L, 1);          /* [table<s,s>, table<s,t>]] */
167         lua_pushstring(L, value);       /* [string, table<s,s>, table<s,t>] */
168         lua_setfield(L, -3, key);       /* [table<s,s>, table<s,t>]  */
169     }
170     else {
171         lua_pop(L, 1);
172     }
173     return 1;
174 }
175
176 /* helper callback for req_parseargs */
177 static int req_aprtable2luatable_cb_len(void *l, const char *key,
178                                     const char *value, size_t len)
179 {
180     int t;
181     lua_State *L = (lua_State *) l;     /* [table<s,t>, table<s,s>] */
182     /* rstack_dump(L, RRR, "start of cb"); */
183     /* L is [table<s,t>, table<s,s>] */
184     /* build complex */
185
186     lua_getfield(L, -1, key);   /* [VALUE, table<s,t>, table<s,s>] */
187     /* rstack_dump(L, RRR, "after getfield"); */
188     t = lua_type(L, -1);
189     switch (t) {
190     case LUA_TNIL:
191     case LUA_TNONE:{
192             lua_pop(L, 1);      /* [table<s,t>, table<s,s>] */
193             lua_newtable(L);    /* [array, table<s,t>, table<s,s>] */
194             lua_pushnumber(L, 1);       /* [1, array, table<s,t>, table<s,s>] */
195             lua_pushlstring(L, value, len);   /* [string, 1, array, table<s,t>, table<s,s>] */
196             lua_settable(L, -3);        /* [array, table<s,t>, table<s,s>]  */
197             lua_setfield(L, -2, key);   /* [table<s,t>, table<s,s>] */
198             break;
199         }
200     
201     case LUA_TTABLE:{
202             /* [array, table<s,t>, table<s,s>] */
203             int size = lua_rawlen(L, -1);
204             lua_pushnumber(L, size + 1);        /* [#, array, table<s,t>, table<s,s>] */
205             lua_pushlstring(L, value, len);   /* [string, #, array, table<s,t>, table<s,s>] */
206             lua_settable(L, -3);        /* [array, table<s,t>, table<s,s>] */
207             lua_setfield(L, -2, key);   /* [table<s,t>, table<s,s>] */
208             break;
209         }
210     }
211
212     /* L is [table<s,t>, table<s,s>] */
213     /* build simple */
214     lua_getfield(L, -2, key);   /* [VALUE, table<s,s>, table<s,t>] */
215     if (lua_isnoneornil(L, -1)) {       /* only set if not already set */
216         lua_pop(L, 1);          /* [table<s,s>, table<s,t>]] */
217         lua_pushlstring(L, value, len);       /* [string, table<s,s>, table<s,t>] */
218         lua_setfield(L, -3, key);       /* [table<s,s>, table<s,t>]  */
219     }
220     else {
221         lua_pop(L, 1);
222     }
223     return 1;
224 }
225
226
227 /*
228  =======================================================================================================================
229     lua_read_body(request_rec *r, const char **rbuf, apr_off_t *size): Reads any additional form data sent in POST/PUT
230     requests. Used for multipart POST data.
231  =======================================================================================================================
232  */
233 static int lua_read_body(request_rec *r, const char **rbuf, apr_off_t *size,
234         apr_off_t maxsize)
235 {
236     int rc = OK;
237
238     if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
239         return (rc);
240     }
241     if (ap_should_client_block(r)) {
242
243         /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
244         char         argsbuffer[HUGE_STRING_LEN];
245         apr_off_t    rsize, len_read, rpos = 0;
246         apr_off_t length = r->remaining;
247         /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
248
249         if (maxsize != 0 && length > maxsize) {
250             return APR_EINCOMPLETE; /* Only room for incomplete data chunk :( */
251         }
252         *rbuf = (const char *) apr_pcalloc(r->pool, (apr_size_t) (length + 1));
253         *size = length;
254         while ((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) {
255             if ((rpos + len_read) > length) {
256                 rsize = length - rpos;
257             }
258             else {
259                 rsize = len_read;
260             }
261
262             memcpy((char *) *rbuf + rpos, argsbuffer, (size_t) rsize);
263             rpos += rsize;
264         }
265     }
266
267     return (rc);
268 }
269
270
271 /*
272  * =======================================================================================================================
273  * lua_write_body: Reads any additional form data sent in POST/PUT requests
274  * and writes to a file.
275  * =======================================================================================================================
276  */
277 static apr_status_t lua_write_body(request_rec *r, apr_file_t *file, apr_off_t *size)
278 {
279     apr_status_t rc = OK;
280
281     if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)))
282         return rc;
283     if (ap_should_client_block(r)) {
284         char argsbuffer[HUGE_STRING_LEN];
285         apr_off_t rsize,
286                   len_read,
287                   rpos = 0;
288         apr_off_t length = r->remaining;
289
290         *size = length;
291         while ((len_read =
292                     ap_get_client_block(r, argsbuffer,
293                                         sizeof(argsbuffer))) > 0) {
294             if ((rpos + len_read) > length)
295                 rsize = (apr_size_t) length - rpos;
296             else
297                 rsize = len_read;
298
299             rc = apr_file_write_full(file, argsbuffer, (apr_size_t) rsize,
300                                      NULL);
301             if (rc != APR_SUCCESS)
302                 return rc;
303             rpos += rsize;
304         }
305     }
306
307     return rc;
308 }
309
310 /* r:parseargs() returning a lua table */
311 static int req_parseargs(lua_State *L)
312 {
313     apr_table_t *form_table;
314     request_rec *r = ap_lua_check_request_rec(L, 1);
315     lua_newtable(L);
316     lua_newtable(L);            /* [table, table] */
317     ap_args_to_table(r, &form_table);
318     apr_table_do(req_aprtable2luatable_cb, L, form_table, NULL);
319     return 2;                   /* [table<string, string>, table<string, array<string>>] */
320 }
321
322 /* ap_lua_binstrstr: Binary strstr function for uploaded data with NULL bytes */
323 static char* ap_lua_binstrstr (const char * haystack, size_t hsize, const char* needle, size_t nsize)
324 {
325     size_t p;
326     if (haystack == NULL) return NULL;
327     if (needle == NULL) return NULL;
328     if (hsize < nsize) return NULL;
329     for (p = 0; p <= (hsize - nsize); ++p) {
330         if (memcmp(haystack + p, needle, nsize) == 0) {
331             return (char*) (haystack + p);
332         }
333     }
334     return NULL;
335
336
337 /* r:parsebody(): Parses regular (url-enocded) or multipart POST data and returns two tables*/
338 static int req_parsebody(lua_State *L)
339 {
340     apr_array_header_t          *pairs;
341     apr_off_t len;
342     int res;
343     apr_size_t size;
344     apr_size_t max_post_size;
345     char *multipart;
346     const char *contentType;
347     request_rec *r = ap_lua_check_request_rec(L, 1);
348     max_post_size = (apr_size_t) luaL_optinteger(L, 2, MAX_STRING_LEN);
349     multipart = apr_pcalloc(r->pool, 256);
350     contentType = apr_table_get(r->headers_in, "Content-Type");
351     lua_newtable(L);
352     lua_newtable(L);            /* [table, table] */    
353     if (contentType != NULL && (sscanf(contentType, "multipart/form-data; boundary=%250c", multipart) == 1)) {
354         char        *buffer, *key, *filename;
355         char        *start = 0, *end = 0, *crlf = 0;
356         const char  *data;
357         int         i;
358         size_t      vlen = 0;
359         size_t      len = 0;
360         if (lua_read_body(r, &data, (apr_off_t*) &size, max_post_size) != OK) {
361             return 2;
362         }
363         len = strlen(multipart);
364         i = 0;
365         for
366         (
367             start = strstr((char *) data, multipart);
368             start != NULL;
369             start = end
370         ) {
371             i++;
372             if (i == POST_MAX_VARS) break;
373             crlf = strstr((char *) start, "\r\n\r\n");
374             if (!crlf) break;
375             end = ap_lua_binstrstr(crlf, (size - (crlf - data)), multipart, len);
376             if (end == NULL) break;
377             key = (char *) apr_pcalloc(r->pool, 256);
378             filename = (char *) apr_pcalloc(r->pool, 256);
379             vlen = end - crlf - 8;
380             buffer = (char *) apr_pcalloc(r->pool, vlen+1);
381             memcpy(buffer, crlf + 4, vlen);
382             sscanf(start + len + 2,
383                 "Content-Disposition: form-data; name=\"%255[^\"]\"; filename=\"%255[^\"]\"",
384                 key, filename);
385             if (*key) {
386                 req_aprtable2luatable_cb_len(L, key, buffer, vlen);
387             }
388         }
389     }
390     else {
391         char *buffer;
392         res = ap_parse_form_data(r, NULL, &pairs, -1, max_post_size);
393         if (res == OK) {
394             while(pairs && !apr_is_empty_array(pairs)) {
395                 ap_form_pair_t *pair = (ap_form_pair_t *) apr_array_pop(pairs);
396                 apr_brigade_length(pair->value, 1, &len);
397                 size = (apr_size_t) len;
398                 buffer = apr_palloc(r->pool, size + 1);
399                 apr_brigade_flatten(pair->value, buffer, &size);
400                 buffer[len] = 0;
401                 req_aprtable2luatable_cb(L, pair->name, buffer);
402             }
403         }
404     }
405     return 2;                   /* [table<string, string>, table<string, array<string>>] */
406 }
407
408
409 /*
410  * lua_ap_requestbody; r:requestbody([filename]) - Reads or stores the request
411  * body
412  */
413 static int lua_ap_requestbody(lua_State *L)
414 {
415     const char     *filename;
416     request_rec    *r;
417     apr_off_t      maxSize;
418     
419     r = ap_lua_check_request_rec(L, 1);
420     filename = luaL_optstring(L, 2, 0);
421     maxSize = (apr_off_t)luaL_optinteger(L, 3, 0);
422
423     if (r) {
424         apr_off_t size;
425         if (maxSize > 0 && r->remaining > maxSize) {
426             lua_pushnil(L);
427             lua_pushliteral(L, "Request body was larger than the permitted size.");
428             return 2;
429         }
430         if (r->method_number != M_POST && r->method_number != M_PUT)
431             return (0);
432         if (!filename) {
433             const char     *data;
434
435             if (lua_read_body(r, &data, &size, maxSize) != OK)
436                 return (0);
437
438             lua_pushlstring(L, data, (size_t) size);
439             lua_pushinteger(L, (lua_Integer) size);
440             return (2);
441         } else {
442             apr_status_t rc;
443             apr_file_t     *file;
444
445             rc = apr_file_open(&file, filename, APR_CREATE | APR_FOPEN_WRITE,
446                                APR_FPROT_OS_DEFAULT, r->pool);
447             lua_settop(L, 0);
448             if (rc == APR_SUCCESS) {
449                 rc = lua_write_body(r, file, &size);
450                 apr_file_close(file);
451                 if (rc != OK) {
452                     lua_pushboolean(L, 0);
453                     return 1;
454                 }
455                 lua_pushinteger(L, (lua_Integer) size);
456                 return (1);
457             } else
458                 lua_pushboolean(L, 0);
459             return (1);
460         }
461     }
462
463     return (0);
464 }
465
466 /* wrap ap_rputs as r:puts(String) */
467 static int req_puts(lua_State *L)
468 {
469     request_rec *r = ap_lua_check_request_rec(L, 1);
470
471     int argc = lua_gettop(L);
472     int i;
473
474     for (i = 2; i <= argc; i++) {
475         ap_rputs(luaL_checkstring(L, i), r);
476     }
477     return 0;
478 }
479
480 /* wrap ap_rwrite as r:write(String) */
481 static int req_write(lua_State *L)
482 {
483     request_rec *r = ap_lua_check_request_rec(L, 1);
484     size_t n;
485     int rv;
486     const char *buf = luaL_checklstring(L, 2, &n);
487
488     rv = ap_rwrite((void *) buf, n, r);
489     lua_pushinteger(L, rv);
490     return 1;
491 }
492
493 /* r:addoutputfilter(name|function) */
494 static int req_add_output_filter(lua_State *L)
495 {
496     request_rec *r = ap_lua_check_request_rec(L, 1);
497     const char *name = luaL_checkstring(L, 2);
498     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01485) "adding output filter %s",
499                   name);
500     ap_add_output_filter(name, L, r, r->connection);
501     return 0;
502 }
503
504 /* wrap ap_construct_url as r:construct_url(String) */
505 static int req_construct_url(lua_State *L)
506 {
507     request_rec *r = ap_lua_check_request_rec(L, 1);
508     const char *name = luaL_checkstring(L, 2);
509     lua_pushstring(L, ap_construct_url(r->pool, name, r));
510     return 1;
511 }
512
513 /* wrap ap_escape_html r:escape_html(String) */
514 static int req_escape_html(lua_State *L)
515 {
516     request_rec *r = ap_lua_check_request_rec(L, 1);
517     const char *s = luaL_checkstring(L, 2);
518     lua_pushstring(L, ap_escape_html(r->pool, s));
519     return 1;
520 }
521
522 /* wrap optional ssl_var_lookup as  r:ssl_var_lookup(String) */
523 static int req_ssl_var_lookup(lua_State *L)
524 {
525     request_rec *r = ap_lua_check_request_rec(L, 1);
526     const char *s = luaL_checkstring(L, 2);
527     const char *res = ap_lua_ssl_val(r->pool, r->server, r->connection, r, 
528                                      (char *)s);
529     lua_pushstring(L, res);
530     return 1;
531 }
532
533 /* BEGIN dispatch mathods for request_rec fields */
534
535 /* not really a field, but we treat it like one */
536 static const char *req_document_root(request_rec *r)
537 {
538     return ap_document_root(r);
539 }
540
541 static const char *req_context_prefix(request_rec *r)
542 {
543     return ap_context_prefix(r);
544 }
545
546 static const char *req_context_document_root(request_rec *r)
547 {
548     return ap_context_document_root(r);
549 }
550
551 static char *req_uri_field(request_rec *r)
552 {
553     return r->uri;
554 }
555
556 static const char *req_method_field(request_rec *r)
557 {
558     return r->method;
559 }
560 static const char *req_handler_field(request_rec *r)
561 {
562     return r->handler;
563 }
564 static const char *req_proxyreq_field(request_rec *r)
565 {
566     switch (r->proxyreq) {
567         case PROXYREQ_NONE:     return "PROXYREQ_NONE";
568         case PROXYREQ_PROXY:    return "PROXYREQ_PROXY";
569         case PROXYREQ_REVERSE:  return "PROXYREQ_REVERSE";
570         case PROXYREQ_RESPONSE: return "PROXYREQ_RESPONSE";
571         default: return NULL;
572     }
573 }
574 static const char *req_hostname_field(request_rec *r)
575 {
576     return r->hostname;
577 }
578
579 static const char *req_args_field(request_rec *r)
580 {
581     return r->args;
582 }
583
584 static const char *req_path_info_field(request_rec *r)
585 {
586     return r->path_info;
587 }
588
589 static const char *req_canonical_filename_field(request_rec *r)
590 {
591     return r->canonical_filename;
592 }
593
594 static const char *req_filename_field(request_rec *r)
595 {
596     return r->filename;
597 }
598
599 static const char *req_user_field(request_rec *r)
600 {
601     return r->user;
602 }
603
604 static const char *req_unparsed_uri_field(request_rec *r)
605 {
606     return r->unparsed_uri;
607 }
608
609 static const char *req_ap_auth_type_field(request_rec *r)
610 {
611     return r->ap_auth_type;
612 }
613
614 static const char *req_content_encoding_field(request_rec *r)
615 {
616     return r->content_encoding;
617 }
618
619 static const char *req_content_type_field(request_rec *r)
620 {
621     return r->content_type;
622 }
623
624 static const char *req_range_field(request_rec *r)
625 {
626     return r->range;
627 }
628
629 static const char *req_protocol_field(request_rec *r)
630 {
631     return r->protocol;
632 }
633
634 static const char *req_the_request_field(request_rec *r)
635 {
636     return r->the_request;
637 }
638
639 static const char *req_log_id_field(request_rec *r)
640 {
641     return r->log_id;
642 }
643
644 static const char *req_useragent_ip_field(request_rec *r)
645 {
646     return r->useragent_ip;
647 }
648
649 static int req_remaining_field(request_rec *r)
650 {
651     return r->remaining;
652 }
653
654 static int req_status_field(request_rec *r)
655 {
656     return r->status;
657 }
658
659 static int req_assbackwards_field(request_rec *r)
660 {
661     return r->assbackwards;
662 }
663
664 static req_table_t* req_headers_in(request_rec *r)
665 {
666   req_table_t* t = apr_palloc(r->pool, sizeof(req_table_t));
667   t->r = r;
668   t->t = r->headers_in;
669   t->n = "headers_in";
670   return t;
671 }
672
673 static req_table_t* req_headers_out(request_rec *r)
674 {
675   req_table_t* t = apr_palloc(r->pool, sizeof(req_table_t));
676   t->r = r;
677   t->t = r->headers_out;
678   t->n = "headers_out";
679   return t;
680 }
681
682 static req_table_t* req_err_headers_out(request_rec *r)
683 {
684   req_table_t* t = apr_palloc(r->pool, sizeof(req_table_t));
685   t->r = r;
686   t->t = r->err_headers_out;
687   t->n = "err_headers_out";
688   return t;
689 }
690
691 static req_table_t* req_subprocess_env(request_rec *r)
692 {
693   req_table_t* t = apr_palloc(r->pool, sizeof(req_table_t));
694   t->r = r;
695   t->t = r->subprocess_env;
696   t->n = "subprocess_env";
697   return t;
698 }
699
700 static req_table_t* req_notes(request_rec *r)
701 {
702   req_table_t* t = apr_palloc(r->pool, sizeof(req_table_t));
703   t->r = r;
704   t->t = r->notes;
705   t->n = "notes";
706   return t;
707 }
708
709 static int req_ssl_is_https_field(request_rec *r)
710 {
711     return ap_lua_ssl_is_https(r->connection);
712 }
713
714 static int req_ap_get_server_port(request_rec *r)
715 {
716     return (int) ap_get_server_port(r);
717 }
718
719 static int lua_ap_rflush (lua_State *L) {
720
721     int returnValue;
722     request_rec *r;
723     luaL_checktype(L, 1, LUA_TUSERDATA);
724     r = ap_lua_check_request_rec(L, 1);
725     returnValue = ap_rflush(r);
726     lua_pushboolean(L, (returnValue == 0));
727     return 1;
728 }
729
730
731 static const char* lua_ap_options(request_rec* r) 
732 {
733     int opts;
734     opts = ap_allow_options(r);
735     return apr_psprintf(r->pool, "%s %s %s %s %s %s", (opts&OPT_INDEXES) ? "Indexes" : "", (opts&OPT_INCLUDES) ? "Includes" : "", (opts&OPT_SYM_LINKS) ? "FollowSymLinks" : "", (opts&OPT_EXECCGI) ? "ExecCGI" : "", (opts&OPT_MULTI) ? "MultiViews" : "", (opts&OPT_ALL) == OPT_ALL ? "All" : "" );
736 }
737
738 static const char* lua_ap_allowoverrides(request_rec* r) 
739 {
740     int opts;
741     opts = ap_allow_overrides(r);
742     if ( (opts & OR_ALL) == OR_ALL) {
743         return "All";
744     }
745     else if (opts == OR_NONE) {
746         return "None";
747     }
748     return apr_psprintf(r->pool, "%s %s %s %s %s", (opts & OR_LIMIT) ? "Limit" : "", (opts & OR_OPTIONS) ? "Options" : "", (opts & OR_FILEINFO) ? "FileInfo" : "", (opts & OR_AUTHCFG) ? "AuthCfg" : "", (opts & OR_INDEXES) ? "Indexes" : "" );
749     
750 }
751
752 static int lua_ap_started(request_rec* r) 
753 {
754     return (int)(ap_scoreboard_image->global->restart_time / 1000000);
755 }
756
757 static const char* lua_ap_basic_auth_pw(request_rec* r) 
758 {
759     const char* pw = NULL;
760     ap_get_basic_auth_pw(r, &pw);
761     return pw ? pw : "";
762 }
763
764 static int lua_ap_limit_req_body(request_rec* r) 
765 {
766     return (int) ap_get_limit_req_body(r);
767 }
768
769 static int lua_ap_is_initial_req(request_rec *r)
770 {
771     return ap_is_initial_req(r);
772 }
773
774 static int lua_ap_some_auth_required(request_rec *r)
775 {
776     return ap_some_auth_required(r);
777 }
778
779 static int lua_ap_sendfile(lua_State *L)
780 {
781
782     apr_finfo_t file_info;
783     const char  *filename;
784     request_rec *r;
785
786     luaL_checktype(L, 1, LUA_TUSERDATA);
787     luaL_checktype(L, 2, LUA_TSTRING);
788     r = ap_lua_check_request_rec(L, 1);
789     filename = lua_tostring(L, 2);
790     apr_stat(&file_info, filename, APR_FINFO_MIN, r->pool);
791     if (file_info.filetype == APR_NOFILE || file_info.filetype == APR_DIR) {
792         lua_pushboolean(L, 0);
793     }
794     else {
795         apr_size_t      sent;
796         apr_status_t    rc;
797         apr_file_t      *file;
798
799         rc = apr_file_open(&file, filename, APR_READ, APR_OS_DEFAULT,
800                             r->pool);
801         if (rc == APR_SUCCESS) {
802             ap_send_fd(file, r, 0, (apr_size_t)file_info.size, &sent);
803             apr_file_close(file);
804             lua_pushinteger(L, sent);
805         }
806         else {
807             lua_pushboolean(L, 0);
808         }
809     }
810
811     return (1);
812 }
813
814
815 /*
816  * lua_apr_b64encode; r:encode_base64(string) - encodes a string to Base64
817  * format
818  */
819 static int lua_apr_b64encode(lua_State *L)
820 {
821     const char     *plain;
822     char           *encoded;
823     size_t          plain_len, encoded_len;
824     request_rec    *r;
825
826     r = ap_lua_check_request_rec(L, 1);
827     luaL_checktype(L, 2, LUA_TSTRING);
828     plain = lua_tolstring(L, 2, &plain_len);
829     encoded_len = apr_base64_encode_len(plain_len);
830     if (encoded_len) {
831         encoded = apr_palloc(r->pool, encoded_len);
832         encoded_len = apr_base64_encode(encoded, plain, plain_len);
833         if (encoded_len > 0 && encoded[encoded_len - 1] == '\0')
834             encoded_len--; 
835         lua_pushlstring(L, encoded, encoded_len);
836         return 1;
837     }
838     return 0;
839 }
840
841 /*
842  * lua_apr_b64decode; r:decode_base64(string) - decodes a Base64 string
843  */
844 static int lua_apr_b64decode(lua_State *L)
845 {
846     const char     *encoded;
847     char           *plain;
848     size_t          encoded_len, decoded_len;
849     request_rec    *r;
850
851     r = ap_lua_check_request_rec(L, 1);
852     luaL_checktype(L, 2, LUA_TSTRING);
853     encoded = lua_tolstring(L, 2, &encoded_len);
854     decoded_len = apr_base64_decode_len(encoded);
855     if (decoded_len) {
856         plain = apr_palloc(r->pool, decoded_len);
857         decoded_len = apr_base64_decode(plain, encoded);
858         if (decoded_len > 0 && plain[decoded_len - 1] == '\0')
859             decoded_len--; 
860         lua_pushlstring(L, plain, decoded_len);
861         return 1;
862     }
863     return 0;
864 }
865
866 /*
867  * lua_ap_unescape; r:unescape(string) - Unescapes an URL-encoded string
868  */
869 static int lua_ap_unescape(lua_State *L)
870 {
871     const char     *escaped;
872     char           *plain;
873     size_t x,
874            y;
875     request_rec    *r;
876     r = ap_lua_check_request_rec(L, 1);
877     luaL_checktype(L, 2, LUA_TSTRING);
878     escaped = lua_tolstring(L, 2, &x);
879     plain = apr_pstrdup(r->pool, escaped);
880     y = ap_unescape_urlencoded(plain);
881     if (!y) {
882         lua_pushstring(L, plain);
883         return 1;
884     }
885     return 0;
886 }
887
888 /*
889  * lua_ap_escape; r:escape(string) - URL-escapes a string
890  */
891 static int lua_ap_escape(lua_State *L)
892 {
893     const char     *plain;
894     char           *escaped;
895     size_t x;
896     request_rec    *r;
897     r = ap_lua_check_request_rec(L, 1);
898     luaL_checktype(L, 2, LUA_TSTRING);
899     plain = lua_tolstring(L, 2, &x);
900     escaped = ap_escape_urlencoded(r->pool, plain);
901     lua_pushstring(L, escaped);
902     return 1;
903 }
904
905 /*
906  * lua_apr_md5; r:md5(string) - Calculates an MD5 digest of a string
907  */
908 static int lua_apr_md5(lua_State *L)
909 {
910     const char     *buffer;
911     char           *result;
912     size_t len;
913     request_rec    *r;
914
915     r = ap_lua_check_request_rec(L, 1);
916     luaL_checktype(L, 2, LUA_TSTRING);
917     buffer = lua_tolstring(L, 2, &len);
918     result = ap_md5_binary(r->pool, (const unsigned char *)buffer, len);
919     lua_pushstring(L, result);
920     return 1;
921 }
922
923 /*
924  * lua_apr_sha1; r:sha1(string) - Calculates the SHA1 digest of a string
925  */
926 static int lua_apr_sha1(lua_State *L)
927 {
928     unsigned char digest[APR_SHA1_DIGESTSIZE];
929     apr_sha1_ctx_t sha1;
930     const char     *buffer;
931     char           *result;
932     size_t len;
933     request_rec    *r;
934
935     r = ap_lua_check_request_rec(L, 1);
936     luaL_checktype(L, 2, LUA_TSTRING);
937     result = apr_pcalloc(r->pool, sizeof(digest) * 2 + 1);
938     buffer = lua_tolstring(L, 2, &len);
939     apr_sha1_init(&sha1);
940     apr_sha1_update(&sha1, buffer, len);
941     apr_sha1_final(digest, &sha1);
942     
943     ap_bin2hex(digest, sizeof(digest), result);
944     lua_pushstring(L, result);
945     return 1;
946 }
947
948 /*
949  * lua_apr_htpassword; r:htpassword(string [, algorithm [, cost]]) - Creates
950  * a htpassword hash from a string
951  */
952 static int lua_apr_htpassword(lua_State *L)
953 {
954     passwd_ctx     ctx = { 0 };
955     request_rec    *r;
956
957     r = ap_lua_check_request_rec(L, 1);
958     luaL_checktype(L, 2, LUA_TSTRING);
959     ctx.passwd = apr_pstrdup(r->pool, lua_tostring(L, 2));
960     ctx.alg = luaL_optinteger(L, 3, ALG_APMD5);
961     ctx.cost = luaL_optinteger(L, 4, 0);
962     ctx.pool = r->pool;
963     ctx.out = apr_pcalloc(r->pool, MAX_PASSWD_LEN);
964     ctx.out_len = MAX_PASSWD_LEN;
965     if (mk_password_hash(&ctx)) {
966         lua_pushboolean(L, 0);
967         lua_pushstring(L, ctx.errstr);
968         return 2;
969     } else {
970         lua_pushstring(L, ctx.out);
971     }
972     return 1;
973 }
974
975 /*
976  * lua_apr_touch; r:touch(string [, time]) - Sets mtime of a file
977  */
978 static int lua_apr_touch(lua_State *L)
979 {
980     request_rec     *r;
981     const char      *path;
982     apr_status_t    status;
983     apr_time_t      mtime;
984
985     r = ap_lua_check_request_rec(L, 1);
986     luaL_checktype(L, 2, LUA_TSTRING);
987     path = lua_tostring(L, 2);
988     mtime = (apr_time_t)luaL_optnumber(L, 3, (lua_Number)apr_time_now());
989     status = apr_file_mtime_set(path, mtime, r->pool);
990     lua_pushboolean(L, (status == 0));
991     return 1;
992 }
993
994 /*
995  * lua_apr_mkdir; r:mkdir(string [, permissions]) - Creates a directory
996  */
997 static int lua_apr_mkdir(lua_State *L)
998 {
999     request_rec     *r;
1000     const char      *path;
1001     apr_status_t    status;
1002     apr_fileperms_t perms;
1003
1004     r = ap_lua_check_request_rec(L, 1);
1005     luaL_checktype(L, 2, LUA_TSTRING);
1006     path = lua_tostring(L, 2);
1007     perms = luaL_optinteger(L, 3, APR_OS_DEFAULT);
1008     status = apr_dir_make(path, perms, r->pool);
1009     lua_pushboolean(L, (status == 0));
1010     return 1;
1011 }
1012
1013 /*
1014  * lua_apr_mkrdir; r:mkrdir(string [, permissions]) - Creates directories
1015  * recursive
1016  */
1017 static int lua_apr_mkrdir(lua_State *L)
1018 {
1019     request_rec     *r;
1020     const char      *path;
1021     apr_status_t    status;
1022     apr_fileperms_t perms;
1023
1024     r = ap_lua_check_request_rec(L, 1);
1025     luaL_checktype(L, 2, LUA_TSTRING);
1026     path = lua_tostring(L, 2);
1027     perms = luaL_optinteger(L, 3, APR_OS_DEFAULT);
1028     status = apr_dir_make_recursive(path, perms, r->pool);
1029     lua_pushboolean(L, (status == 0));
1030     return 1;
1031 }
1032
1033 /*
1034  * lua_apr_rmdir; r:rmdir(string) - Removes a directory
1035  */
1036 static int lua_apr_rmdir(lua_State *L)
1037 {
1038     request_rec     *r;
1039     const char      *path;
1040     apr_status_t    status;
1041
1042     r = ap_lua_check_request_rec(L, 1);
1043     luaL_checktype(L, 2, LUA_TSTRING);
1044     path = lua_tostring(L, 2);
1045     status = apr_dir_remove(path, r->pool);
1046     lua_pushboolean(L, (status == 0));
1047     return 1;
1048 }
1049
1050 /*
1051  * lua_apr_date_parse_rfc; r.date_parse_rfc(string) - Parses a DateTime string
1052  */
1053 static int lua_apr_date_parse_rfc(lua_State *L)
1054 {
1055     const char *input;
1056     apr_time_t result;
1057
1058     luaL_checktype(L, 1, LUA_TSTRING);
1059     input = lua_tostring(L, 1);
1060     result = apr_date_parse_rfc(input);
1061     if (result == 0)
1062         return 0;
1063     lua_pushnumber(L, (lua_Number)(result / APR_USEC_PER_SEC));
1064     return 1;
1065 }
1066
1067 /*
1068  * lua_ap_mpm_query; r:mpm_query(info) - Queries for MPM info
1069  */
1070 static int lua_ap_mpm_query(lua_State *L)
1071 {
1072     int x,
1073         y;
1074
1075     x = lua_tointeger(L, 1);
1076     ap_mpm_query(x, &y);
1077     lua_pushinteger(L, y);
1078     return 1;
1079 }
1080
1081 /*
1082  * lua_ap_expr; r:expr(string) - Evaluates an expr statement.
1083  */
1084 static int lua_ap_expr(lua_State *L)
1085 {
1086     request_rec    *r;
1087     int x = 0;
1088     const char     *expr,
1089     *err;
1090     ap_expr_info_t res;
1091
1092     luaL_checktype(L, 1, LUA_TUSERDATA);
1093     luaL_checktype(L, 2, LUA_TSTRING);
1094     r = ap_lua_check_request_rec(L, 1);
1095     expr = lua_tostring(L, 2);
1096
1097
1098     res.filename = NULL;
1099     res.flags = 0;
1100     res.line_number = 0;
1101     res.module_index = APLOG_MODULE_INDEX;
1102
1103     err = ap_expr_parse(r->pool, r->pool, &res, expr, NULL);
1104     if (!err) {
1105         x = ap_expr_exec(r, &res, &err);
1106         lua_pushboolean(L, x);
1107         if (x < 0) {
1108             lua_pushstring(L, err);
1109             return 2;
1110         }
1111         return 1;
1112     } else {
1113         lua_pushboolean(L, 0);
1114         lua_pushstring(L, err);
1115         return 2;
1116     }
1117     lua_pushboolean(L, 0);
1118     return 1;
1119 }
1120
1121
1122 /*
1123  * lua_ap_regex; r:regex(string, pattern [, flags])
1124  * - Evaluates a regex and returns captures if matched
1125  */
1126 static int lua_ap_regex(lua_State *L)
1127 {
1128     request_rec    *r;
1129     int i,
1130         rv,
1131         flags;
1132     const char     *pattern,
1133     *source;
1134     char           *err;
1135     ap_regex_t regex;
1136     ap_regmatch_t matches[MODLUA_MAX_REG_MATCH+1];
1137
1138     luaL_checktype(L, 1, LUA_TUSERDATA);
1139     luaL_checktype(L, 2, LUA_TSTRING);
1140     luaL_checktype(L, 3, LUA_TSTRING);
1141     r = ap_lua_check_request_rec(L, 1);
1142     source = lua_tostring(L, 2);
1143     pattern = lua_tostring(L, 3);
1144     flags = luaL_optinteger(L, 4, 0);
1145
1146     rv = ap_regcomp(&regex, pattern, flags);
1147     if (rv) {
1148         lua_pushboolean(L, 0);
1149         err = apr_palloc(r->pool, 256);
1150         ap_regerror(rv, &regex, err, 256);
1151         lua_pushstring(L, err);
1152         return 2;
1153     }
1154
1155     if (regex.re_nsub > MODLUA_MAX_REG_MATCH) {
1156         lua_pushboolean(L, 0);
1157         err = apr_palloc(r->pool, 64);
1158         apr_snprintf(err, 64,
1159                      "regcomp found %d matches; only %d allowed.",
1160                      regex.re_nsub, MODLUA_MAX_REG_MATCH);
1161         lua_pushstring(L, err);
1162         return 2;
1163     }
1164
1165     rv = ap_regexec(&regex, source, MODLUA_MAX_REG_MATCH, matches, 0);
1166     if (rv == AP_REG_NOMATCH) {
1167         lua_pushboolean(L, 0);
1168         return 1;
1169     }
1170     
1171     lua_newtable(L);
1172     for (i = 0; i <= regex.re_nsub; i++) {
1173         lua_pushinteger(L, i);
1174         if (matches[i].rm_so >= 0 && matches[i].rm_eo >= 0)
1175             lua_pushstring(L,
1176                            apr_pstrndup(r->pool, source + matches[i].rm_so,
1177                                         matches[i].rm_eo - matches[i].rm_so));
1178         else
1179             lua_pushnil(L);
1180         lua_settable(L, -3);
1181
1182     }
1183     return 1;
1184 }
1185
1186
1187
1188
1189 /*
1190  * lua_ap_scoreboard_process; r:scoreboard_process(a) - returns scoreboard info
1191  */
1192 static int lua_ap_scoreboard_process(lua_State *L)
1193 {
1194     int i;
1195     process_score  *ps_record;
1196
1197     luaL_checktype(L, 1, LUA_TUSERDATA);
1198     luaL_checktype(L, 2, LUA_TNUMBER);
1199     i = lua_tointeger(L, 2);
1200     ps_record = ap_get_scoreboard_process(i);
1201     if (ps_record) {
1202         lua_newtable(L);
1203
1204         lua_pushstring(L, "connections");
1205         lua_pushnumber(L, ps_record->connections);
1206         lua_settable(L, -3);
1207
1208         lua_pushstring(L, "keepalive");
1209         lua_pushnumber(L, ps_record->keep_alive);
1210         lua_settable(L, -3);
1211
1212         lua_pushstring(L, "lingering_close");
1213         lua_pushnumber(L, ps_record->lingering_close);
1214         lua_settable(L, -3);
1215
1216         lua_pushstring(L, "pid");
1217         lua_pushnumber(L, ps_record->pid);
1218         lua_settable(L, -3);
1219
1220         lua_pushstring(L, "suspended");
1221         lua_pushnumber(L, ps_record->suspended);
1222         lua_settable(L, -3);
1223
1224         lua_pushstring(L, "write_completion");
1225         lua_pushnumber(L, ps_record->write_completion);
1226         lua_settable(L, -3);
1227
1228         lua_pushstring(L, "not_accepting");
1229         lua_pushnumber(L, ps_record->not_accepting);
1230         lua_settable(L, -3);
1231
1232         lua_pushstring(L, "quiescing");
1233         lua_pushnumber(L, ps_record->quiescing);
1234         lua_settable(L, -3);
1235
1236         return 1;
1237     }
1238     return 0;
1239 }
1240
1241 /*
1242  * lua_ap_scoreboard_worker; r:scoreboard_worker(proc, thread) - Returns thread
1243  * info
1244  */
1245 static int lua_ap_scoreboard_worker(lua_State *L)
1246 {
1247     int i, j;
1248     worker_score *ws_record = NULL;
1249     request_rec *r = NULL;
1250
1251     luaL_checktype(L, 1, LUA_TUSERDATA);
1252     luaL_checktype(L, 2, LUA_TNUMBER);
1253     luaL_checktype(L, 3, LUA_TNUMBER);
1254
1255     r = ap_lua_check_request_rec(L, 1);
1256     if (!r) return 0;
1257
1258     i = lua_tointeger(L, 2);
1259     j = lua_tointeger(L, 3);
1260     ws_record = apr_palloc(r->pool, sizeof *ws_record);
1261
1262     ap_copy_scoreboard_worker(ws_record, i, j);
1263     if (ws_record) {
1264         lua_newtable(L);
1265
1266         lua_pushstring(L, "access_count");
1267         lua_pushnumber(L, ws_record->access_count);
1268         lua_settable(L, -3);
1269
1270         lua_pushstring(L, "bytes_served");
1271         lua_pushnumber(L, (lua_Number) ws_record->bytes_served);
1272         lua_settable(L, -3);
1273
1274         lua_pushstring(L, "client");
1275         lua_pushstring(L, ws_record->client);
1276         lua_settable(L, -3);
1277
1278         lua_pushstring(L, "conn_bytes");
1279         lua_pushnumber(L, (lua_Number) ws_record->conn_bytes);
1280         lua_settable(L, -3);
1281
1282         lua_pushstring(L, "conn_count");
1283         lua_pushnumber(L, ws_record->conn_count);
1284         lua_settable(L, -3);
1285
1286         lua_pushstring(L, "generation");
1287         lua_pushnumber(L, ws_record->generation);
1288         lua_settable(L, -3);
1289
1290         lua_pushstring(L, "last_used");
1291         lua_pushnumber(L, (lua_Number) ws_record->last_used);
1292         lua_settable(L, -3);
1293
1294         lua_pushstring(L, "pid");
1295         lua_pushnumber(L, ws_record->pid);
1296         lua_settable(L, -3);
1297
1298         lua_pushstring(L, "request");
1299         lua_pushstring(L, ws_record->request);
1300         lua_settable(L, -3);
1301
1302         lua_pushstring(L, "start_time");
1303         lua_pushnumber(L, (lua_Number) ws_record->start_time);
1304         lua_settable(L, -3);
1305
1306         lua_pushstring(L, "status");
1307         lua_pushnumber(L, ws_record->status);
1308         lua_settable(L, -3);
1309
1310         lua_pushstring(L, "stop_time");
1311         lua_pushnumber(L, (lua_Number) ws_record->stop_time);
1312         lua_settable(L, -3);
1313
1314         lua_pushstring(L, "tid");
1315
1316         lua_pushinteger(L, (lua_Integer) ws_record->tid);
1317         lua_settable(L, -3);
1318
1319         lua_pushstring(L, "vhost");
1320         lua_pushstring(L, ws_record->vhost);
1321         lua_settable(L, -3);
1322 #ifdef HAVE_TIMES
1323         lua_pushstring(L, "stimes");
1324         lua_pushnumber(L, ws_record->times.tms_stime);
1325         lua_settable(L, -3);
1326
1327         lua_pushstring(L, "utimes");
1328         lua_pushnumber(L, ws_record->times.tms_utime);
1329         lua_settable(L, -3);
1330 #endif
1331         return 1;
1332     }
1333     return 0;
1334 }
1335
1336 /*
1337  * lua_ap_clock; r:clock() - Returns timestamp with microsecond precision
1338  */
1339 static int lua_ap_clock(lua_State *L)
1340 {
1341     apr_time_t now;
1342     now = apr_time_now();
1343     lua_pushnumber(L, (lua_Number) now);
1344     return 1;
1345 }
1346
1347 /*
1348  * lua_ap_add_input_filter; r:add_input_filter(name) - Adds an input filter to
1349  * the chain
1350  */
1351 static int lua_ap_add_input_filter(lua_State *L)
1352 {
1353     request_rec    *r;
1354     const char     *filterName;
1355     ap_filter_rec_t *filter;
1356
1357     luaL_checktype(L, 1, LUA_TUSERDATA);
1358     luaL_checktype(L, 2, LUA_TSTRING);
1359     r = ap_lua_check_request_rec(L, 1);
1360     filterName = lua_tostring(L, 2);
1361     filter = ap_get_input_filter_handle(filterName);
1362     if (filter) {
1363         ap_add_input_filter_handle(filter, NULL, r, r->connection);
1364         lua_pushboolean(L, 1);
1365     } else
1366         lua_pushboolean(L, 0);
1367     return 1;
1368 }
1369
1370
1371 /*
1372  * lua_ap_module_info; r:module_info(mod_name) - Returns information about a
1373  * loaded module
1374  */
1375 static int lua_ap_module_info(lua_State *L)
1376 {
1377     const char     *moduleName;
1378     module         *mod;
1379
1380     luaL_checktype(L, 1, LUA_TSTRING);
1381     moduleName = lua_tostring(L, 1);
1382     mod = ap_find_linked_module(moduleName);
1383     if (mod && mod->cmds) {
1384         const command_rec *cmd;
1385         lua_newtable(L);
1386         lua_pushstring(L, "commands");
1387         lua_newtable(L);
1388         for (cmd = mod->cmds; cmd->name; ++cmd) {
1389             lua_pushstring(L, cmd->name);
1390             lua_pushstring(L, cmd->errmsg);
1391             lua_settable(L, -3);
1392         }
1393         lua_settable(L, -3);
1394         return 1;
1395     }
1396     return 0;
1397 }
1398
1399 /*
1400  * lua_ap_runtime_dir_relative: r:runtime_dir_relative(file): Returns the
1401  * filename as relative to the runtime dir
1402  */
1403 static int lua_ap_runtime_dir_relative(lua_State *L)
1404 {
1405     request_rec    *r;
1406     const char     *file;
1407
1408     luaL_checktype(L, 1, LUA_TUSERDATA);
1409     r = ap_lua_check_request_rec(L, 1);
1410     file = luaL_optstring(L, 2, ".");
1411     lua_pushstring(L, ap_runtime_dir_relative(r->pool, file));
1412     return 1;
1413 }
1414
1415 /*
1416  * lua_ap_set_document_root; r:set_document_root(path) - sets the current doc
1417  * root for the request
1418  */
1419 static int lua_ap_set_document_root(lua_State *L)
1420 {
1421     request_rec    *r;
1422     const char     *root;
1423
1424     luaL_checktype(L, 1, LUA_TUSERDATA);
1425     luaL_checktype(L, 2, LUA_TSTRING);
1426     r = ap_lua_check_request_rec(L, 1);
1427     root = lua_tostring(L, 2);
1428     ap_set_document_root(r, root);
1429     return 0;
1430 }
1431
1432 /*
1433  * lua_ap_getdir; r:get_direntries(directory) - Gets all entries of a
1434  * directory and returns the directory info as a table
1435  */
1436 static int lua_ap_getdir(lua_State *L)
1437 {
1438     request_rec    *r;
1439     apr_dir_t      *thedir;
1440     apr_finfo_t    file_info;
1441     apr_status_t   status;
1442     const char     *directory;
1443
1444     luaL_checktype(L, 1, LUA_TUSERDATA);
1445     luaL_checktype(L, 2, LUA_TSTRING);
1446     r = ap_lua_check_request_rec(L, 1);
1447     directory = lua_tostring(L, 2);
1448     if (apr_dir_open(&thedir, directory, r->pool) == APR_SUCCESS) {
1449         int i = 0;
1450         lua_newtable(L);
1451         do {
1452             status = apr_dir_read(&file_info, APR_FINFO_NAME, thedir);
1453             if (APR_STATUS_IS_INCOMPLETE(status)) {
1454                 continue; /* ignore un-stat()able files */
1455             }
1456             else if (status != APR_SUCCESS) {
1457                 break;
1458             }
1459             lua_pushinteger(L, ++i);
1460             lua_pushstring(L, file_info.name);
1461             lua_settable(L, -3);
1462
1463         } while (1);
1464         apr_dir_close(thedir);
1465         return 1;
1466     }
1467     else {
1468         return 0;
1469     }
1470 }
1471
1472 /*
1473  * lua_ap_stat; r:stat(filename [, wanted]) - Runs stat on a file and
1474  * returns the file info as a table
1475  */
1476 static int lua_ap_stat(lua_State *L)
1477 {
1478     request_rec    *r;
1479     const char     *filename;
1480     apr_finfo_t file_info;
1481     apr_int32_t wanted;
1482
1483     luaL_checktype(L, 1, LUA_TUSERDATA);
1484     luaL_checktype(L, 2, LUA_TSTRING);
1485     r = ap_lua_check_request_rec(L, 1);
1486     filename = lua_tostring(L, 2);
1487     wanted = luaL_optinteger(L, 3, APR_FINFO_MIN);
1488     if (apr_stat(&file_info, filename, wanted, r->pool) == OK) {
1489         lua_newtable(L);
1490         if (wanted & APR_FINFO_MTIME) {
1491             lua_pushstring(L, "mtime");
1492             lua_pushnumber(L, (lua_Number) file_info.mtime);
1493             lua_settable(L, -3);
1494         }
1495         if (wanted & APR_FINFO_ATIME) {
1496             lua_pushstring(L, "atime");
1497             lua_pushnumber(L, (lua_Number) file_info.atime);
1498             lua_settable(L, -3);
1499         }
1500         if (wanted & APR_FINFO_CTIME) {
1501             lua_pushstring(L, "ctime");
1502             lua_pushnumber(L, (lua_Number) file_info.ctime);
1503             lua_settable(L, -3);
1504         }
1505         if (wanted & APR_FINFO_SIZE) {
1506             lua_pushstring(L, "size");
1507             lua_pushnumber(L, (lua_Number) file_info.size);
1508             lua_settable(L, -3);
1509         }
1510         if (wanted & APR_FINFO_TYPE) {
1511             lua_pushstring(L, "filetype");
1512             lua_pushinteger(L, file_info.filetype);
1513             lua_settable(L, -3);
1514         }
1515         if (wanted & APR_FINFO_PROT) {
1516             lua_pushstring(L, "protection");
1517             lua_pushinteger(L, file_info.protection);
1518             lua_settable(L, -3);
1519         }
1520         return 1;
1521     }
1522     else {
1523         return 0;
1524     }
1525 }
1526
1527 /*
1528  * lua_ap_loaded_modules; r:loaded_modules() - Returns a list of loaded modules
1529  */
1530 static int lua_ap_loaded_modules(lua_State *L)
1531 {
1532     int i;
1533     lua_newtable(L);
1534     for (i = 0; ap_loaded_modules[i] && ap_loaded_modules[i]->name; i++) {
1535         lua_pushinteger(L, i + 1);
1536         lua_pushstring(L, ap_loaded_modules[i]->name);
1537         lua_settable(L, -3);
1538     }
1539     return 1;
1540 }
1541
1542 /*
1543  * lua_ap_server_info; r:server_info() - Returns server info, such as the
1544  * executable filename, server root, mpm etc
1545  */
1546 static int lua_ap_server_info(lua_State *L)
1547 {
1548     lua_newtable(L);
1549
1550     lua_pushstring(L, "server_executable");
1551     lua_pushstring(L, ap_server_argv0);
1552     lua_settable(L, -3);
1553
1554     lua_pushstring(L, "server_root");
1555     lua_pushstring(L, ap_server_root);
1556     lua_settable(L, -3);
1557
1558     lua_pushstring(L, "scoreboard_fname");
1559     lua_pushstring(L, ap_scoreboard_fname);
1560     lua_settable(L, -3);
1561
1562     lua_pushstring(L, "server_mpm");
1563     lua_pushstring(L, ap_show_mpm());
1564     lua_settable(L, -3);
1565
1566     return 1;
1567 }
1568
1569
1570 /*
1571  * === Auto-scraped functions ===
1572  */
1573
1574
1575 /**
1576  * ap_set_context_info: Set context_prefix and context_document_root.
1577  * @param r The request
1578  * @param prefix the URI prefix, without trailing slash
1579  * @param document_root the corresponding directory on disk, without trailing
1580  * slash
1581  * @note If one of prefix of document_root is NULL, the corrsponding
1582  * property will not be changed.
1583  */
1584 static int lua_ap_set_context_info(lua_State *L)
1585 {
1586     request_rec    *r;
1587     const char     *prefix;
1588     const char     *document_root;
1589     luaL_checktype(L, 1, LUA_TUSERDATA);
1590     r = ap_lua_check_request_rec(L, 1);
1591     luaL_checktype(L, 2, LUA_TSTRING);
1592     prefix = lua_tostring(L, 2);
1593     luaL_checktype(L, 3, LUA_TSTRING);
1594     document_root = lua_tostring(L, 3);
1595     ap_set_context_info(r, prefix, document_root);
1596     return 0;
1597 }
1598
1599
1600 /**
1601  * ap_os_escape_path (apr_pool_t *p, const char *path, int partial)
1602  * convert an OS path to a URL in an OS dependant way.
1603  * @param p The pool to allocate from
1604  * @param path The path to convert
1605  * @param partial if set, assume that the path will be appended to something
1606  *        with a '/' in it (and thus does not prefix "./")
1607  * @return The converted URL
1608  */
1609 static int lua_ap_os_escape_path(lua_State *L)
1610 {
1611     char           *returnValue;
1612     request_rec    *r;
1613     const char     *path;
1614     int partial = 0;
1615     luaL_checktype(L, 1, LUA_TUSERDATA);
1616     r = ap_lua_check_request_rec(L, 1);
1617     luaL_checktype(L, 2, LUA_TSTRING);
1618     path = lua_tostring(L, 2);
1619     if (lua_isboolean(L, 3))
1620         partial = lua_toboolean(L, 3);
1621     returnValue = ap_os_escape_path(r->pool, path, partial);
1622     lua_pushstring(L, returnValue);
1623     return 1;
1624 }
1625
1626
1627 /**
1628  * ap_escape_logitem (apr_pool_t *p, const char *str)
1629  * Escape a string for logging
1630  * @param p The pool to allocate from
1631  * @param str The string to escape
1632  * @return The escaped string
1633  */
1634 static int lua_ap_escape_logitem(lua_State *L)
1635 {
1636     char           *returnValue;
1637     request_rec    *r;
1638     const char     *str;
1639     luaL_checktype(L, 1, LUA_TUSERDATA);
1640     r = ap_lua_check_request_rec(L, 1);
1641     luaL_checktype(L, 2, LUA_TSTRING);
1642     str = lua_tostring(L, 2);
1643     returnValue = ap_escape_logitem(r->pool, str);
1644     lua_pushstring(L, returnValue);
1645     return 1;
1646 }
1647
1648 /**
1649  * ap_strcmp_match (const char *str, const char *expected)
1650  * Determine if a string matches a pattern containing the wildcards '?' or '*'
1651  * @param str The string to check
1652  * @param expected The pattern to match against
1653  * @param ignoreCase Whether to ignore case when matching
1654  * @return 1 if the two strings match, 0 otherwise
1655  */
1656 static int lua_ap_strcmp_match(lua_State *L)
1657 {
1658     int returnValue;
1659     const char     *str;
1660     const char     *expected;
1661     int ignoreCase = 0;
1662     luaL_checktype(L, 1, LUA_TSTRING);
1663     str = lua_tostring(L, 1);
1664     luaL_checktype(L, 2, LUA_TSTRING);
1665     expected = lua_tostring(L, 2);
1666     if (lua_isboolean(L, 3))
1667         ignoreCase = lua_toboolean(L, 3);
1668     if (!ignoreCase)
1669         returnValue = ap_strcmp_match(str, expected);
1670     else
1671         returnValue = ap_strcasecmp_match(str, expected);
1672     lua_pushboolean(L, (!returnValue));
1673     return 1;
1674 }
1675
1676
1677 /**
1678  * ap_set_keepalive (request_rec *r)
1679  * Set the keepalive status for this request
1680  * @param r The current request
1681  * @return 1 if keepalive can be set, 0 otherwise
1682  */
1683 static int lua_ap_set_keepalive(lua_State *L)
1684 {
1685     int returnValue;
1686     request_rec    *r;
1687     luaL_checktype(L, 1, LUA_TUSERDATA);
1688     r = ap_lua_check_request_rec(L, 1);
1689     returnValue = ap_set_keepalive(r);
1690     lua_pushboolean(L, returnValue);
1691     return 1;
1692 }
1693
1694 /**
1695  * ap_make_etag (request_rec *r, int force_weak)
1696  * Construct an entity tag from the resource information.  If it's a real
1697  * file, build in some of the file characteristics.
1698  * @param r The current request
1699  * @param force_weak Force the entity tag to be weak - it could be modified
1700  *                   again in as short an interval.
1701  * @return The entity tag
1702  */
1703 static int lua_ap_make_etag(lua_State *L)
1704 {
1705     char           *returnValue;
1706     request_rec    *r;
1707     int force_weak;
1708     luaL_checktype(L, 1, LUA_TUSERDATA);
1709     r = ap_lua_check_request_rec(L, 1);
1710     luaL_checktype(L, 2, LUA_TBOOLEAN);
1711     force_weak = (int)luaL_optinteger(L, 2, 0);
1712     returnValue = ap_make_etag(r, force_weak);
1713     lua_pushstring(L, returnValue);
1714     return 1;
1715 }
1716
1717
1718
1719 /**
1720  * ap_send_interim_response (request_rec *r, int send_headers)
1721  * Send an interim (HTTP 1xx) response immediately.
1722  * @param r The request
1723  * @param send_headers Whether to send&clear headers in r->headers_out
1724  */
1725 static int lua_ap_send_interim_response(lua_State *L)
1726 {
1727     request_rec    *r;
1728     int send_headers = 0;
1729     luaL_checktype(L, 1, LUA_TUSERDATA);
1730     r = ap_lua_check_request_rec(L, 1);
1731     if (lua_isboolean(L, 2))
1732         send_headers = lua_toboolean(L, 2);
1733     ap_send_interim_response(r, send_headers);
1734     return 0;
1735 }
1736
1737
1738 /**
1739  * ap_custom_response (request_rec *r, int status, const char *string)
1740  * Install a custom response handler for a given status
1741  * @param r The current request
1742  * @param status The status for which the custom response should be used
1743  * @param string The custom response.  This can be a static string, a file
1744  *               or a URL
1745  */
1746 static int lua_ap_custom_response(lua_State *L)
1747 {
1748     request_rec    *r;
1749     int status;
1750     const char     *string;
1751     luaL_checktype(L, 1, LUA_TUSERDATA);
1752     r = ap_lua_check_request_rec(L, 1);
1753     luaL_checktype(L, 2, LUA_TNUMBER);
1754     status = lua_tointeger(L, 2);
1755     luaL_checktype(L, 3, LUA_TSTRING);
1756     string = lua_tostring(L, 3);
1757     ap_custom_response(r, status, string);
1758     return 0;
1759 }
1760
1761
1762 /**
1763  * ap_exists_config_define (const char *name)
1764  * Check for a definition from the server command line
1765  * @param name The define to check for
1766  * @return 1 if defined, 0 otherwise
1767  */
1768 static int lua_ap_exists_config_define(lua_State *L)
1769 {
1770     int returnValue;
1771     const char     *name;
1772     luaL_checktype(L, 1, LUA_TSTRING);
1773     name = lua_tostring(L, 1);
1774     returnValue = ap_exists_config_define(name);
1775     lua_pushboolean(L, returnValue);
1776     return 1;
1777 }
1778
1779 static int lua_ap_get_server_name_for_url(lua_State *L)
1780 {
1781     const char     *servername;
1782     request_rec    *r;
1783     luaL_checktype(L, 1, LUA_TUSERDATA);
1784     r = ap_lua_check_request_rec(L, 1);
1785     servername = ap_get_server_name_for_url(r);
1786     lua_pushstring(L, servername);
1787     return 1;
1788 }
1789
1790 /* ap_state_query (int query_code) item starts a new field  */
1791 static int lua_ap_state_query(lua_State *L)
1792 {
1793
1794     int returnValue;
1795     int query_code;
1796     luaL_checktype(L, 1, LUA_TNUMBER);
1797     query_code = lua_tointeger(L, 1);
1798     returnValue = ap_state_query(query_code);
1799     lua_pushinteger(L, returnValue);
1800     return 1;
1801 }
1802
1803 /*
1804  * lua_ap_usleep; r:usleep(microseconds)
1805  * - Sleep for the specified number of microseconds.
1806  */
1807 static int lua_ap_usleep(lua_State *L)
1808 {
1809     apr_interval_time_t msec;
1810     luaL_checktype(L, 1, LUA_TNUMBER);
1811     msec = (apr_interval_time_t)lua_tonumber(L, 1);
1812     apr_sleep(msec);
1813     return 0;
1814 }
1815
1816 /* END dispatch methods for request_rec fields */
1817
1818 static int req_dispatch(lua_State *L)
1819 {
1820     apr_hash_t *dispatch;
1821     req_fun_t *rft;
1822     request_rec *r = ap_lua_check_request_rec(L, 1);
1823     const char *name = luaL_checkstring(L, 2);
1824     lua_pop(L, 2);
1825
1826     lua_getfield(L, LUA_REGISTRYINDEX, "Apache2.Request.dispatch");
1827     dispatch = lua_touserdata(L, 1);
1828     lua_pop(L, 1);
1829
1830     rft = apr_hash_get(dispatch, name, APR_HASH_KEY_STRING);
1831     if (rft) {
1832         switch (rft->type) {
1833         case APL_REQ_FUNTYPE_TABLE:{
1834                 req_table_t *rs;
1835                 req_field_apr_table_f func = (req_field_apr_table_f)rft->fun;
1836                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01486)
1837                               "request_rec->dispatching %s -> apr table",
1838                               name);
1839                 rs = (*func)(r);
1840                 ap_lua_push_apr_table(L, rs);
1841                 return 1;
1842             }
1843
1844         case APL_REQ_FUNTYPE_LUACFUN:{
1845                 lua_CFunction func = (lua_CFunction)rft->fun;
1846                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01487)
1847                               "request_rec->dispatching %s -> lua_CFunction",
1848                               name);
1849                 lua_pushcfunction(L, func);
1850                 return 1;
1851             }
1852         case APL_REQ_FUNTYPE_STRING:{
1853                 req_field_string_f func = (req_field_string_f)rft->fun;
1854                 char *rs;
1855                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01488)
1856                               "request_rec->dispatching %s -> string", name);
1857                 rs = (*func) (r);
1858                 lua_pushstring(L, rs);
1859                 return 1;
1860             }
1861         case APL_REQ_FUNTYPE_INT:{
1862                 req_field_int_f func = (req_field_int_f)rft->fun;
1863                 int rs;
1864                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01489)
1865                               "request_rec->dispatching %s -> int", name);
1866                 rs = (*func) (r);
1867                 lua_pushinteger(L, rs);
1868                 return 1;
1869             }
1870         case APL_REQ_FUNTYPE_BOOLEAN:{
1871                 req_field_int_f func = (req_field_int_f)rft->fun;
1872                 int rs;
1873                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01490)
1874                               "request_rec->dispatching %s -> boolean", name);
1875                 rs = (*func) (r);
1876                 lua_pushboolean(L, rs);
1877                 return 1;
1878             }
1879         }
1880     }
1881
1882     ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01491) "nothing for %s", name);
1883     return 0;
1884 }
1885
1886 /* helper function for the logging functions below */
1887 static int req_log_at(lua_State *L, int level)
1888 {
1889     const char *msg;
1890     request_rec *r = ap_lua_check_request_rec(L, 1);
1891     lua_Debug dbg;
1892
1893     lua_getstack(L, 1, &dbg);
1894     lua_getinfo(L, "Sl", &dbg);
1895
1896     msg = luaL_checkstring(L, 2);
1897     /* Intentional no APLOGNO */
1898     ap_log_rerror(dbg.source, dbg.currentline, APLOG_MODULE_INDEX, level, 0,
1899                   r, "%s", msg);
1900     return 0;
1901 }
1902
1903 /* r:debug(String) and friends which use apache logging */
1904 static int req_emerg(lua_State *L)
1905 {
1906     return req_log_at(L, APLOG_EMERG);
1907 }
1908 static int req_alert(lua_State *L)
1909 {
1910     return req_log_at(L, APLOG_ALERT);
1911 }
1912 static int req_crit(lua_State *L)
1913 {
1914     return req_log_at(L, APLOG_CRIT);
1915 }
1916 static int req_err(lua_State *L)
1917 {
1918     return req_log_at(L, APLOG_ERR);
1919 }
1920 static int req_warn(lua_State *L)
1921 {
1922     return req_log_at(L, APLOG_WARNING);
1923 }
1924 static int req_notice(lua_State *L)
1925 {
1926     return req_log_at(L, APLOG_NOTICE);
1927 }
1928 static int req_info(lua_State *L)
1929 {
1930     return req_log_at(L, APLOG_INFO);
1931 }
1932 static int req_debug(lua_State *L)
1933 {
1934     return req_log_at(L, APLOG_DEBUG);
1935 }
1936
1937 static int lua_ivm_get(lua_State *L) 
1938 {
1939     const char *key, *raw_key;
1940     apr_pool_t *pool;
1941     lua_ivm_object *object = NULL;
1942     request_rec *r = ap_lua_check_request_rec(L, 1);
1943     key = luaL_checkstring(L, 2);
1944     raw_key = apr_pstrcat(r->pool, "lua_ivm_", key, NULL);
1945     apr_global_mutex_lock(lua_ivm_mutex);
1946     pool = *((apr_pool_t**) apr_shm_baseaddr_get(lua_ivm_shm));
1947     apr_pool_userdata_get((void **)&object, raw_key, pool);
1948     if (object) {
1949         if (object->type == LUA_TBOOLEAN) lua_pushboolean(L, (int) object->number);
1950         else if (object->type == LUA_TNUMBER) lua_pushnumber(L, object->number);
1951         else if (object->type == LUA_TSTRING) lua_pushlstring(L, object->vb.buf, object->size);
1952         apr_global_mutex_unlock(lua_ivm_mutex);
1953         return 1;
1954     }
1955     else {
1956         apr_global_mutex_unlock(lua_ivm_mutex);
1957         return 0;
1958     }
1959 }
1960
1961
1962 static int lua_ivm_set(lua_State *L) 
1963 {
1964     const char *key, *raw_key;
1965     const char *value = NULL;
1966     apr_pool_t *pool;
1967     size_t str_len;
1968     lua_ivm_object *object = NULL;
1969     request_rec *r = ap_lua_check_request_rec(L, 1);
1970     key = luaL_checkstring(L, 2);
1971     luaL_checkany(L, 3);
1972     raw_key = apr_pstrcat(r->pool, "lua_ivm_", key, NULL);
1973     
1974     apr_global_mutex_lock(lua_ivm_mutex);
1975     pool = *((apr_pool_t**) apr_shm_baseaddr_get(lua_ivm_shm));
1976     apr_pool_userdata_get((void **)&object, raw_key, pool);
1977     if (!object) {
1978         object = apr_pcalloc(pool, sizeof(lua_ivm_object));
1979         ap_varbuf_init(pool, &object->vb, 2);
1980         object->size = 1;
1981         object->vb_size = 1;
1982     }
1983     object->type = lua_type(L, 3);
1984     if (object->type == LUA_TNUMBER) object->number = lua_tonumber(L, 3);
1985     else if (object->type == LUA_TBOOLEAN) object->number = lua_tonumber(L, 3);
1986     else if (object->type == LUA_TSTRING) {
1987         value = lua_tolstring(L, 3, &str_len);
1988         str_len++; /* add trailing \0 */
1989         if ( str_len > object->vb_size) {
1990             ap_varbuf_grow(&object->vb, str_len);
1991             object->vb_size = str_len;
1992         }
1993         object->size = str_len-1;
1994         memset(object->vb.buf, 0, str_len);
1995         memcpy(object->vb.buf, value, str_len-1);
1996     }
1997     apr_pool_userdata_set(object, raw_key, NULL, pool);
1998     apr_global_mutex_unlock(lua_ivm_mutex);
1999     return 0;
2000 }
2001
2002 static int lua_get_cookie(lua_State *L) 
2003 {
2004     const char *key, *cookie;
2005     request_rec *r = ap_lua_check_request_rec(L, 1);
2006     key = luaL_checkstring(L, 2);
2007     cookie = NULL;
2008     ap_cookie_read(r, key, &cookie, 0);
2009     if (cookie != NULL) {
2010         lua_pushstring(L, cookie);
2011         return 1;
2012     }
2013     return 0;
2014 }
2015
2016 static int lua_set_cookie(lua_State *L) 
2017 {
2018     const char *key, *value, *out, *path = "", *domain = "";
2019     const char *strexpires = "", *strdomain = "", *strpath = "";
2020     int secure = 0, expires = 0, httponly = 0;
2021     char cdate[APR_RFC822_DATE_LEN+1];
2022     apr_status_t rv;
2023     request_rec *r = ap_lua_check_request_rec(L, 1);
2024     
2025     /* New >= 2.4.8 method: */
2026     if (lua_istable(L, 2)) {
2027          
2028         /* key */
2029         lua_pushstring(L, "key");
2030         lua_gettable(L, -2);
2031         key = luaL_checkstring(L, -1);
2032         lua_pop(L, 1);
2033         
2034         /* value */
2035         lua_pushstring(L, "value");
2036         lua_gettable(L, -2);
2037         value = luaL_checkstring(L, -1);
2038         lua_pop(L, 1);
2039         
2040         /* expiry */
2041         lua_pushstring(L, "expires");
2042         lua_gettable(L, -2);
2043         expires = (int)luaL_optinteger(L, -1, 0);
2044         lua_pop(L, 1);
2045         
2046         /* secure */
2047         lua_pushstring(L, "secure");
2048         lua_gettable(L, -2);
2049         if (lua_isboolean(L, -1)) {
2050             secure = lua_toboolean(L, -1);
2051         }
2052         lua_pop(L, 1);
2053         
2054         /* httponly */
2055         lua_pushstring(L, "httponly");
2056         lua_gettable(L, -2);
2057         if (lua_isboolean(L, -1)) {
2058             httponly = lua_toboolean(L, -1);
2059         }
2060         lua_pop(L, 1);
2061         
2062         /* path */
2063         lua_pushstring(L, "path");
2064         lua_gettable(L, -2);
2065         path = luaL_optstring(L, -1, "/");
2066         lua_pop(L, 1);
2067         
2068         /* domain */
2069         lua_pushstring(L, "domain");
2070         lua_gettable(L, -2);
2071         domain = luaL_optstring(L, -1, "");
2072         lua_pop(L, 1);        
2073     }
2074     /* Old <= 2.4.7 method: */
2075     else {
2076         key = luaL_checkstring(L, 2);
2077         value = luaL_checkstring(L, 3);
2078         secure = 0;
2079         if (lua_isboolean(L, 4)) {
2080             secure = lua_toboolean(L, 4);
2081         }
2082         expires = luaL_optinteger(L, 5, 0);
2083     }
2084     
2085     /* Calculate expiry if set */
2086     if (expires > 0) {
2087         rv = apr_rfc822_date(cdate, apr_time_from_sec(expires));
2088         if (rv == APR_SUCCESS) {
2089             strexpires = apr_psprintf(r->pool, "Expires=%s;", cdate);
2090         }
2091     }
2092     
2093     /* Create path segment */
2094     if (path != NULL && strlen(path) > 0) {
2095         strpath = apr_psprintf(r->pool, "Path=%s;", path);
2096     }
2097     
2098     /* Create domain segment */
2099     if (domain != NULL && strlen(domain) > 0) {
2100         /* Domain does NOT like quotes in most browsers, so let's avoid that */
2101         strdomain = apr_psprintf(r->pool, "Domain=%s;", domain);
2102     }
2103     
2104     /* URL-encode key/value */
2105     value = ap_escape_urlencoded(r->pool, value);
2106     key = ap_escape_urlencoded(r->pool, key);
2107     
2108     /* Create the header */
2109     out = apr_psprintf(r->pool, "%s=%s; %s %s %s %s %s", key, value, 
2110             secure ? "Secure;" : "", 
2111             expires ? strexpires : "", 
2112             httponly ? "HttpOnly;" : "", 
2113             *strdomain ? strdomain : "", 
2114             *strpath ? strpath : "");
2115     
2116     apr_table_add(r->err_headers_out, "Set-Cookie", out);
2117     return 0;
2118 }
2119
2120 static apr_uint64_t ap_ntoh64(const apr_uint64_t *input)
2121 {
2122     apr_uint64_t rval;
2123     unsigned char *data = (unsigned char *)&rval;
2124     if (APR_IS_BIGENDIAN) {
2125         return *input;
2126     }
2127     
2128     data[0] = *input >> 56;
2129     data[1] = *input >> 48;
2130     data[2] = *input >> 40;
2131     data[3] = *input >> 32;
2132     data[4] = *input >> 24;
2133     data[5] = *input >> 16;
2134     data[6] = *input >> 8;
2135     data[7] = *input >> 0;
2136
2137     return rval;
2138 }
2139
2140 static int lua_websocket_greet(lua_State *L)
2141 {
2142     const char *key = NULL;
2143     unsigned char digest[APR_SHA1_DIGESTSIZE];
2144     apr_sha1_ctx_t sha1;
2145     char           *encoded;
2146     int encoded_len;
2147     request_rec *r = ap_lua_check_request_rec(L, 1);
2148     key = apr_table_get(r->headers_in, "Sec-WebSocket-Key");
2149     if (key != NULL) {
2150         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03011) 
2151                       "Websocket: Got websocket key: %s", key);
2152         key = apr_pstrcat(r->pool, key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 
2153                 NULL);
2154         apr_sha1_init(&sha1);
2155         apr_sha1_update(&sha1, key, strlen(key));
2156         apr_sha1_final(digest, &sha1);
2157         encoded_len = apr_base64_encode_len(APR_SHA1_DIGESTSIZE);
2158         if (encoded_len) {
2159             encoded = apr_palloc(r->pool, encoded_len);
2160             encoded_len = apr_base64_encode(encoded, (char*) digest, APR_SHA1_DIGESTSIZE);
2161             r->status = 101;
2162             apr_table_setn(r->headers_out, "Upgrade", "websocket");
2163             apr_table_setn(r->headers_out, "Connection", "Upgrade");
2164             apr_table_setn(r->headers_out, "Sec-WebSocket-Accept", encoded);
2165             
2166             /* Trick httpd into NOT using the chunked filter, IMPORTANT!!!111*/
2167             apr_table_setn(r->headers_out, "Transfer-Encoding", "chunked");
2168             
2169             r->clength = 0;
2170             r->bytes_sent = 0;
2171             r->read_chunked = 0;
2172             ap_rflush(r);
2173             ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03012) 
2174                           "Websocket: Upgraded from HTTP to Websocket");
2175             lua_pushboolean(L, 1);
2176             return 1;
2177         }
2178     }
2179     ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02666)
2180                   "Websocket: Upgrade from HTTP to Websocket failed");
2181     return 0;
2182 }
2183
2184 static apr_status_t lua_websocket_readbytes(conn_rec* c, char* buffer, 
2185         apr_off_t len) 
2186 {
2187     apr_bucket_brigade *brigade = apr_brigade_create(c->pool, c->bucket_alloc);
2188     apr_status_t rv;
2189     rv = ap_get_brigade(c->input_filters, brigade, AP_MODE_READBYTES, 
2190             APR_BLOCK_READ, len);
2191     if (rv == APR_SUCCESS) {
2192         if (!APR_BRIGADE_EMPTY(brigade)) {
2193             apr_bucket* bucket = APR_BRIGADE_FIRST(brigade);
2194             const char* data = NULL;
2195             apr_size_t data_length = 0;
2196             rv = apr_bucket_read(bucket, &data, &data_length, APR_BLOCK_READ);
2197             if (rv == APR_SUCCESS) {
2198                 memcpy(buffer, data, len);
2199             }
2200             apr_bucket_delete(bucket);
2201         }
2202     }
2203     apr_brigade_cleanup(brigade);
2204     return rv;
2205 }
2206
2207 static int lua_websocket_peek(lua_State *L) 
2208 {
2209     apr_status_t rv;
2210     apr_bucket_brigade *brigade;
2211     
2212     request_rec *r = ap_lua_check_request_rec(L, 1);
2213     
2214     brigade = apr_brigade_create(r->connection->pool, 
2215             r->connection->bucket_alloc);
2216     rv = ap_get_brigade(r->connection->input_filters, brigade, 
2217             AP_MODE_READBYTES, APR_NONBLOCK_READ, 1);
2218     if (rv == APR_SUCCESS) {
2219         lua_pushboolean(L, 1);
2220     }
2221     else {
2222         lua_pushboolean(L, 0);
2223     }
2224     apr_brigade_cleanup(brigade);
2225     return 1;
2226 }
2227
2228 static int lua_websocket_read(lua_State *L) 
2229 {
2230     apr_socket_t *sock;
2231     apr_status_t rv;
2232     int do_read = 1;
2233     int n = 0;
2234     apr_size_t len = 1;
2235     apr_size_t plen = 0;
2236     unsigned short payload_short = 0;
2237     apr_uint64_t payload_long = 0;
2238     unsigned char *mask_bytes;
2239     char byte;
2240     int plaintext;
2241     
2242     
2243     request_rec *r = ap_lua_check_request_rec(L, 1);
2244     plaintext = ap_lua_ssl_is_https(r->connection) ? 0 : 1;
2245
2246     
2247     mask_bytes = apr_pcalloc(r->pool, 4);
2248     sock = ap_get_conn_socket(r->connection);
2249
2250     while (do_read) {
2251         do_read = 0;
2252         /* Get opcode and FIN bit */
2253         if (plaintext) {
2254             rv = apr_socket_recv(sock, &byte, &len);
2255         }
2256         else {
2257             rv = lua_websocket_readbytes(r->connection, &byte, 1);
2258         }
2259         if (rv == APR_SUCCESS) {
2260             unsigned char ubyte, fin, opcode, mask, payload;
2261             ubyte = (unsigned char)byte;
2262             /* fin bit is the first bit */
2263             fin = ubyte >> (CHAR_BIT - 1);
2264             /* opcode is the last four bits (there's 3 reserved bits we don't care about) */
2265             opcode = ubyte & 0xf;
2266
2267             /* Get the payload length and mask bit */
2268             if (plaintext) {
2269                 rv = apr_socket_recv(sock, &byte, &len);
2270             }
2271             else {
2272                 rv = lua_websocket_readbytes(r->connection, &byte, 1);
2273             }
2274             if (rv == APR_SUCCESS) {
2275                 ubyte = (unsigned char)byte;
2276                 /* Mask is the first bit */
2277                 mask = ubyte >> (CHAR_BIT - 1);
2278                 /* Payload is the last 7 bits */
2279                 payload = ubyte & 0x7f;
2280                 plen = payload;
2281
2282                 /* Extended payload? */
2283                 if (payload == 126) {
2284                     len = 2;
2285                     if (plaintext) {
2286                         /* XXX: apr_socket_recv does not receive len bits, only up to len bits! */
2287                         rv = apr_socket_recv(sock, (char*) &payload_short, &len);
2288                     }
2289                     else {
2290                         rv = lua_websocket_readbytes(r->connection, 
2291                                 (char*) &payload_short, 2);
2292                     }
2293                     payload_short = ntohs(payload_short);
2294
2295                     if (rv == APR_SUCCESS) {
2296                         plen = payload_short;
2297                     }
2298                     else {
2299                         return 0;
2300                     }
2301                 }
2302                 /* Super duper extended payload? */
2303                 if (payload == 127) {
2304                     len = 8;
2305                     if (plaintext) {
2306                         rv = apr_socket_recv(sock, (char*) &payload_long, &len);
2307                     }
2308                     else {
2309                         rv = lua_websocket_readbytes(r->connection, 
2310                                 (char*) &payload_long, 8);
2311                     }
2312                     if (rv == APR_SUCCESS) {
2313                         plen = ap_ntoh64(&payload_long);
2314                     }
2315                     else {
2316                         return 0;
2317                     }
2318                 }
2319                 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03210)
2320                               "Websocket: Reading %" APR_SIZE_T_FMT " (%s) bytes, masking is %s. %s", 
2321                               plen,
2322                               (payload >= 126) ? "extra payload" : "no extra payload", 
2323                               mask ? "on" : "off", 
2324                               fin ? "This is a final frame" : "more to follow");
2325                 if (mask) {
2326                     len = 4;
2327                     if (plaintext) {
2328                         rv = apr_socket_recv(sock, (char*) mask_bytes, &len);
2329                     }
2330                     else {
2331                         rv = lua_websocket_readbytes(r->connection, 
2332                                 (char*) mask_bytes, 4);
2333                     }
2334                     if (rv != APR_SUCCESS) {
2335                         return 0;
2336                     }
2337                 }
2338                 if (plen < (HUGE_STRING_LEN*1024) && plen > 0) {
2339                     apr_size_t remaining = plen;
2340                     apr_size_t received;
2341                     apr_off_t at = 0;
2342                     char *buffer = apr_palloc(r->pool, plen+1);
2343                     buffer[plen] = 0;
2344
2345                     if (plaintext) {
2346                         while (remaining > 0) {
2347                             received = remaining;
2348                             rv = apr_socket_recv(sock, buffer+at, &received);
2349                             if (received > 0 ) {
2350                                 remaining -= received;
2351                                 at += received;
2352                             }
2353                         }
2354                         ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, 
2355                                 "Websocket: Frame contained %" APR_OFF_T_FMT " bytes, pushed to Lua stack", 
2356                                 at);
2357                     }
2358                     else {
2359                         rv = lua_websocket_readbytes(r->connection, buffer, 
2360                                 remaining);
2361                         ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, 
2362                                 "Websocket: SSL Frame contained %" APR_SIZE_T_FMT " bytes, "\
2363                                 "pushed to Lua stack", 
2364                                 remaining);
2365                     }
2366                     if (mask) {
2367                         for (n = 0; n < plen; n++) {
2368                             buffer[n] ^= mask_bytes[n%4];
2369                         }
2370                     }
2371
2372                     lua_pushlstring(L, buffer, (size_t) plen); /* push to stack */
2373                     lua_pushboolean(L, fin); /* push FIN bit to stack as boolean */
2374                     return 2;
2375                 }
2376
2377
2378                 /* Decide if we need to react to the opcode or not */
2379                 if (opcode == 0x09) { /* ping */
2380                     char frame[2];
2381                     plen = 2;
2382                     frame[0] = 0x8A;
2383                     frame[1] = 0;
2384                     apr_socket_send(sock, frame, &plen); /* Pong! */
2385                     do_read = 1;
2386                 }
2387             }
2388         }
2389     }
2390     return 0;
2391 }
2392
2393
2394 static int lua_websocket_write(lua_State *L) 
2395 {
2396     const char *string;
2397     apr_status_t rv;
2398     size_t len;
2399     int raw = 0;
2400     char prelude;
2401     request_rec *r = ap_lua_check_request_rec(L, 1);
2402     
2403     if (lua_isboolean(L, 3)) {
2404         raw = lua_toboolean(L, 3);
2405     }
2406     string = lua_tolstring(L, 2, &len);
2407     
2408     if (raw != 1) {
2409         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03013) 
2410                       "Websocket: Writing framed message to client");
2411         
2412         prelude = 0x81; /* text frame, FIN */
2413         ap_rputc(prelude, r);
2414         if (len < 126) {
2415             ap_rputc(len, r);
2416         } 
2417         else if (len < 65535) {
2418             apr_uint16_t slen = len;
2419             ap_rputc(126, r); 
2420             slen = htons(slen);
2421             ap_rwrite((char*) &slen, 2, r);
2422         }
2423         else {
2424             apr_uint64_t llen = len;
2425             ap_rputc(127, r);
2426             llen = ap_ntoh64(&llen); /* ntoh doubles as hton */
2427             ap_rwrite((char*) &llen, 8, r);
2428         }
2429     }
2430     else {
2431         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03014) 
2432                       "Websocket: Writing raw message to client");
2433     }
2434     ap_rwrite(string, len, r);
2435     rv = ap_rflush(r);
2436     if (rv == APR_SUCCESS) {
2437         lua_pushboolean(L, 1);
2438     }
2439     else {
2440         lua_pushboolean(L, 0);
2441     }
2442     return 1;
2443 }
2444
2445
2446 static int lua_websocket_close(lua_State *L) 
2447 {
2448     apr_socket_t *sock;
2449     char prelude[2];
2450     request_rec *r = ap_lua_check_request_rec(L, 1);
2451     
2452     sock = ap_get_conn_socket(r->connection);
2453     
2454     /* Send a header that says: socket is closing. */
2455     prelude[0] = 0x88; /* closing socket opcode */
2456     prelude[1] = 0; /* zero length frame */
2457     ap_rwrite(prelude, 2, r);
2458     
2459     /* Close up tell the MPM and filters to back off */
2460     apr_socket_close(sock);
2461     r->output_filters = NULL;
2462     r->connection->keepalive = AP_CONN_CLOSE;
2463     return 0;
2464 }
2465
2466 static int lua_websocket_ping(lua_State *L) 
2467 {
2468     apr_socket_t *sock;
2469     apr_size_t plen;
2470     char prelude[2];
2471     apr_status_t rv;
2472     request_rec *r = ap_lua_check_request_rec(L, 1);
2473     sock = ap_get_conn_socket(r->connection);
2474     
2475     /* Send a header that says: PING. */
2476     prelude[0] = 0x89; /* ping  opcode */
2477     prelude[1] = 0;
2478     plen = 2;
2479     apr_socket_send(sock, prelude, &plen);
2480     
2481     
2482     /* Get opcode and FIN bit from pong */
2483     plen = 2;
2484     rv = apr_socket_recv(sock, prelude, &plen);
2485     if (rv == APR_SUCCESS) {
2486         unsigned char opcode = prelude[0];
2487         unsigned char len = prelude[1];
2488         unsigned char mask = len >> 7;
2489         if (mask) len -= 128;
2490         plen = len;
2491         ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03015) 
2492                       "Websocket: Got PONG opcode: %x", opcode);
2493         if (opcode == 0x8A) {
2494             lua_pushboolean(L, 1);
2495         }
2496         else {
2497             lua_pushboolean(L, 0);
2498         }
2499         if (plen > 0) {
2500             ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, 
2501                           "Websocket: Reading %" APR_SIZE_T_FMT " bytes of PONG", plen);
2502             return 1;
2503         }
2504         if (mask) {
2505             plen = 2;
2506             apr_socket_recv(sock, prelude, &plen);
2507             plen = 2;
2508             apr_socket_recv(sock, prelude, &plen);
2509         }
2510     }
2511     else {
2512         lua_pushboolean(L, 0);
2513     }
2514     return 1;
2515 }
2516
2517
2518 #define APLUA_REQ_TRACE(lev) static int req_trace##lev(lua_State *L)  \
2519 {                                                               \
2520     return req_log_at(L, APLOG_TRACE##lev);                     \
2521 }
2522
2523 APLUA_REQ_TRACE(1)
2524 APLUA_REQ_TRACE(2)
2525 APLUA_REQ_TRACE(3)
2526 APLUA_REQ_TRACE(4)
2527 APLUA_REQ_TRACE(5)
2528 APLUA_REQ_TRACE(6)
2529 APLUA_REQ_TRACE(7)
2530 APLUA_REQ_TRACE(8)
2531
2532 /* handle r.status = 201 */
2533 static int req_newindex(lua_State *L)
2534 {
2535     const char *key;
2536     /* request_rec* r = lua_touserdata(L, lua_upvalueindex(1)); */
2537     /* const char* key = luaL_checkstring(L, -2); */
2538     request_rec *r = ap_lua_check_request_rec(L, 1);
2539     key = luaL_checkstring(L, 2);
2540
2541     if (0 == strcmp("args", key)) {
2542         const char *value = luaL_checkstring(L, 3);
2543         r->args = apr_pstrdup(r->pool, value);
2544         return 0;
2545     }
2546
2547     if (0 == strcmp("content_type", key)) {
2548         const char *value = luaL_checkstring(L, 3);
2549         ap_set_content_type(r, apr_pstrdup(r->pool, value));
2550         return 0;
2551     }
2552
2553     if (0 == strcmp("filename", key)) {
2554         const char *value = luaL_checkstring(L, 3);
2555         r->filename = apr_pstrdup(r->pool, value);
2556         return 0;
2557     }
2558
2559     if (0 == strcmp("handler", key)) {
2560         const char *value = luaL_checkstring(L, 3);
2561         r->handler = apr_pstrdup(r->pool, value);
2562         return 0;
2563     }
2564
2565     if (0 == strcmp("proxyreq", key)) {
2566         int value = luaL_checkinteger(L, 3);
2567         r->proxyreq = value;
2568         return 0;
2569     }
2570
2571     if (0 == strcmp("status", key)) {
2572         int code = luaL_checkinteger(L, 3);
2573         r->status = code;
2574         return 0;
2575     }
2576
2577     if (0 == strcmp("uri", key)) {
2578         const char *value = luaL_checkstring(L, 3);
2579         r->uri = apr_pstrdup(r->pool, value);
2580         return 0;
2581     }
2582
2583     if (0 == strcmp("user", key)) {
2584         const char *value = luaL_checkstring(L, 3);
2585         r->user = apr_pstrdup(r->pool, value);
2586         return 0;
2587     }
2588
2589     lua_pushstring(L,
2590                    apr_psprintf(r->pool,
2591                                 "Property [%s] may not be set on a request_rec",
2592                                 key));
2593     lua_error(L);
2594     return 0;
2595 }
2596
2597
2598
2599 /* helper function for walking config trees */
2600 static void read_cfg_tree(lua_State *L, request_rec *r, ap_directive_t *rcfg) {
2601     int x = 0;
2602     const char* value;
2603     ap_directive_t *cfg;
2604     lua_newtable(L);
2605     
2606     for (cfg = rcfg; cfg; cfg = cfg->next) {
2607         x++;
2608         lua_pushnumber(L, x);
2609         lua_newtable(L);
2610         value = apr_psprintf(r->pool, "%s %s", cfg->directive, cfg->args);
2611         lua_pushstring(L, "directive");
2612         lua_pushstring(L, value);
2613         lua_settable(L, -3);
2614         lua_pushstring(L, "file");
2615         lua_pushstring(L, cfg->filename);
2616         lua_settable(L, -3);
2617         lua_pushstring(L, "line");
2618         lua_pushnumber(L, cfg->line_num);
2619         lua_settable(L, -3);
2620         if (cfg->first_child) {
2621             lua_pushstring(L, "children");
2622             read_cfg_tree(L, r, cfg->first_child);
2623             lua_settable(L, -3);
2624         }
2625         lua_settable(L, -3);
2626     }
2627 }
2628
2629 static int lua_ap_get_config(lua_State *L) {
2630     request_rec *r = ap_lua_check_request_rec(L, 1);   
2631     read_cfg_tree(L, r, ap_conftree);
2632     
2633     return 1;
2634 }
2635
2636
2637 /* Hack, hack, hack...! TODO: Make this actually work properly */
2638 static int lua_ap_get_active_config(lua_State *L) {
2639     ap_directive_t *subdir;
2640     ap_directive_t *dir = ap_conftree;
2641     request_rec *r = ap_lua_check_request_rec(L, 1);
2642     
2643     for (dir = ap_conftree; dir; dir = dir->next) {
2644         if (ap_strcasestr(dir->directive, "<virtualhost") && dir->first_child) {
2645             for (subdir = dir->first_child; subdir; subdir = subdir->next) {
2646                 if (ap_strcasecmp_match(subdir->directive, "servername") &&
2647                         !ap_strcasecmp_match(r->hostname, subdir->args)) {
2648                     read_cfg_tree(L, r, dir->first_child);
2649                     return 1;
2650                 }
2651                 if (ap_strcasecmp_match(subdir->directive, "serveralias") &&
2652                         !ap_strcasecmp_match(r->hostname, subdir->args)) {
2653                     read_cfg_tree(L, r, dir->first_child);
2654                     return 1;
2655                 }
2656             }
2657         }
2658     }     
2659     return 0;
2660 }
2661
2662
2663
2664 static const struct luaL_Reg request_methods[] = {
2665     {"__index", req_dispatch},
2666     {"__newindex", req_newindex},
2667     /*   {"__newindex", req_set_field}, */
2668     {NULL, NULL}
2669 };
2670
2671
2672 static const struct luaL_Reg connection_methods[] = {
2673     {NULL, NULL}
2674 };
2675
2676 static const char* lua_ap_auth_name(request_rec* r)
2677 {
2678     const char *name;
2679     name = ap_auth_name(r);
2680     return name ? name : "";
2681 }
2682
2683 static const char* lua_ap_get_server_name(request_rec* r)
2684 {
2685     const char *name;
2686     name = ap_get_server_name(r);
2687     return name ? name : "localhost";
2688 }
2689
2690
2691
2692
2693 static const struct luaL_Reg server_methods[] = {
2694     {NULL, NULL}
2695 };
2696
2697
2698 static req_fun_t *makefun(const void *fun, int type, apr_pool_t *pool)
2699 {
2700     req_fun_t *rft = apr_palloc(pool, sizeof(req_fun_t));
2701     rft->fun = fun;
2702     rft->type = type;
2703     return rft;
2704 }
2705
2706 void ap_lua_load_request_lmodule(lua_State *L, apr_pool_t *p)
2707 {
2708
2709     apr_hash_t *dispatch = apr_hash_make(p);
2710
2711     apr_hash_set(dispatch, "puts", APR_HASH_KEY_STRING,
2712                  makefun(&req_puts, APL_REQ_FUNTYPE_LUACFUN, p));
2713     apr_hash_set(dispatch, "write", APR_HASH_KEY_STRING,
2714                  makefun(&req_write, APL_REQ_FUNTYPE_LUACFUN, p));
2715     apr_hash_set(dispatch, "document_root", APR_HASH_KEY_STRING,
2716                  makefun(&req_document_root, APL_REQ_FUNTYPE_STRING, p));
2717     apr_hash_set(dispatch, "context_prefix", APR_HASH_KEY_STRING,
2718                  makefun(&req_context_prefix, APL_REQ_FUNTYPE_STRING, p));
2719     apr_hash_set(dispatch, "context_document_root", APR_HASH_KEY_STRING,
2720                  makefun(&req_context_document_root, APL_REQ_FUNTYPE_STRING, p));
2721     apr_hash_set(dispatch, "parseargs", APR_HASH_KEY_STRING,
2722                  makefun(&req_parseargs, APL_REQ_FUNTYPE_LUACFUN, p));
2723     apr_hash_set(dispatch, "parsebody", APR_HASH_KEY_STRING,
2724                  makefun(&req_parsebody, APL_REQ_FUNTYPE_LUACFUN, p));
2725     apr_hash_set(dispatch, "debug", APR_HASH_KEY_STRING,
2726                  makefun(&req_debug, APL_REQ_FUNTYPE_LUACFUN, p));
2727     apr_hash_set(dispatch, "info", APR_HASH_KEY_STRING,
2728                  makefun(&req_info, APL_REQ_FUNTYPE_LUACFUN, p));
2729     apr_hash_set(dispatch, "notice", APR_HASH_KEY_STRING,
2730                  makefun(&req_notice, APL_REQ_FUNTYPE_LUACFUN, p));
2731     apr_hash_set(dispatch, "warn", APR_HASH_KEY_STRING,
2732                  makefun(&req_warn, APL_REQ_FUNTYPE_LUACFUN, p));
2733     apr_hash_set(dispatch, "err", APR_HASH_KEY_STRING,
2734                  makefun(&req_err, APL_REQ_FUNTYPE_LUACFUN, p));
2735     apr_hash_set(dispatch, "crit", APR_HASH_KEY_STRING,
2736                  makefun(&req_crit, APL_REQ_FUNTYPE_LUACFUN, p));
2737     apr_hash_set(dispatch, "alert", APR_HASH_KEY_STRING,
2738                  makefun(&req_alert, APL_REQ_FUNTYPE_LUACFUN, p));
2739     apr_hash_set(dispatch, "emerg", APR_HASH_KEY_STRING,
2740                  makefun(&req_emerg, APL_REQ_FUNTYPE_LUACFUN, p));
2741     apr_hash_set(dispatch, "trace1", APR_HASH_KEY_STRING,
2742                  makefun(&req_trace1, APL_REQ_FUNTYPE_LUACFUN, p));
2743     apr_hash_set(dispatch, "trace2", APR_HASH_KEY_STRING,
2744                  makefun(&req_trace2, APL_REQ_FUNTYPE_LUACFUN, p));
2745     apr_hash_set(dispatch, "trace3", APR_HASH_KEY_STRING,
2746                  makefun(&req_trace3, APL_REQ_FUNTYPE_LUACFUN, p));
2747     apr_hash_set(dispatch, "trace4", APR_HASH_KEY_STRING,
2748                  makefun(&req_trace4, APL_REQ_FUNTYPE_LUACFUN, p));
2749     apr_hash_set(dispatch, "trace5", APR_HASH_KEY_STRING,
2750                  makefun(&req_trace5, APL_REQ_FUNTYPE_LUACFUN, p));
2751     apr_hash_set(dispatch, "trace6", APR_HASH_KEY_STRING,
2752                  makefun(&req_trace6, APL_REQ_FUNTYPE_LUACFUN, p));
2753     apr_hash_set(dispatch, "trace7", APR_HASH_KEY_STRING,
2754                  makefun(&req_trace7, APL_REQ_FUNTYPE_LUACFUN, p));
2755     apr_hash_set(dispatch, "trace8", APR_HASH_KEY_STRING,
2756                  makefun(&req_trace8, APL_REQ_FUNTYPE_LUACFUN, p));
2757     apr_hash_set(dispatch, "add_output_filter", APR_HASH_KEY_STRING,
2758                  makefun(&req_add_output_filter, APL_REQ_FUNTYPE_LUACFUN, p));
2759     apr_hash_set(dispatch, "construct_url", APR_HASH_KEY_STRING,
2760                  makefun(&req_construct_url, APL_REQ_FUNTYPE_LUACFUN, p));
2761     apr_hash_set(dispatch, "escape_html", APR_HASH_KEY_STRING,
2762                  makefun(&req_escape_html, APL_REQ_FUNTYPE_LUACFUN, p));
2763     apr_hash_set(dispatch, "ssl_var_lookup", APR_HASH_KEY_STRING,
2764                  makefun(&req_ssl_var_lookup, APL_REQ_FUNTYPE_LUACFUN, p));
2765     apr_hash_set(dispatch, "is_https", APR_HASH_KEY_STRING,
2766                  makefun(&req_ssl_is_https_field, APL_REQ_FUNTYPE_BOOLEAN, p));
2767     apr_hash_set(dispatch, "assbackwards", APR_HASH_KEY_STRING,
2768                  makefun(&req_assbackwards_field, APL_REQ_FUNTYPE_BOOLEAN, p));
2769     apr_hash_set(dispatch, "status", APR_HASH_KEY_STRING,
2770                  makefun(&req_status_field, APL_REQ_FUNTYPE_INT, p));
2771     apr_hash_set(dispatch, "protocol", APR_HASH_KEY_STRING,
2772                  makefun(&req_protocol_field, APL_REQ_FUNTYPE_STRING, p));
2773     apr_hash_set(dispatch, "range", APR_HASH_KEY_STRING,
2774                  makefun(&req_range_field, APL_REQ_FUNTYPE_STRING, p));
2775     apr_hash_set(dispatch, "content_type", APR_HASH_KEY_STRING,
2776                  makefun(&req_content_type_field, APL_REQ_FUNTYPE_STRING, p));
2777     apr_hash_set(dispatch, "content_encoding", APR_HASH_KEY_STRING,
2778                  makefun(&req_content_encoding_field, APL_REQ_FUNTYPE_STRING,
2779                          p));
2780     apr_hash_set(dispatch, "ap_auth_type", APR_HASH_KEY_STRING,
2781                  makefun(&req_ap_auth_type_field, APL_REQ_FUNTYPE_STRING, p));
2782     apr_hash_set(dispatch, "unparsed_uri", APR_HASH_KEY_STRING,
2783                  makefun(&req_unparsed_uri_field, APL_REQ_FUNTYPE_STRING, p));
2784     apr_hash_set(dispatch, "user", APR_HASH_KEY_STRING,
2785                  makefun(&req_user_field, APL_REQ_FUNTYPE_STRING, p));
2786     apr_hash_set(dispatch, "filename", APR_HASH_KEY_STRING,
2787                  makefun(&req_filename_field, APL_REQ_FUNTYPE_STRING, p));
2788     apr_hash_set(dispatch, "canonical_filename", APR_HASH_KEY_STRING,
2789                  makefun(&req_canonical_filename_field,
2790                          APL_REQ_FUNTYPE_STRING, p));
2791     apr_hash_set(dispatch, "path_info", APR_HASH_KEY_STRING,
2792                  makefun(&req_path_info_field, APL_REQ_FUNTYPE_STRING, p));
2793     apr_hash_set(dispatch, "args", APR_HASH_KEY_STRING,
2794                  makefun(&req_args_field, APL_REQ_FUNTYPE_STRING, p));
2795     apr_hash_set(dispatch, "handler", APR_HASH_KEY_STRING,
2796                  makefun(&req_handler_field, APL_REQ_FUNTYPE_STRING, p));
2797     apr_hash_set(dispatch, "hostname", APR_HASH_KEY_STRING,
2798                  makefun(&req_hostname_field, APL_REQ_FUNTYPE_STRING, p));
2799     apr_hash_set(dispatch, "uri", APR_HASH_KEY_STRING,
2800                  makefun(&req_uri_field, APL_REQ_FUNTYPE_STRING, p));
2801     apr_hash_set(dispatch, "the_request", APR_HASH_KEY_STRING,
2802                  makefun(&req_the_request_field, APL_REQ_FUNTYPE_STRING, p));
2803     apr_hash_set(dispatch, "log_id", APR_HASH_KEY_STRING,
2804                  makefun(&req_log_id_field, APL_REQ_FUNTYPE_STRING, p));
2805     apr_hash_set(dispatch, "useragent_ip", APR_HASH_KEY_STRING,
2806                  makefun(&req_useragent_ip_field, APL_REQ_FUNTYPE_STRING, p));
2807     apr_hash_set(dispatch, "method", APR_HASH_KEY_STRING,
2808                  makefun(&req_method_field, APL_REQ_FUNTYPE_STRING, p));
2809     apr_hash_set(dispatch, "proxyreq", APR_HASH_KEY_STRING,
2810                  makefun(&req_proxyreq_field, APL_REQ_FUNTYPE_STRING, p));
2811     apr_hash_set(dispatch, "headers_in", APR_HASH_KEY_STRING,
2812                  makefun(&req_headers_in, APL_REQ_FUNTYPE_TABLE, p));
2813     apr_hash_set(dispatch, "headers_out", APR_HASH_KEY_STRING,
2814                  makefun(&req_headers_out, APL_REQ_FUNTYPE_TABLE, p));
2815     apr_hash_set(dispatch, "err_headers_out", APR_HASH_KEY_STRING,
2816                  makefun(&req_err_headers_out, APL_REQ_FUNTYPE_TABLE, p));
2817     apr_hash_set(dispatch, "notes", APR_HASH_KEY_STRING,
2818                  makefun(&req_notes, APL_REQ_FUNTYPE_TABLE, p));
2819     apr_hash_set(dispatch, "subprocess_env", APR_HASH_KEY_STRING,
2820                  makefun(&req_subprocess_env, APL_REQ_FUNTYPE_TABLE, p));
2821     apr_hash_set(dispatch, "flush", APR_HASH_KEY_STRING,
2822                  makefun(&lua_ap_rflush, APL_REQ_FUNTYPE_LUACFUN, p));
2823     apr_hash_set(dispatch, "port", APR_HASH_KEY_STRING,
2824                  makefun(&req_ap_get_server_port, APL_REQ_FUNTYPE_INT, p));
2825     apr_hash_set(dispatch, "banner", APR_HASH_KEY_STRING,
2826                  makefun(&ap_get_server_banner, APL_REQ_FUNTYPE_STRING, p));
2827     apr_hash_set(dispatch, "options", APR_HASH_KEY_STRING,
2828                  makefun(&lua_ap_options, APL_REQ_FUNTYPE_STRING, p));
2829     apr_hash_set(dispatch, "allowoverrides", APR_HASH_KEY_STRING,
2830                  makefun(&lua_ap_allowoverrides, APL_REQ_FUNTYPE_STRING, p));
2831     apr_hash_set(dispatch, "started", APR_HASH_KEY_STRING,
2832                  makefun(&lua_ap_started, APL_REQ_FUNTYPE_INT, p));
2833     apr_hash_set(dispatch, "basic_auth_pw", APR_HASH_KEY_STRING,
2834                  makefun(&lua_ap_basic_auth_pw, APL_REQ_FUNTYPE_STRING, p));
2835     apr_hash_set(dispatch, "limit_req_body", APR_HASH_KEY_STRING,
2836                  makefun(&lua_ap_limit_req_body, APL_REQ_FUNTYPE_INT, p));
2837     apr_hash_set(dispatch, "server_built", APR_HASH_KEY_STRING,
2838                  makefun(&ap_get_server_built, APL_REQ_FUNTYPE_STRING, p));
2839     apr_hash_set(dispatch, "is_initial_req", APR_HASH_KEY_STRING,
2840                  makefun(&lua_ap_is_initial_req, APL_REQ_FUNTYPE_BOOLEAN, p));
2841     apr_hash_set(dispatch, "remaining", APR_HASH_KEY_STRING,
2842                  makefun(&req_remaining_field, APL_REQ_FUNTYPE_INT, p));
2843     apr_hash_set(dispatch, "some_auth_required", APR_HASH_KEY_STRING,
2844                  makefun(&lua_ap_some_auth_required, APL_REQ_FUNTYPE_BOOLEAN, p));
2845     apr_hash_set(dispatch, "server_name", APR_HASH_KEY_STRING,
2846                  makefun(&lua_ap_get_server_name, APL_REQ_FUNTYPE_STRING, p));
2847     apr_hash_set(dispatch, "auth_name", APR_HASH_KEY_STRING,
2848                  makefun(&lua_ap_auth_name, APL_REQ_FUNTYPE_STRING, p));
2849     apr_hash_set(dispatch, "sendfile", APR_HASH_KEY_STRING,
2850                  makefun(&lua_ap_sendfile, APL_REQ_FUNTYPE_LUACFUN, p));
2851     apr_hash_set(dispatch, "dbacquire", APR_HASH_KEY_STRING,
2852                  makefun(&lua_db_acquire, APL_REQ_FUNTYPE_LUACFUN, p));
2853     apr_hash_set(dispatch, "stat", APR_HASH_KEY_STRING,
2854                  makefun(&lua_ap_stat, APL_REQ_FUNTYPE_LUACFUN, p));
2855     apr_hash_set(dispatch, "get_direntries", APR_HASH_KEY_STRING,
2856                  makefun(&lua_ap_getdir, APL_REQ_FUNTYPE_LUACFUN, p));
2857     apr_hash_set(dispatch, "regex", APR_HASH_KEY_STRING,
2858                  makefun(&lua_ap_regex, APL_REQ_FUNTYPE_LUACFUN, p));
2859     apr_hash_set(dispatch, "usleep", APR_HASH_KEY_STRING,
2860                  makefun(&lua_ap_usleep, APL_REQ_FUNTYPE_LUACFUN, p));
2861     apr_hash_set(dispatch, "base64_encode", APR_HASH_KEY_STRING,
2862                  makefun(&lua_apr_b64encode, APL_REQ_FUNTYPE_LUACFUN, p));
2863     apr_hash_set(dispatch, "base64_decode", APR_HASH_KEY_STRING,
2864                  makefun(&lua_apr_b64decode, APL_REQ_FUNTYPE_LUACFUN, p));
2865     apr_hash_set(dispatch, "md5", APR_HASH_KEY_STRING,
2866                  makefun(&lua_apr_md5, APL_REQ_FUNTYPE_LUACFUN, p));
2867     apr_hash_set(dispatch, "sha1", APR_HASH_KEY_STRING,
2868                  makefun(&lua_apr_sha1, APL_REQ_FUNTYPE_LUACFUN, p));
2869     apr_hash_set(dispatch, "htpassword", APR_HASH_KEY_STRING,
2870                  makefun(&lua_apr_htpassword, APL_REQ_FUNTYPE_LUACFUN, p));
2871     apr_hash_set(dispatch, "touch", APR_HASH_KEY_STRING,
2872                  makefun(&lua_apr_touch, APL_REQ_FUNTYPE_LUACFUN, p));
2873     apr_hash_set(dispatch, "mkdir", APR_HASH_KEY_STRING,
2874                  makefun(&lua_apr_mkdir, APL_REQ_FUNTYPE_LUACFUN, p));
2875     apr_hash_set(dispatch, "mkrdir", APR_HASH_KEY_STRING,
2876                  makefun(&lua_apr_mkrdir, APL_REQ_FUNTYPE_LUACFUN, p));
2877     apr_hash_set(dispatch, "rmdir", APR_HASH_KEY_STRING,
2878                  makefun(&lua_apr_rmdir, APL_REQ_FUNTYPE_LUACFUN, p));
2879     apr_hash_set(dispatch, "date_parse_rfc", APR_HASH_KEY_STRING,
2880                  makefun(&lua_apr_date_parse_rfc, APL_REQ_FUNTYPE_LUACFUN, p));
2881     apr_hash_set(dispatch, "escape", APR_HASH_KEY_STRING,
2882                  makefun(&lua_ap_escape, APL_REQ_FUNTYPE_LUACFUN, p));
2883     apr_hash_set(dispatch, "unescape", APR_HASH_KEY_STRING,
2884                  makefun(&lua_ap_unescape, APL_REQ_FUNTYPE_LUACFUN, p));
2885     apr_hash_set(dispatch, "mpm_query", APR_HASH_KEY_STRING,
2886                  makefun(&lua_ap_mpm_query, APL_REQ_FUNTYPE_LUACFUN, p));
2887     apr_hash_set(dispatch, "expr", APR_HASH_KEY_STRING,
2888                  makefun(&lua_ap_expr, APL_REQ_FUNTYPE_LUACFUN, p));
2889     apr_hash_set(dispatch, "scoreboard_process", APR_HASH_KEY_STRING,
2890                  makefun(&lua_ap_scoreboard_process, APL_REQ_FUNTYPE_LUACFUN, p));
2891     apr_hash_set(dispatch, "scoreboard_worker", APR_HASH_KEY_STRING,
2892                  makefun(&lua_ap_scoreboard_worker, APL_REQ_FUNTYPE_LUACFUN, p));
2893     apr_hash_set(dispatch, "clock", APR_HASH_KEY_STRING,
2894                  makefun(&lua_ap_clock, APL_REQ_FUNTYPE_LUACFUN, p));
2895     apr_hash_set(dispatch, "requestbody", APR_HASH_KEY_STRING,
2896                  makefun(&lua_ap_requestbody, APL_REQ_FUNTYPE_LUACFUN, p));
2897     apr_hash_set(dispatch, "add_input_filter", APR_HASH_KEY_STRING,
2898                  makefun(&lua_ap_add_input_filter, APL_REQ_FUNTYPE_LUACFUN, p));
2899     apr_hash_set(dispatch, "module_info", APR_HASH_KEY_STRING,
2900                  makefun(&lua_ap_module_info, APL_REQ_FUNTYPE_LUACFUN, p));
2901     apr_hash_set(dispatch, "loaded_modules", APR_HASH_KEY_STRING,
2902                  makefun(&lua_ap_loaded_modules, APL_REQ_FUNTYPE_LUACFUN, p));
2903     apr_hash_set(dispatch, "runtime_dir_relative", APR_HASH_KEY_STRING,
2904                  makefun(&lua_ap_runtime_dir_relative, APL_REQ_FUNTYPE_LUACFUN, p));
2905     apr_hash_set(dispatch, "server_info", APR_HASH_KEY_STRING,
2906                  makefun(&lua_ap_server_info, APL_REQ_FUNTYPE_LUACFUN, p));
2907     apr_hash_set(dispatch, "set_document_root", APR_HASH_KEY_STRING,
2908                  makefun(&lua_ap_set_document_root, APL_REQ_FUNTYPE_LUACFUN, p));
2909     apr_hash_set(dispatch, "set_context_info", APR_HASH_KEY_STRING,
2910                  makefun(&lua_ap_set_context_info, APL_REQ_FUNTYPE_LUACFUN, p));
2911     apr_hash_set(dispatch, "os_escape_path", APR_HASH_KEY_STRING,
2912                  makefun(&lua_ap_os_escape_path, APL_REQ_FUNTYPE_LUACFUN, p));
2913     apr_hash_set(dispatch, "escape_logitem", APR_HASH_KEY_STRING,
2914                  makefun(&lua_ap_escape_logitem, APL_REQ_FUNTYPE_LUACFUN, p));
2915     apr_hash_set(dispatch, "strcmp_match", APR_HASH_KEY_STRING,
2916                  makefun(&lua_ap_strcmp_match, APL_REQ_FUNTYPE_LUACFUN, p));
2917     apr_hash_set(dispatch, "set_keepalive", APR_HASH_KEY_STRING,
2918                  makefun(&lua_ap_set_keepalive, APL_REQ_FUNTYPE_LUACFUN, p));
2919     apr_hash_set(dispatch, "make_etag", APR_HASH_KEY_STRING,
2920                  makefun(&lua_ap_make_etag, APL_REQ_FUNTYPE_LUACFUN, p));
2921     apr_hash_set(dispatch, "send_interim_response", APR_HASH_KEY_STRING,
2922                  makefun(&lua_ap_send_interim_response, APL_REQ_FUNTYPE_LUACFUN, p));
2923     apr_hash_set(dispatch, "custom_response", APR_HASH_KEY_STRING,
2924                  makefun(&lua_ap_custom_response, APL_REQ_FUNTYPE_LUACFUN, p));
2925     apr_hash_set(dispatch, "exists_config_define", APR_HASH_KEY_STRING,
2926                  makefun(&lua_ap_exists_config_define, APL_REQ_FUNTYPE_LUACFUN, p));
2927     apr_hash_set(dispatch, "state_query", APR_HASH_KEY_STRING,
2928                  makefun(&lua_ap_state_query, APL_REQ_FUNTYPE_LUACFUN, p));
2929     apr_hash_set(dispatch, "get_server_name_for_url", APR_HASH_KEY_STRING,
2930                  makefun(&lua_ap_get_server_name_for_url, APL_REQ_FUNTYPE_LUACFUN, p));
2931     apr_hash_set(dispatch, "ivm_get", APR_HASH_KEY_STRING,
2932                  makefun(&lua_ivm_get, APL_REQ_FUNTYPE_LUACFUN, p));
2933     apr_hash_set(dispatch, "ivm_set", APR_HASH_KEY_STRING,
2934                  makefun(&lua_ivm_set, APL_REQ_FUNTYPE_LUACFUN, p));
2935     apr_hash_set(dispatch, "getcookie", APR_HASH_KEY_STRING,
2936                  makefun(&lua_get_cookie, APL_REQ_FUNTYPE_LUACFUN, p));
2937     apr_hash_set(dispatch, "setcookie", APR_HASH_KEY_STRING,
2938                  makefun(&lua_set_cookie, APL_REQ_FUNTYPE_LUACFUN, p));
2939     apr_hash_set(dispatch, "wsupgrade", APR_HASH_KEY_STRING,
2940                  makefun(&lua_websocket_greet, APL_REQ_FUNTYPE_LUACFUN, p));
2941     apr_hash_set(dispatch, "wsread", APR_HASH_KEY_STRING,
2942                  makefun(&lua_websocket_read, APL_REQ_FUNTYPE_LUACFUN, p));
2943     apr_hash_set(dispatch, "wspeek", APR_HASH_KEY_STRING,
2944                  makefun(&lua_websocket_peek, APL_REQ_FUNTYPE_LUACFUN, p));
2945     apr_hash_set(dispatch, "wswrite", APR_HASH_KEY_STRING,
2946                  makefun(&lua_websocket_write, APL_REQ_FUNTYPE_LUACFUN, p));
2947     apr_hash_set(dispatch, "wsclose", APR_HASH_KEY_STRING,
2948                  makefun(&lua_websocket_close, APL_REQ_FUNTYPE_LUACFUN, p));
2949     apr_hash_set(dispatch, "wsping", APR_HASH_KEY_STRING,
2950                  makefun(&lua_websocket_ping, APL_REQ_FUNTYPE_LUACFUN, p));
2951     apr_hash_set(dispatch, "config", APR_HASH_KEY_STRING,
2952                  makefun(&lua_ap_get_config, APL_REQ_FUNTYPE_LUACFUN, p));
2953     apr_hash_set(dispatch, "activeconfig", APR_HASH_KEY_STRING,
2954                  makefun(&lua_ap_get_active_config, APL_REQ_FUNTYPE_LUACFUN, p));
2955     lua_pushlightuserdata(L, dispatch);
2956     lua_setfield(L, LUA_REGISTRYINDEX, "Apache2.Request.dispatch");
2957
2958     luaL_newmetatable(L, "Apache2.Request");     /* [metatable] */
2959     lua_pushvalue(L, -1);
2960
2961     lua_setfield(L, -2, "__index");
2962     luaL_setfuncs_compat(L, request_methods);    /* [metatable] */
2963
2964     lua_pop(L, 2);
2965
2966     luaL_newmetatable(L, "Apache2.Connection");  /* [metatable] */
2967     lua_pushvalue(L, -1);
2968
2969     lua_setfield(L, -2, "__index");
2970     luaL_setfuncs_compat(L, connection_methods); /* [metatable] */
2971
2972     lua_pop(L, 2);
2973
2974     luaL_newmetatable(L, "Apache2.Server");      /* [metatable] */
2975     lua_pushvalue(L, -1);
2976
2977     lua_setfield(L, -2, "__index");
2978     luaL_setfuncs_compat(L, server_methods);     /* [metatable] */
2979
2980     lua_pop(L, 2);
2981
2982 }
2983
2984 void ap_lua_push_connection(lua_State *L, conn_rec *c)
2985 {
2986     req_table_t* t;
2987     lua_boxpointer(L, c);
2988     luaL_getmetatable(L, "Apache2.Connection");
2989     lua_setmetatable(L, -2);
2990     luaL_getmetatable(L, "Apache2.Connection");
2991
2992     t = apr_pcalloc(c->pool, sizeof(req_table_t));
2993     t->t = c->notes;
2994     t->r = NULL;
2995     t->n = "notes";
2996     ap_lua_push_apr_table(L, t);
2997     lua_setfield(L, -2, "notes");
2998
2999     lua_pushstring(L, c->client_ip);
3000     lua_setfield(L, -2, "client_ip");
3001
3002     lua_pop(L, 1);
3003 }
3004
3005
3006 void ap_lua_push_server(lua_State *L, server_rec *s)
3007 {
3008     lua_boxpointer(L, s);
3009     luaL_getmetatable(L, "Apache2.Server");
3010     lua_setmetatable(L, -2);
3011     luaL_getmetatable(L, "Apache2.Server");
3012
3013     lua_pushstring(L, s->server_hostname);
3014     lua_setfield(L, -2, "server_hostname");
3015
3016     lua_pop(L, 1);
3017 }
3018
3019 void ap_lua_push_request(lua_State *L, request_rec *r)
3020 {
3021     lua_boxpointer(L, r);
3022     luaL_getmetatable(L, "Apache2.Request");
3023     lua_setmetatable(L, -2);
3024 }