diff options
author | Steven Barth <steven@midlink.org> | 2008-05-28 15:28:13 +0000 |
---|---|---|
committer | Steven Barth <steven@midlink.org> | 2008-05-28 15:28:13 +0000 |
commit | 4365fbe2a373b73af5578d0ed6eddfb2ba9901ef (patch) | |
tree | cdc534c74a881b666012a92a645ff22c973a11a7 /libs/sgi-webuci/src | |
parent | 776f9957d0376670e9d3e43677dbe3ba19ded193 (diff) |
Squashed commit of the following:
commit d45d1757d24d8214f730af1a3401dd2bef4a434f
Author: Steven <steven@cyrus.homeunix.org>
Date: Wed May 28 17:23:27 2008 +0200
* libs/core: Removed dummymode checks in sys
* libs/sgi-webuci: Fixes
commit b870e8d345bc8912fd8ab61d463b9d68b924a6f4
Author: Felix Fietkau <nbd@openwrt.org>
Date: Wed May 28 15:40:10 2008 +0200
fix path to theme
commit e3732926bd98db4cc38de6eb8018cd4e55176699
Author: Felix Fietkau <nbd@openwrt.org>
Date: Wed May 28 14:56:03 2008 +0200
set the proper path to the config in dummy mode
commit a75aecf46f037c98bd6e49b9e48adb735d76d150
Author: Felix Fietkau <nbd@openwrt.org>
Date: Wed May 28 14:50:42 2008 +0200
add some dummy mode support
commit 12bb39ef606bca6b403cc982213a6597b76dc1b3
Author: Felix Fietkau <nbd@openwrt.org>
Date: Wed May 28 14:41:56 2008 +0200
normalize paths
commit 7aaad1103fd2bdc75aca158baa6ef191f9a961c6
Author: Felix Fietkau <nbd@openwrt.org>
Date: Wed May 28 14:27:26 2008 +0200
add missing require statement
commit 5766274bd2511b00c42b474aeeeb3efaca6ded9b
Author: Felix Fietkau <nbd@openwrt.org>
Date: Wed May 28 14:19:54 2008 +0200
add optional luaposix package (patched for darwin support)
commit 9e257a76d03722fc0ce8312aa9952641b21424bd
Author: Felix Fietkau <nbd@openwrt.org>
Date: Tue May 27 20:21:59 2008 +0200
add missing files, more integration for the boa plugin, fix path to lua modules
commit dacc1a98ec946975fcb19f87076dfa7db865fca6
Author: Felix Fietkau <nbd@openwrt.org>
Date: Tue May 27 19:42:37 2008 +0200
use "compile" instead of "source" and rename the old version of compile to "compile-all"
commit eb14777c4fee1eb5740aba1e5603e481320da7b1
Author: Felix Fietkau <nbd@openwrt.org>
Date: Tue May 27 19:41:59 2008 +0200
more boa integration
commit df0afb965bf0a987b653e9d0acadf3151179a596
Author: Felix Fietkau <nbd@openwrt.org>
Date: Tue May 27 18:33:42 2008 +0200
build boa and the webuci.so plugin along with sgi-webuci
commit 878161dabf32066631103d199e2cbaf3f5a7fb07
Author: Felix Fietkau <nbd@openwrt.org>
Date: Tue May 27 18:03:16 2008 +0200
add .gitignore
Diffstat (limited to 'libs/sgi-webuci/src')
-rw-r--r-- | libs/sgi-webuci/src/cgi.c | 530 | ||||
-rw-r--r-- | libs/sgi-webuci/src/luci.c | 216 |
2 files changed, 746 insertions, 0 deletions
diff --git a/libs/sgi-webuci/src/cgi.c b/libs/sgi-webuci/src/cgi.c new file mode 100644 index 000000000..f8bf4045e --- /dev/null +++ b/libs/sgi-webuci/src/cgi.c @@ -0,0 +1,530 @@ +/* + * CGI routines for luci + * 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. + */ + +/* + * Based on code from cgilib: + * + * cgi.c - Some simple routines for CGI programming + * Copyright (c) 1996-9,2007,8 Martin Schulze <joey@infodrom.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE 1 + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdbool.h> +#include <strings.h> +#include <ctype.h> +#include <lauxlib.h> + +#define BUFSIZE 128 + +static char * +cgiGetLine (FILE *stream) +{ + static char *line = NULL; + static size_t size = 0; + char buf[BUFSIZE]; + char *cp; + + if (!line) { + if ((line = (char *)malloc (BUFSIZE)) == NULL) + return NULL; + size = BUFSIZE; + } + line[0] = '\0'; + + while (!feof (stream)) { + if ((cp = fgets (buf, sizeof (buf), stream)) == NULL) + return NULL; + + if (strlen(line)+strlen(buf)+1 > size) { + if ((cp = (char *)realloc (line, size + BUFSIZE)) == NULL) + return line; + size += BUFSIZE; + line = cp; + } + + strcat (line, buf); + if (line[strlen(line)-1] == '\n') { + line[strlen(line)-1] = '\0'; + if (line[strlen(line)-1] == '\r') + line[strlen(line)-1] = '\0'; + return line; + } + } + + return NULL; +} + + +static const char * +luci_getenv(lua_State *L, const char *name) +{ + const char *ret; + + lua_getfield(L, lua_upvalueindex(2), name); + ret = lua_tostring(L, -1); + lua_pop(L, 1); + return ret; +} + +static void +luci_setvar(lua_State *L, const char *name, const char *value, bool append) +{ + /* Check if there is an existing value already */ + lua_getfield(L, lua_upvalueindex(1), name); + if (lua_isnil(L, -1)) { + /* nope, we're safe - add a new one */ + lua_pushstring(L, value); + lua_setfield(L, lua_upvalueindex(1), name); + } else if (lua_istable(L, -1) && append) { + /* it's a table already, but appending is requested + * take the last element and append the new string to it */ + int tlast = lua_objlen(L, -1); + lua_rawgeti(L, -1, tlast); + lua_pushstring(L, value); + lua_pushstring(L, "\n"); + lua_concat(L, 3); + lua_rawseti(L, -2, tlast); + } else if (lua_istable(L, -1)) { + /* it's a table, which means we already have two + * or more entries, add the next one */ + + int tnext = lua_objlen(L, -1) + 1; /* next entry */ + + lua_pushstring(L, value); + luaL_setn(L, -2, tnext); + lua_rawseti(L, -2, tnext); + } else if (lua_isstring(L, -1) && append) { + /* append the new string to the existing variable */ + lua_pushstring(L, value); + lua_pushstring(L, "\n"); + lua_concat(L, 3); + lua_setfield(L, lua_upvalueindex(1), name); + } else if (lua_isstring(L, -1)) { + /* we're trying to add a variable that already has + * a string value. convert the string value to a + * table and add our new value to the table as well + */ + lua_createtable(L, 2, 0); + lua_pushvalue(L, -2); /* copy of the initial string value */ + lua_rawseti(L, -2, 1); + + lua_pushstring(L, value); + lua_rawseti(L, -2, 2); + lua_setfield(L, lua_upvalueindex(1), name); + } else { + luaL_error(L, "Invalid table entry type for index '%s'", name); + } +} + +char *cgiDecodeString (char *text) +{ + char *cp, *xp; + + for (cp=text,xp=text; *cp; cp++) { + if (*cp == '%') { + if (strchr("0123456789ABCDEFabcdef", *(cp+1)) + && strchr("0123456789ABCDEFabcdef", *(cp+2))) { + if (islower(*(cp+1))) + *(cp+1) = toupper(*(cp+1)); + if (islower(*(cp+2))) + *(cp+2) = toupper(*(cp+2)); + *(xp) = (*(cp+1) >= 'A' ? *(cp+1) - 'A' + 10 : *(cp+1) - '0' ) * 16 + + (*(cp+2) >= 'A' ? *(cp+2) - 'A' + 10 : *(cp+2) - '0'); + xp++;cp+=2; + } + } else { + *(xp++) = *cp; + } + } + memset(xp, 0, cp-xp); + return text; +} + +#if 0 +/* cgiReadFile() + * + * Read and save a file fro a multipart request + */ +#include <errno.h> +char *cgiReadFile (FILE *stream, char *boundary) +{ + char *crlfboundary, *buf; + size_t boundarylen; + int c; + unsigned int pivot; + char *cp; + char template[]= "/tmp/cgilibXXXXXX"; + FILE *tmpfile; + int fd; + + boundarylen = strlen(boundary)+3; + if ((crlfboundary = (char *)malloc (boundarylen)) == NULL) + return NULL; + sprintf (crlfboundary, "\r\n%s", boundary); + + if ((buf = (char *)malloc (boundarylen)) == NULL) { + free (crlfboundary); + return NULL; + } + memset (buf, 0, boundarylen); + pivot = 0; + + if ((fd = mkstemp (template)) == -1) { + free (crlfboundary); + free (buf); + return NULL; + } + + if ((tmpfile = fdopen (fd, "w")) == NULL) { + free (crlfboundary); + free (buf); + unlink (template); + return NULL; + } + + while (!feof (stream)) { + c = fgetc (stream); + + if (c == 0) { + if (strlen (buf)) { + for (cp=buf; *cp; cp++) + putc (*cp, tmpfile); + memset (buf, 0, boundarylen); + pivot = 0; + } + putc (c, tmpfile); + continue; + } + + if (strlen (buf)) { + if (crlfboundary[pivot+1] == c) { + buf[++pivot] = c; + + if (strlen (buf) == strlen (crlfboundary)) + break; + else + continue; + } else { + for (cp=buf; *cp; cp++) + putc (*cp, tmpfile); + memset (buf, 0, boundarylen); + pivot = 0; + } + } + + if (crlfboundary[0] == c) { + buf[0] = c; + } else { + fputc (c, tmpfile); + } + } + + if (!feof (stream)) + fgets (buf, boundarylen, stream); + + fclose (tmpfile); + + free (crlfboundary); + free (buf); + + return strdup (template); +} +#endif + +/* + * Decode multipart/form-data + */ +#define MULTIPART_DELTA 5 +void luci_parse_multipart (lua_State *L, char *boundary) +{ + char *line; + char *cp, *xp; + char *name = NULL, *type = NULL; + char *fname = NULL; + int header = 1; + bool append = false; + + while ((line = cgiGetLine (stdin)) != NULL) { + if (!strncmp (line, boundary, strlen(boundary))) { + header = 1; + if (name) + free(name); + if (type) + free(type); + name = NULL; + type = NULL; + append = false; + } else if (header && !name && !strncasecmp (line, "Content-Disposition: form-data; ", 32)) { + if ((cp = strstr (line, "name=\"")) == NULL) + continue; + cp += 6; + if ((xp = strchr (cp, '\"')) == NULL) + continue; + name = malloc(xp-cp + 1); + strncpy(name, cp, xp-cp); + name[xp-cp] = 0; + cgiDecodeString (name); + + if ((cp = strstr (line, "filename=\"")) == NULL) + continue; + cp += 10; + if ((xp = strchr (cp, '\"')) == NULL) + continue; + fname = malloc(xp-cp + 1); + strncpy(fname, cp, xp-cp); + fname[xp-cp] = 0; + cgiDecodeString (fname); + } else if (header && !type && !strncasecmp (line, "Content-Type: ", 14)) { + cp = line + 14; + type = strdup (cp); + } else if (header) { + if (!strlen(line)) { + header = 0; + + if (fname) { +#if 0 + header = 1; + tmpfile = cgiReadFile (stdin, boundary); + + if (!tmpfile) { + free (name); + free (fname); + if (type) + free (type); + name = fname = type = NULL; + } + + cgiDebugOutput (2, "Wrote %s (%s) to file: %s", name, fname, tmpfile); + + if (!strlen (fname)) { + cgiDebugOutput (3, "Found empty filename, removing"); + unlink (tmpfile); + free (tmpfile); + free (name); + free (fname); + if (type) + free (type); + name = fname = type = NULL; + } else { + if ((file = (s_file *)malloc (sizeof (s_file))) == NULL) { + cgiDebugOutput (3, "malloc failed, ignoring %s=%s", name, fname); + unlink (tmpfile); + free (tmpfile); + free (name); + free (fname); + if (type) + free (type); + name = fname = type = NULL; + continue; + } + + file->name = name; + file->type = type; + file->tmpfile = tmpfile; + if ((cp = rindex (fname, '/')) == NULL) + file->filename = fname; + else { + file->filename = strdup (++cp); + free (fname); + } + name = type = fname = NULL; + + if (!files) { + if ((files = (s_file **)malloc(2*sizeof (s_file *))) == NULL) { + cgiDebugOutput (3, "malloc failed, ignoring %s=%s", name, fname); + unlink (tmpfile); + free (tmpfile); + free (name); + name = NULL; + if (type) { + free (type); + type = NULL; + } + free (file->filename); + free (file); + continue; + } + memset (files, 0, 2*sizeof (s_file *)); + index = 0; + } else { + for (index=0; files[index]; index++); + if ((tmpf = (s_file **)realloc(files, (index+2)*sizeof (s_file *))) == NULL) { + cgiDebugOutput (3, "realloc failed, ignoring %s=%s", name, fname); + unlink (tmpfile); + free (tmpfile); + free (name); + if (type) + free (type); + free (file->filename); + free (file); + name = type = fname = NULL; + continue; + } + files = tmpf; + memset (files + index, 0, 2*sizeof (s_file *)); + } + files[index] = file; + } +#else + free(fname); + fname = NULL; +#endif + } + } + } else { + if (!name) + return; + + cgiDecodeString(line); + luci_setvar(L, name, line, append); + if (!append) /* beginning of variable contents */ + append = true; + } + } +} + +/* parse the request header and store variables + * in the array supplied as function argument 1 on the stack + */ +int luci_parse_header (lua_State *L) +{ + int length; + char *line = NULL; + int numargs; + char *cp = NULL, *ip = NULL, *esp = NULL; + const char *ct, *il; + int i; + + if (!lua_istable(L, lua_upvalueindex(1))) + luaL_error(L, "Invalid argument"); + + if (!lua_istable(L, lua_upvalueindex(2))) + luaL_error(L, "Invalid argument"); + + ct = luci_getenv(L, "content_type"); + if (ct) { + ct = cp = strdup(ct); + } + if (cp && strstr(cp, "multipart/form-data") && strstr(cp, "boundary=")) { + cp = strstr(cp, "boundary=") + strlen ("boundary=") - 2; + *cp = *(cp+1) = '-'; + luci_parse_multipart(L, cp); + free((char *) ct); + return 0; + } + free((char *) ct); + + ct = luci_getenv(L, "request_method"); + il = luci_getenv(L, "content_length"); + + if (!ct) { + fprintf(stderr, "no request method!\n"); + return 0; + } + + if (!strcmp(ct, "POST")) { + if (il) { + length = atoi(il); + if (length <= 0) + return 0; + line = (char *)malloc (length+2); + if (line) + fgets(line, length+1, stdin); + } + } else if (!strcmp(ct, "GET")) { + ct = luci_getenv(L, "query_string"); + if (ct) + esp = strdup(ct); + if (esp && strlen(esp)) { + line = (char *)malloc (strlen(esp)+2); + if (line) + strcpy (line, esp); + } + free(esp); + } + + if (!line) + return 0; + + /* + * From now on all cgi variables are stored in the variable line + * and look like foo=bar&foobar=barfoo&foofoo= + */ + for (cp=line; *cp; cp++) + if (*cp == '+') + *cp = ' '; + + if (strlen(line)) { + for (numargs=1,cp=line; *cp; cp++) + if (*cp == '&' || *cp == ';' ) numargs++; + } else + numargs = 0; + + cp = line; + i=0; + while (*cp) { + char *name; + char *value; + + if ((ip = (char *)strchr(cp, '&')) != NULL) { + *ip = '\0'; + } else if ((ip = (char *)strchr(cp, ';')) != NULL) { + *ip = '\0'; + } else + ip = cp + strlen(cp); + + if ((esp=(char *)strchr(cp, '=')) == NULL) + goto skip; + + if (!strlen(esp)) + goto skip; + + if (i >= numargs) + goto skip; + + esp[0] = 0; + name = cp; + cgiDecodeString (name); + + cp = ++esp; + value = cp; + cgiDecodeString (value); + + luci_setvar(L, name, value, false); +skip: + cp = ++ip; + } + free(line); + return 0; +} + diff --git a/libs/sgi-webuci/src/luci.c b/libs/sgi-webuci/src/luci.c new file mode 100644 index 000000000..d65fc20b6 --- /dev/null +++ b/libs/sgi-webuci/src/luci.c @@ -0,0 +1,216 @@ +/* + * 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 int luci_init(struct httpd_plugin *p) +{ + char *path = NULL; + int ret = 0; + + L = luaL_newstate(); + if (!L) + goto error; + + luaL_openlibs(L); + + path = malloc(strlen(p->dir) + sizeof(LUAMAIN) + 2); + strcpy(path, p->dir); + strcat(path, "/" LUAMAIN); + + ret = luaL_dofile(L, path); + + lua_getfield(L, LUA_GLOBALSINDEX, "luci-plugin"); + do { + if (!lua_istable(L, -1)) { + ret = 1; + break; + } + + lua_getfield(L, -1, "init"); + if (!lua_isfunction(L, -1)) + break; + + lua_pushstring(L, p->dir); + ret = lua_pcall(L, 1, 0, 0); + } while (0); + free(path); + + if (ret != 0) + goto error; + + return 1; + +error: + fprintf(stderr, "Error: "); + if (L) { + const char *s = lua_tostring(L, -1); + if (!s) + s = "unknown error"; + fprintf(stderr, "%s\n", s); + lua_close(L); + } else { + fprintf(stderr, "Out of memory!\n"); + } + return 0; +} + +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; + + 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(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, +}; |