mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1421780 13f79535-47bb-0310-9956-ffa450edef68
1126 lines
32 KiB
C
1126 lines
32 KiB
C
/**
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "mod_lua.h"
|
|
#include "lua_apr.h"
|
|
|
|
|
|
/**
|
|
* make a userdata out of a C pointer, and vice versa
|
|
* instead of using lightuserdata
|
|
*/
|
|
#ifndef lua_boxpointer
|
|
#define lua_boxpointer(L,u) (*(void **)(lua_newuserdata(L, sizeof(void *))) = (u))
|
|
#define lua_unboxpointer(L,i) (*(void **)(lua_touserdata(L, i)))
|
|
#endif
|
|
|
|
|
|
AP_LUA_DECLARE(apr_table_t*) ap_lua_check_apr_table(lua_State *L, int index)
|
|
{
|
|
apr_table_t *t;
|
|
luaL_checkudata(L, index, "Apr.Table");
|
|
t = (apr_table_t *) lua_unboxpointer(L, index);
|
|
return t;
|
|
}
|
|
|
|
|
|
AP_LUA_DECLARE(void) ap_lua_push_apr_table(lua_State *L, apr_table_t *t)
|
|
{
|
|
lua_boxpointer(L, t);
|
|
luaL_getmetatable(L, "Apr.Table");
|
|
lua_setmetatable(L, -2);
|
|
}
|
|
|
|
static int lua_table_set(lua_State *L)
|
|
{
|
|
apr_table_t *t = ap_lua_check_apr_table(L, 1);
|
|
const char *key = luaL_checkstring(L, 2);
|
|
const char *val = luaL_checkstring(L, 3);
|
|
|
|
apr_table_set(t, key, val);
|
|
return 0;
|
|
}
|
|
|
|
static int lua_table_get(lua_State *L)
|
|
{
|
|
apr_table_t *t = ap_lua_check_apr_table(L, 1);
|
|
const char *key = luaL_checkstring(L, 2);
|
|
const char *val = apr_table_get(t, key);
|
|
lua_pushstring(L, val);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg lua_table_methods[] = {
|
|
{"set", lua_table_set},
|
|
{"get", lua_table_get},
|
|
{0, 0}
|
|
};
|
|
|
|
|
|
AP_LUA_DECLARE(int) ap_lua_init(lua_State *L, apr_pool_t *p)
|
|
{
|
|
luaL_newmetatable(L, "Apr.Table");
|
|
luaL_register(L, "apr_table", lua_table_methods);
|
|
lua_pushstring(L, "__index");
|
|
lua_pushstring(L, "get");
|
|
lua_gettable(L, 2);
|
|
lua_settable(L, 1);
|
|
|
|
lua_pushstring(L, "__newindex");
|
|
lua_pushstring(L, "set");
|
|
lua_gettable(L, 2);
|
|
lua_settable(L, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
=======================================================================================================================
|
|
util_read(request_rec *r, const char **rbuf, apr_off_t *size): Reads any additional form data sent in POST/PUT
|
|
requests.
|
|
=======================================================================================================================
|
|
*/
|
|
static int util_read(request_rec *r, const char **rbuf, apr_off_t *size)
|
|
{
|
|
/*~~~~~~~~*/
|
|
int rc = OK;
|
|
/*~~~~~~~~*/
|
|
|
|
if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
|
|
return (rc);
|
|
}
|
|
|
|
if (ap_should_client_block(r)) {
|
|
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
char argsbuffer[HUGE_STRING_LEN];
|
|
apr_off_t rsize, len_read, rpos = 0;
|
|
apr_off_t length = r->remaining;
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
|
|
*rbuf = (const char *) apr_pcalloc(r->pool, (apr_size_t) (length + 1));
|
|
*size = length;
|
|
while ((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) {
|
|
if ((rpos + len_read) > length) {
|
|
rsize = length - rpos;
|
|
}
|
|
else {
|
|
rsize = len_read;
|
|
}
|
|
|
|
memcpy((char *) *rbuf + rpos, argsbuffer, (size_t) rsize);
|
|
rpos += rsize;
|
|
}
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
/*
|
|
=======================================================================================================================
|
|
util_write(request_rec *r, const char **rbuf, apr_off_t *size): Reads any additional form data sent in POST/PUT
|
|
requests and writes to a file.
|
|
=======================================================================================================================
|
|
*/
|
|
static int util_write(request_rec *r, apr_file_t *file, apr_off_t *size)
|
|
{
|
|
/*~~~~~~~~*/
|
|
int rc = OK;
|
|
/*~~~~~~~~*/
|
|
|
|
if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
|
|
return (rc);
|
|
}
|
|
|
|
if (ap_should_client_block(r)) {
|
|
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
char argsbuffer[HUGE_STRING_LEN];
|
|
apr_off_t rsize, len_read, rpos = 0;
|
|
apr_off_t length = r->remaining;
|
|
apr_size_t written;
|
|
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
|
|
|
|
*size = length;
|
|
while ((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) {
|
|
if ((rpos + len_read) > length) {
|
|
rsize = (apr_size_t) length - rpos;
|
|
}
|
|
else {
|
|
rsize = len_read;
|
|
}
|
|
|
|
rc = apr_file_write_full(file, argsbuffer, (apr_size_t) rsize, &written);
|
|
if (written != rsize) return -1;
|
|
rpos += rsize;
|
|
}
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
static request_rec *ap_lua_check_request_rec(lua_State *L, int index)
|
|
{
|
|
request_rec *r;
|
|
luaL_checkudata(L, index, "Apache2.Request");
|
|
r = (request_rec*) lua_unboxpointer(L, index);
|
|
return r;
|
|
}
|
|
|
|
/* lua_apr_b64encode; r:encode_base64(string) - encodes a string to Base64 format */
|
|
static int lua_apr_b64encode (lua_State *L) {
|
|
const char *plain;
|
|
char *encoded;
|
|
size_t x,y,z;
|
|
request_rec *r;
|
|
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
plain = lua_tolstring(L, 2, &x);
|
|
y = apr_base64_encode_len(x)+1;
|
|
if (y) {
|
|
encoded = apr_palloc(r->pool, y);
|
|
z = apr_base64_encode(encoded, plain, x);
|
|
lua_pushlstring(L, encoded, z);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* lua_apr_b64decode; r:decode_base64(string) - decodes a Base64 string*/
|
|
static int lua_apr_b64decode (lua_State *L) {
|
|
const char *encoded;
|
|
char *plain;
|
|
size_t x,y,z;
|
|
request_rec *r;
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
encoded = lua_tolstring(L, 2, &x);
|
|
y = apr_base64_decode_len(encoded)+1;
|
|
if (y) {
|
|
plain = apr_palloc(r->pool, y);
|
|
z = apr_base64_decode(plain, encoded);
|
|
lua_pushlstring(L, plain, z);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* lua_ap_unescape; r:unescape(string) - Unescapes an URL-encoded string */
|
|
static int lua_ap_unescape (lua_State *L) {
|
|
const char *escaped;
|
|
char *plain;
|
|
size_t x,y;
|
|
request_rec *r;
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
escaped = lua_tolstring(L, 2, &x);
|
|
plain = apr_pstrdup(r->pool, escaped);
|
|
strncpy(plain, escaped, x);
|
|
y = ap_unescape_urlencoded(plain);
|
|
if (!y) {
|
|
lua_pushstring(L, plain);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* lua_ap_escape; r:escape(string) - URL-escapes a string */
|
|
static int lua_ap_escape (lua_State *L) {
|
|
const char *plain;
|
|
char *escaped;
|
|
size_t x;
|
|
request_rec *r;
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
plain = lua_tolstring(L, 2, &x);
|
|
escaped = ap_escape_urlencoded(r->pool, plain);
|
|
lua_pushstring(L, escaped);
|
|
return 1;
|
|
}
|
|
|
|
/* lua_apr_md5; r:md5(string) - Calculates an MD5 digest of a string */
|
|
static int lua_apr_md5(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~*/
|
|
union {
|
|
unsigned char chr[16];
|
|
uint32_t num[4];
|
|
} digest;
|
|
apr_md5_ctx_t md5;
|
|
const char* buffer;
|
|
char* result;
|
|
char Rmd5[16];
|
|
uint32_t *md5X;
|
|
size_t x,y;
|
|
request_rec *r;
|
|
/*~~~~~~~~~~~~~~~~*/
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
result = apr_pcalloc(r->pool, (APR_MD5_DIGESTSIZE*2)+1);
|
|
buffer = lua_tolstring(L, 2, &y);
|
|
apr_md5_init(&md5);
|
|
apr_md5_update(&md5, buffer, y);
|
|
apr_md5_final(digest.chr, &md5);
|
|
|
|
for (x = 0; x < 16; x += 4) {
|
|
Rmd5[x] = digest.chr[x + 3];
|
|
Rmd5[x + 1] = digest.chr[x + 2];
|
|
Rmd5[x + 2] = digest.chr[x + 1];
|
|
Rmd5[x + 3] = digest.chr[x];
|
|
}
|
|
|
|
md5X = (uint32_t *) Rmd5;
|
|
sprintf(result, "%08x%08x%08x%08x", md5X[0], md5X[1], md5X[2], md5X[3]);
|
|
lua_pushstring(L, result);
|
|
return 1;
|
|
}
|
|
|
|
/* lua_apr_sha1; r:sha1(string) - Calculates the SHA1 digest of a string */
|
|
static int lua_apr_sha1(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~*/
|
|
union {
|
|
unsigned char chr[16];
|
|
uint32_t num[4];
|
|
} digest;
|
|
apr_sha1_ctx_t sha1;
|
|
const char* buffer;
|
|
char* result;
|
|
unsigned char Rsha1[20];
|
|
uint32_t *sha1X;
|
|
size_t x,y;
|
|
request_rec *r;
|
|
/*~~~~~~~~~~~~~~~~*/
|
|
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
result = apr_pcalloc(r->pool, (APR_SHA1_DIGESTSIZE*2)+1);
|
|
buffer = lua_tolstring(L, 2, &y);
|
|
apr_sha1_init(&sha1);
|
|
apr_sha1_update(&sha1, buffer, y);
|
|
apr_sha1_final(digest.chr, &sha1);
|
|
|
|
for (x = 0; x < 20; x += 4) {
|
|
Rsha1[x] = digest.chr[x + 3];
|
|
Rsha1[x + 1] = digest.chr[x + 2];
|
|
Rsha1[x + 2] = digest.chr[x + 1];
|
|
Rsha1[x + 3] = digest.chr[x];
|
|
}
|
|
|
|
sha1X = (uint32_t *) Rsha1;
|
|
sprintf(result, "%08x%08x%08x%08x%08x", sha1X[0], sha1X[1], sha1X[2], sha1X[3], sha1X[4]);
|
|
lua_pushstring(L, result);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/* lua_ap_banner; r:banner() - Returns the current server banner */
|
|
static int lua_ap_banner(lua_State *L)
|
|
{
|
|
lua_pushstring(L, ap_get_server_banner());
|
|
return 1;
|
|
}
|
|
|
|
/* lua_ap_port; r:port() - Returns the port used by the request */
|
|
static int lua_ap_port(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
request_rec *r;
|
|
apr_port_t port;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
port = ap_get_server_port(r);
|
|
lua_pushnumber(L, port);
|
|
return 1;
|
|
}
|
|
|
|
/* lua_ap_mpm_query; r:mpm_query(info) - Queries for MPM info */
|
|
static int lua_ap_mpm_query(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
int x,y;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
x = lua_tonumber(L, 1);
|
|
ap_mpm_query(x, &y);
|
|
lua_pushnumber(L, y);
|
|
return 1;
|
|
}
|
|
|
|
/* lua_ap_expr; r:expr(string) - Evaluates an expr statement. */
|
|
static int lua_ap_expr(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
request_rec *r;
|
|
int x = 0;
|
|
const char *expr, *err;
|
|
ap_expr_info_t res;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
expr = lua_tostring(L, 2);
|
|
|
|
|
|
res.filename = NULL;
|
|
res.flags = 0;
|
|
res.line_number = 0;
|
|
res.module_index = 0;
|
|
|
|
err = ap_expr_parse(r->pool, r->pool, &res, expr, NULL);
|
|
if (!err) {
|
|
x = ap_expr_exec(r, &res, &err);
|
|
lua_pushboolean(L, x);
|
|
if (x < 0) {
|
|
lua_pushstring(L, err);
|
|
return 2;
|
|
}
|
|
return 1;
|
|
}
|
|
else {
|
|
lua_pushboolean(L, 0);
|
|
lua_pushstring(L, err);
|
|
return 2;
|
|
}
|
|
lua_pushboolean(L, 0);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* lua_ap_regex; r:regex(string, pattern) - Evaluates a regex and returns captures if matched */
|
|
static int lua_ap_regex(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
request_rec *r;
|
|
int x = 0;
|
|
const char *pattern, *source, *err;
|
|
ap_regex_t regex;
|
|
ap_regmatch_t matches[10];
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
luaL_checktype(L, 3, LUA_TSTRING);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
pattern = lua_tostring(L, 2);
|
|
source = lua_tostring(L, 3);
|
|
|
|
|
|
if (ap_regcomp(®ex, pattern,0)) {
|
|
return 0;
|
|
}
|
|
|
|
int i;
|
|
x = ap_regexec(®ex, source, 10, matches, 0);
|
|
if (x < 0) {
|
|
lua_pushstring(L, err);
|
|
return 1;
|
|
}
|
|
lua_newtable(L);
|
|
for (i=0;i<10;i++) {
|
|
lua_pushinteger(L, i);
|
|
if (matches[i].rm_so >= 0 && matches[i].rm_eo >= 0) {
|
|
lua_pushstring(L,apr_pstrndup(r->pool, source+matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so));
|
|
}
|
|
else {
|
|
lua_pushnil(L);
|
|
}
|
|
lua_settable(L, -3);
|
|
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* lua_ap_scoreboard_process; r:scoreboard_process(a) - returns scoreboard info */
|
|
static int lua_ap_scoreboard_process(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
int i;
|
|
process_score* ps_record;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
luaL_checktype(L, 2, LUA_TNUMBER);
|
|
i = lua_tonumber(L, 2);
|
|
ps_record = ap_get_scoreboard_process(i);
|
|
if (ps_record) {
|
|
lua_newtable(L);
|
|
|
|
lua_pushstring(L, "connections");
|
|
lua_pushnumber(L, ps_record->connections);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "keepalive");
|
|
lua_pushnumber(L, ps_record->keep_alive);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "lingering_close");
|
|
lua_pushnumber(L, ps_record->lingering_close);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "pid");
|
|
lua_pushnumber(L, ps_record->pid);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "suspended");
|
|
lua_pushnumber(L, ps_record->suspended);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "write_completion");
|
|
lua_pushnumber(L, ps_record->write_completion);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "not_accepting");
|
|
lua_pushnumber(L, ps_record->not_accepting);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "quiescing");
|
|
lua_pushnumber(L, ps_record->quiescing);
|
|
lua_settable(L, -3);
|
|
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* lua_ap_scoreboard_worker; r:scoreboard_worker(proc, thread) - Returns thread info */
|
|
static int lua_ap_scoreboard_worker(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
int i,j;
|
|
worker_score* ws_record;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
luaL_checktype(L, 2, LUA_TNUMBER);
|
|
luaL_checktype(L, 3, LUA_TNUMBER);
|
|
i = lua_tonumber(L, 2);
|
|
j = lua_tonumber(L, 3);
|
|
ws_record = ap_get_scoreboard_worker_from_indexes(i, j);
|
|
if (ws_record) {
|
|
lua_newtable(L);
|
|
|
|
lua_pushstring(L, "access_count");
|
|
lua_pushnumber(L, ws_record->access_count);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "bytes_served");
|
|
lua_pushnumber(L, ws_record->bytes_served);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "client");
|
|
lua_pushstring(L, ws_record->client);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "conn_bytes");
|
|
lua_pushnumber(L, ws_record->conn_bytes);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "conn_count");
|
|
lua_pushnumber(L, ws_record->conn_count);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "generation");
|
|
lua_pushnumber(L, ws_record->generation);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "last_used");
|
|
lua_pushnumber(L, ws_record->last_used);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "pid");
|
|
lua_pushnumber(L, ws_record->pid);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "request");
|
|
lua_pushstring(L, ws_record->request);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "start_time");
|
|
lua_pushnumber(L, ws_record->start_time);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "status");
|
|
lua_pushnumber(L, ws_record->status);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "stop_time");
|
|
lua_pushnumber(L, ws_record->stop_time);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "tid");
|
|
lua_pushnumber(L, ws_record->tid);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "vhost");
|
|
lua_pushstring(L, ws_record->vhost);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "stimes");
|
|
lua_pushnumber(L, ws_record->times.tms_stime);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "utimes");
|
|
lua_pushnumber(L, ws_record->times.tms_utime);
|
|
lua_settable(L, -3);
|
|
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* lua_ap_restarted; r:started() - Returns the timestamp of last server (re)start */
|
|
static int lua_ap_restarted(lua_State *L)
|
|
{
|
|
lua_pushnumber(L, ap_scoreboard_image->global->restart_time);
|
|
return 1;
|
|
}
|
|
|
|
/* lua_ap_clock; r:clock() - Returns timestamp with microsecond precision*/
|
|
static int lua_ap_clock(lua_State *L) {
|
|
apr_time_t now;
|
|
now = apr_time_now();
|
|
lua_pushnumber(L, now);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* lua_ap_requestbody; r:requestbody([filename]) - Reads or stores the request body */
|
|
static int lua_ap_requestbody(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
const char *filename;
|
|
request_rec* r;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
filename = luaL_optstring(L, 2, 0);
|
|
|
|
if (r) {
|
|
|
|
/*~~~~~~~~~~~~~*/
|
|
apr_off_t size;
|
|
/*~~~~~~~~~~~~~*/
|
|
|
|
if
|
|
(
|
|
r->method_number != M_POST
|
|
&& r->method_number != M_PUT
|
|
) return (0);
|
|
if (!filename) {
|
|
|
|
/*~~~~~~~~~~~~~~*/
|
|
const char *data;
|
|
/*~~~~~~~~~~~~~~*/
|
|
|
|
if (util_read(r, &data, &size) != OK) {
|
|
return (0);
|
|
}
|
|
|
|
lua_pushlstring(L, data, (size_t) size);
|
|
lua_pushinteger(L, (lua_Integer) size);
|
|
return (2);
|
|
}
|
|
else {
|
|
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
apr_status_t rc;
|
|
apr_file_t *file;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
|
|
rc = apr_file_open(&file, filename, APR_CREATE | APR_FOPEN_WRITE,
|
|
APR_FPROT_OS_DEFAULT, r->pool);
|
|
lua_settop(L, 0);
|
|
if (rc == APR_SUCCESS) {
|
|
rc = util_write(r, file, &size);
|
|
apr_file_close(file);
|
|
if (rc == -1) {
|
|
return (0);
|
|
}
|
|
|
|
lua_pushinteger(L, (lua_Integer) size);
|
|
return (1);
|
|
}
|
|
else
|
|
lua_pushboolean(L, 0);
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* lua_ap_add_input_filter; r:add_input_filter(name) - Adds an input filter to the chain */
|
|
static int lua_ap_add_input_filter(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
request_rec *r;
|
|
const char* filterName;
|
|
ap_filter_rec_t *filter;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
filterName = lua_tostring(L, 2);
|
|
filter = ap_get_input_filter_handle(filterName);
|
|
if (filter) {
|
|
ap_add_input_filter_handle(filter, NULL, r, r->connection);
|
|
lua_pushboolean(L, 1);
|
|
}
|
|
else {
|
|
lua_pushboolean(L, 0);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* lua_ap_module_info; r:module_info(mod_name) - Returns information about a loaded module */
|
|
static int lua_ap_module_info(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
const char* moduleName;
|
|
module* mod;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
luaL_checktype(L, 1, LUA_TSTRING);
|
|
moduleName = lua_tostring(L, 1);
|
|
mod = ap_find_linked_module(moduleName);
|
|
if (mod) {
|
|
int i = 0;
|
|
const command_rec *cmd;
|
|
lua_newtable(L);
|
|
lua_pushstring(L, "commands");
|
|
lua_newtable(L);
|
|
for (cmd = mod->cmds; cmd->name; ++cmd) {
|
|
lua_pushstring(L, cmd->name);
|
|
lua_pushstring(L, cmd->errmsg);
|
|
lua_settable(L, -3);
|
|
}
|
|
lua_settable(L, -3);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* lua_ap_runtime_dir_relative: r:runtime_dir_relative(file): Returns the filename as relative to the runtime dir*/
|
|
static int lua_ap_runtime_dir_relative(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
request_rec *r;
|
|
const char* file;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
file = luaL_optstring(L, 2, ".");
|
|
lua_pushstring(L, ap_runtime_dir_relative(r->pool, file));
|
|
return 1;
|
|
}
|
|
|
|
/* lua_ap_set_document_root; r:set_document_root(path) - sets the current doc root for the request */
|
|
static int lua_ap_set_document_root(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
request_rec *r;
|
|
const char* root;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
root = lua_tostring(L, 2);
|
|
ap_set_document_root(r, root);
|
|
return 0;
|
|
}
|
|
|
|
/* lua_ap_stat; r:stat(filename) - Runs stat on a file and returns the file info as a table */
|
|
static int lua_ap_stat(lua_State *L)
|
|
{
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
request_rec *r;
|
|
const char* filename;
|
|
apr_finfo_t file_info;
|
|
/*~~~~~~~~~~~~~~~~~~*/
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
filename = lua_tostring(L, 2);
|
|
apr_stat(&file_info, filename, APR_FINFO_NORM, r->pool);
|
|
lua_newtable(L);
|
|
|
|
lua_pushstring(L, "mtime");
|
|
lua_pushinteger(L, file_info.mtime);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "atime");
|
|
lua_pushinteger(L, file_info.atime);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "ctime");
|
|
lua_pushinteger(L, file_info.ctime);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "size");
|
|
lua_pushinteger(L, file_info.size);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "filetype");
|
|
lua_pushinteger(L, file_info.filetype);
|
|
lua_settable(L, -3);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* lua_ap_loaded_modules; r:loaded_modules() - Returns a list of loaded modules */
|
|
static int lua_ap_loaded_modules(lua_State *L)
|
|
{
|
|
int i;
|
|
lua_newtable(L);
|
|
for (i = 0; ap_loaded_modules[i] && ap_loaded_modules[i]->name; i++) {
|
|
lua_pushinteger(L, i+1);
|
|
lua_pushstring(L, ap_loaded_modules[i]->name);
|
|
lua_settable(L, -3);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* lua_ap_server_info; r:server_info() - Returns server info, such as the executable filename, server root, mpm etc*/
|
|
static int lua_ap_server_info(lua_State *L)
|
|
{
|
|
lua_newtable(L);
|
|
|
|
lua_pushstring(L, "server_executable");
|
|
lua_pushstring(L, ap_server_argv0);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "server_root");
|
|
lua_pushstring(L, ap_server_root);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "scoreboard_fname");
|
|
lua_pushstring(L, ap_scoreboard_fname);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushstring(L, "server_mpm");
|
|
lua_pushstring(L, ap_show_mpm());
|
|
lua_settable(L, -3);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* === Auto-scraped functions === */
|
|
|
|
/**
|
|
* ap_add_version_component (apr_pool_t *pconf, const char *component)
|
|
* Add a component to the server description and banner strings
|
|
* @param pconf The pool to allocate the component from
|
|
* @param component The string to add
|
|
*/
|
|
static int lua_ap_add_version_component (lua_State *L) {
|
|
|
|
request_rec *r;
|
|
const char* component;
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
component = lua_tostring(L, 2);
|
|
ap_add_version_component(r->server->process->pconf, component);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* ap_set_context_info (request_rec *r, const char *prefix,
|
|
const char *document_root) Set context_prefix and context_document_root for a request.
|
|
* @param r The request
|
|
* @param prefix the URI prefix, without trailing slash
|
|
* @param document_root the corresponding directory on disk, without trailing
|
|
* slash
|
|
* @note If one of prefix of document_root is NULL, the corrsponding
|
|
* property will not be changed.
|
|
*/
|
|
static int lua_ap_set_context_info (lua_State *L) {
|
|
|
|
request_rec *r;
|
|
const char* prefix;
|
|
const char* document_root;
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
prefix = lua_tostring(L, 2);
|
|
luaL_checktype(L, 3, LUA_TSTRING);
|
|
document_root = lua_tostring(L, 3);
|
|
ap_set_context_info(r, prefix, document_root);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* ap_os_escape_path (apr_pool_t *p, const char *path, int partial)
|
|
* convert an OS path to a URL in an OS dependant way.
|
|
* @param p The pool to allocate from
|
|
* @param path The path to convert
|
|
* @param partial if set, assume that the path will be appended to something
|
|
* with a '/' in it (and thus does not prefix "./")
|
|
* @return The converted URL
|
|
*/
|
|
static int lua_ap_os_escape_path (lua_State *L) {
|
|
|
|
char * returnValue;
|
|
request_rec *r;
|
|
const char* path;
|
|
int partial = 0;
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
path = lua_tostring(L, 2);
|
|
if ( lua_isboolean( L, 3 ) ) partial = lua_toboolean( L, 3 );
|
|
returnValue = ap_os_escape_path(r->pool, path, partial);
|
|
lua_pushstring(L, returnValue);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**
|
|
* ap_escape_logitem (apr_pool_t *p, const char *str)
|
|
* Escape a string for logging
|
|
* @param p The pool to allocate from
|
|
* @param str The string to escape
|
|
* @return The escaped string
|
|
*/
|
|
static int lua_ap_escape_logitem (lua_State *L) {
|
|
|
|
char * returnValue;
|
|
request_rec *r;
|
|
const char* str;
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
str = lua_tostring(L, 2);
|
|
returnValue = ap_escape_logitem(r->pool, str);
|
|
lua_pushstring(L, returnValue);
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* ap_strcmp_match (const char *str, const char *expected)
|
|
* Determine if a string matches a patterm containing the wildcards '?' or '*'
|
|
* @param str The string to check
|
|
* @param expected The pattern to match against
|
|
* @return 1 if the two strings match, 0 otherwise
|
|
*/
|
|
static int lua_ap_strcmp_match (lua_State *L) {
|
|
|
|
int returnValue;
|
|
const char* str;
|
|
const char* expected;
|
|
int ignoreCase = 0;
|
|
luaL_checktype(L, 1, LUA_TSTRING);
|
|
str = lua_tostring(L, 1);
|
|
luaL_checktype(L, 2, LUA_TSTRING);
|
|
expected = lua_tostring(L, 2);
|
|
if ( lua_isboolean( L, 3 ) ) ignoreCase = lua_toboolean( L, 3 );
|
|
if (!ignoreCase) returnValue = ap_strcmp_match(str, expected);
|
|
else returnValue = ap_strcasecmp_match(str, expected);
|
|
lua_pushboolean(L, (!returnValue)); /* Somehow, this doesn't match the docs */
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**
|
|
* ap_set_keepalive (request_rec *r)
|
|
* Set the keepalive status for this request
|
|
* @param r The current request
|
|
* @return 1 if keepalive can be set, 0 otherwise
|
|
*/
|
|
static int lua_ap_set_keepalive (lua_State *L) {
|
|
|
|
int returnValue;
|
|
request_rec *r;
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
returnValue = ap_set_keepalive(r);
|
|
lua_pushboolean(L, returnValue);
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* ap_make_etag (request_rec *r, int force_weak)
|
|
* Construct an entity tag from the resource information. If it's a real
|
|
* file, build in some of the file characteristics.
|
|
* @param r The current request
|
|
* @param force_weak Force the entity tag to be weak - it could be modified
|
|
* again in as short an interval.
|
|
* @return The entity tag
|
|
*/
|
|
static int lua_ap_make_etag (lua_State *L) {
|
|
|
|
char * returnValue;
|
|
request_rec *r;
|
|
int force_weak;
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TBOOLEAN);
|
|
force_weak = luaL_optint(L, 2, 0);
|
|
returnValue = ap_make_etag(r, force_weak);
|
|
lua_pushstring(L, returnValue);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* ap_send_interim_response (request_rec *r, int send_headers)
|
|
* Send an interim (HTTP 1xx) response immediately.
|
|
* @param r The request
|
|
* @param send_headers Whether to send&clear headers in r->headers_out
|
|
*/
|
|
static int lua_ap_send_interim_response (lua_State *L) {
|
|
|
|
request_rec *r;
|
|
int send_headers;
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
if ( lua_isboolean( L, 2 ) ) send_headers = lua_toboolean( L, 2 );
|
|
ap_send_interim_response(r, send_headers);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* ap_custom_response (request_rec *r, int status, const char *string)
|
|
* Install a custom response handler for a given status
|
|
* @param r The current request
|
|
* @param status The status for which the custom response should be used
|
|
* @param string The custom response. This can be a static string, a file
|
|
* or a URL
|
|
*/
|
|
static int lua_ap_custom_response (lua_State *L) {
|
|
|
|
request_rec *r;
|
|
int status;
|
|
const char* string;
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
luaL_checktype(L, 2, LUA_TNUMBER);
|
|
status = lua_tointeger(L, 2);
|
|
luaL_checktype(L, 3, LUA_TSTRING);
|
|
string = lua_tostring(L, 3);
|
|
ap_custom_response(r, status, string);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* ap_exists_config_define (const char *name)
|
|
* Check for a definition from the server command line
|
|
* @param name The define to check for
|
|
* @return 1 if defined, 0 otherwise
|
|
*/
|
|
static int lua_ap_exists_config_define (lua_State *L) {
|
|
|
|
int returnValue;
|
|
const char* name;
|
|
luaL_checktype(L, 1, LUA_TSTRING);
|
|
name = lua_tostring(L, 1);
|
|
returnValue = ap_exists_config_define(name);
|
|
lua_pushinteger(L, returnValue);
|
|
return 1;
|
|
}
|
|
|
|
static int lua_ap_get_server_name_for_url (lua_State *L) {
|
|
|
|
const char* servername;
|
|
request_rec *r;
|
|
luaL_checktype(L, 1, LUA_TUSERDATA);
|
|
r = ap_lua_check_request_rec(L, 1);
|
|
servername = ap_get_server_name_for_url(r);
|
|
lua_pushstring(L, servername);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* ap_state_query (int query_code) item starts a new field */
|
|
static int lua_ap_state_query (lua_State *L) {
|
|
|
|
int returnValue;
|
|
int query_code;
|
|
luaL_checktype(L, 1, LUA_TNUMBER);
|
|
query_code = lua_tointeger(L, 1);
|
|
returnValue = ap_state_query(query_code);
|
|
lua_pushinteger(L, returnValue);
|
|
return 1;
|
|
}
|
|
|
|
static int lua_ap_sleep (lua_State *L) {
|
|
|
|
int msec;
|
|
luaL_checktype(L, 1, LUA_TNUMBER);
|
|
msec = (lua_tonumber(L, 1) * 1000000);
|
|
apr_sleep(msec);
|
|
return 0;
|
|
}
|
|
|
|
static const struct luaL_Reg httpd_functions [] = {
|
|
{"base64_encode", lua_apr_b64encode},
|
|
{"base64_decode", lua_apr_b64decode},
|
|
{"md5", lua_apr_md5},
|
|
{"sha1", lua_apr_sha1},
|
|
{"escape", lua_ap_escape},
|
|
{"unescape", lua_ap_unescape},
|
|
{"banner", lua_ap_banner},
|
|
{"port", lua_ap_port},
|
|
{"mpm_query", lua_ap_mpm_query},
|
|
{"expr", lua_ap_expr},
|
|
{"scoreboard_process", lua_ap_scoreboard_process},
|
|
{"scoreboard_worker", lua_ap_scoreboard_worker},
|
|
{"started", lua_ap_restarted},
|
|
{"clock", lua_ap_clock},
|
|
{"requestbody", lua_ap_requestbody},
|
|
{"add_input_filter", lua_ap_add_input_filter},
|
|
{"module_info", lua_ap_module_info},
|
|
{"loaded_modules", lua_ap_loaded_modules},
|
|
{"runtime_dir_relative", lua_ap_runtime_dir_relative},
|
|
{"server_info", lua_ap_server_info},
|
|
{"set_document_root", lua_ap_set_document_root},
|
|
{"add_version_component" , lua_ap_add_version_component},
|
|
{"set_context_info" , lua_ap_set_context_info},
|
|
{"os_escape_path" , lua_ap_os_escape_path},
|
|
{"escape_logitem" , lua_ap_escape_logitem},
|
|
{"strcmp_match" , lua_ap_strcmp_match},
|
|
{"set_keepalive" , lua_ap_set_keepalive},
|
|
{"make_etag" , lua_ap_make_etag},
|
|
{"send_interim_response" , lua_ap_send_interim_response},
|
|
{"custom_response" , lua_ap_custom_response},
|
|
{"exists_config_define" , lua_ap_exists_config_define},
|
|
{"state_query" , lua_ap_state_query},
|
|
{"stat" , lua_ap_stat},
|
|
{"regex" , lua_ap_regex},
|
|
{"sleep" , lua_ap_sleep},
|
|
{"get_server_name_for_url" , lua_ap_get_server_name_for_url},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
AP_LUA_DECLARE(int) ap_lua_load_httpd_functions(lua_State *L)
|
|
{
|
|
lua_getglobal(L, "apache2");
|
|
luaL_register(L, NULL, httpd_functions);
|
|
|
|
}
|