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