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