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