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