flm01/openwrt/package/luci/libs/sgi-webuci/src/luci.c

237 lines
4.6 KiB
C

/*
* luci
* Copyright (C) 2008 John Crispin <blogic@openwrt.org>
* Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <string.h>
#include <stdio.h>
#include <boa-plugin.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdbool.h>
#include <stdlib.h>
#define LUAMAIN "luci.lua"
static lua_State *L = NULL;
extern int luci_parse_header (lua_State *L);
static lua_State *luci_context_init(struct httpd_plugin *p)
{
char *path = NULL;
lua_State *Lnew;
int ret = 0;
Lnew = luaL_newstate();
if (!Lnew)
goto error;
luaL_openlibs(Lnew);
path = malloc(strlen(p->dir) + sizeof(LUAMAIN) + 2);
strcpy(path, p->dir);
strcat(path, "/" LUAMAIN);
ret = luaL_dofile(Lnew, path);
lua_getfield(Lnew, LUA_GLOBALSINDEX, "luci-plugin");
do {
if (!lua_istable(Lnew, -1)) {
ret = 1;
break;
}
lua_getfield(Lnew, -1, "init");
if (!lua_isfunction(Lnew, -1))
break;
lua_pushstring(Lnew, p->dir);
ret = lua_pcall(Lnew, 1, 0, 0);
} while (0);
free(path);
if (ret != 0)
goto error;
return Lnew;
error:
fprintf(stderr, "Error: ");
if (Lnew) {
const char *s = lua_tostring(Lnew, -1);
if (!s)
s = "unknown error";
fprintf(stderr, "%s\n", s);
lua_close(Lnew);
} else {
fprintf(stderr, "Out of memory!\n");
}
return NULL;
}
static int luci_init(struct httpd_plugin *p)
{
L = luci_context_init(p);
return (L != NULL);
}
static void pushvar(char *name, char *val)
{
if (!val)
return;
lua_pushstring(L, val);
lua_setfield(L, -2, name);
}
static int luci_pcall(lua_State *L, char *func, int narg)
{
int ret;
ret = lua_pcall(L, narg, narg, 0);
if (ret) {
const char *s = lua_tostring(L, -1);
if (s)
fprintf(stderr, "Error running %s: %s\n", func, s);
return ret;
}
if (!narg)
return ret;
ret = lua_isnumber(L, -1);
if (!ret)
goto done;
ret = lua_tonumber(L, -1);
done:
lua_pop(L, 1);
return ret;
}
static int luci_prepare_req(struct httpd_plugin *p, struct http_context *ctx)
{
int ret;
bool reload = false;
lua_getglobal(L, "luci-plugin");
lua_getfield(L, -1, "reload");
if (lua_isboolean(L, -1))
reload = lua_toboolean(L, -1);
lua_pop(L, 1);
if (reload) {
lua_close(L);
L = luci_context_init(p);
lua_getglobal(L, "luci-plugin");
}
lua_getfield(L, -1, "prepare_req");
ret = lua_isfunction(L, -1);
if (!ret)
goto done;
lua_pushstring(L, ctx->uri);
ret = luci_pcall(L, "prepare_req", 1);
done:
lua_pop(L, 1);
return ret;
}
static int luci_handle_req(struct httpd_plugin *p, struct http_context *ctx)
{
int ret;
lua_newtable(L); /* new table for the http context */
/* convert http_context data structure to lua table */
#define PUSH(x) pushvar(#x, ctx->x)
PUSH(cookie);
PUSH(request_method);
PUSH(server_addr);
PUSH(server_proto);
PUSH(query_string);
PUSH(remote_addr);
lua_pushinteger(L, ctx->remote_port);
lua_setfield(L, -2, "remote_port");
PUSH(content_type);
PUSH(content_length);
PUSH(http_accept);
#undef PUSH
if (!strncmp(ctx->uri, p->prefix, strlen(p->prefix)))
pushvar("uri", ctx->uri + strlen(p->prefix));
else
pushvar("uri", ctx->uri);
/* make sure the global 'luci' table is prepared */
lua_getglobal(L, "luci-plugin");
if (!lua_istable(L, -1))
return 0;
lua_getfield(L, -1, "init_req");
if (!lua_isfunction(L, -1)) {
/* ignore error */
lua_pop(L, 1);
} else {
lua_pushvalue(L, -3);
luci_pcall(L, "init_req", 1);
}
/* storage space for cgi variables */
lua_newtable(L);
lua_pushvalue(L, -1); /* copy for setfield */
lua_setfield(L, -3, "vars");
lua_pushvalue(L, -3); /* the http context table */
/*
* make luci_parse_header a closure
* argument 1: the luci.vars table
* argument 2: the http context table
*/
lua_pushcclosure(L, luci_parse_header, 2);
ret = luci_pcall(L, "parse_header", 0);
lua_getfield(L, -1, "handle_req");
ret = lua_isfunction(L, -1);
if (!ret)
goto done;
lua_pushvalue(L, -3);
ret = luci_pcall(L, "handle_req", 1);
/* pop the luci and http context tables */
done:
lua_pop(L, 2);
return ret;
}
static void luci_unload(struct httpd_plugin *p)
{
lua_close(L);
}
HTTPD_PLUGIN {
.prefix = "/luci/",
.init = luci_init,
.done = luci_unload,
.prepare_req = luci_prepare_req,
.handle_req = luci_handle_req,
};