2 * CGI routines for luci
3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 * Based on code from cgilib:
18 * cgi.c - Some simple routines for CGI programming
19 * Copyright (c) 1996-9,2007,8 Martin Schulze <joey@infodrom.org>
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software Foundation
33 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
50 cgiGetLine (FILE *stream
)
52 static char *line
= NULL
;
53 static size_t size
= 0;
58 if ((line
= (char *)malloc (BUFSIZE
)) == NULL
)
64 while (!feof (stream
)) {
65 if ((cp
= fgets (buf
, sizeof (buf
), stream
)) == NULL
)
68 if (strlen(line
)+strlen(buf
)+1 > size
) {
69 if ((cp
= (char *)realloc (line
, size
+ BUFSIZE
)) == NULL
)
76 if (line
[strlen(line
)-1] == '\n') {
77 line
[strlen(line
)-1] = '\0';
78 if (line
[strlen(line
)-1] == '\r')
79 line
[strlen(line
)-1] = '\0';
89 luci_getenv(lua_State
*L
, const char *name
)
93 lua_getfield(L
, lua_upvalueindex(2), name
);
94 ret
= lua_tostring(L
, -1);
100 luci_setvar(lua_State
*L
, const char *name
, const char *value
, bool append
)
102 /* Check if there is an existing value already */
103 lua_getfield(L
, lua_upvalueindex(1), name
);
104 if (lua_isnil(L
, -1)) {
105 /* nope, we're safe - add a new one */
106 lua_pushstring(L
, value
);
107 lua_setfield(L
, lua_upvalueindex(1), name
);
108 } else if (lua_istable(L
, -1) && append
) {
109 /* it's a table already, but appending is requested
110 * take the last element and append the new string to it */
111 int tlast
= lua_objlen(L
, -1);
112 lua_rawgeti(L
, -1, tlast
);
113 lua_pushstring(L
, value
);
114 lua_pushstring(L
, "\n");
116 lua_rawseti(L
, -2, tlast
);
117 } else if (lua_istable(L
, -1)) {
118 /* it's a table, which means we already have two
119 * or more entries, add the next one */
121 int tnext
= lua_objlen(L
, -1) + 1; /* next entry */
123 lua_pushstring(L
, value
);
124 luaL_setn(L
, -2, tnext
);
125 lua_rawseti(L
, -2, tnext
);
126 } else if (lua_isstring(L
, -1) && append
) {
127 /* append the new string to the existing variable */
128 lua_pushstring(L
, value
);
129 lua_pushstring(L
, "\n");
131 lua_setfield(L
, lua_upvalueindex(1), name
);
132 } else if (lua_isstring(L
, -1)) {
133 /* we're trying to add a variable that already has
134 * a string value. convert the string value to a
135 * table and add our new value to the table as well
137 lua_createtable(L
, 2, 0);
138 lua_pushvalue(L
, -2); /* copy of the initial string value */
139 lua_rawseti(L
, -2, 1);
141 lua_pushstring(L
, value
);
142 lua_rawseti(L
, -2, 2);
143 lua_setfield(L
, lua_upvalueindex(1), name
);
145 luaL_error(L
, "Invalid table entry type for index '%s'", name
);
149 char *cgiDecodeString (char *text
)
153 for (cp
=text
,xp
=text
; *cp
; cp
++) {
155 if (strchr("0123456789ABCDEFabcdef", *(cp
+1))
156 && strchr("0123456789ABCDEFabcdef", *(cp
+2))) {
157 if (islower(*(cp
+1)))
158 *(cp
+1) = toupper(*(cp
+1));
159 if (islower(*(cp
+2)))
160 *(cp
+2) = toupper(*(cp
+2));
161 *(xp
) = (*(cp
+1) >= 'A' ? *(cp
+1) - 'A' + 10 : *(cp
+1) - '0' ) * 16
162 + (*(cp
+2) >= 'A' ? *(cp
+2) - 'A' + 10 : *(cp
+2) - '0');
169 memset(xp
, 0, cp
-xp
);
176 * Read and save a file fro a multipart request
179 char *cgiReadFile (FILE *stream
, char *boundary
)
181 char *crlfboundary
, *buf
;
186 char template[]= "/tmp/cgilibXXXXXX";
190 boundarylen
= strlen(boundary
)+3;
191 if ((crlfboundary
= (char *)malloc (boundarylen
)) == NULL
)
193 sprintf (crlfboundary
, "\r\n%s", boundary
);
195 if ((buf
= (char *)malloc (boundarylen
)) == NULL
) {
199 memset (buf
, 0, boundarylen
);
202 if ((fd
= mkstemp (template)) == -1) {
208 if ((tmpfile
= fdopen (fd
, "w")) == NULL
) {
215 while (!feof (stream
)) {
220 for (cp
=buf
; *cp
; cp
++)
222 memset (buf
, 0, boundarylen
);
230 if (crlfboundary
[pivot
+1] == c
) {
233 if (strlen (buf
) == strlen (crlfboundary
))
238 for (cp
=buf
; *cp
; cp
++)
240 memset (buf
, 0, boundarylen
);
245 if (crlfboundary
[0] == c
) {
253 fgets (buf
, boundarylen
, stream
);
260 return strdup (template);
265 * Decode multipart/form-data
267 #define MULTIPART_DELTA 5
268 void luci_parse_multipart (lua_State
*L
, char *boundary
)
272 char *name
= NULL
, *type
= NULL
;
277 while ((line
= cgiGetLine (stdin
)) != NULL
) {
278 if (!strncmp (line
, boundary
, strlen(boundary
))) {
287 } else if (header
&& !name
&& !strncasecmp (line
, "Content-Disposition: form-data; ", 32)) {
288 if ((cp
= strstr (line
, "name=\"")) == NULL
)
291 if ((xp
= strchr (cp
, '\"')) == NULL
)
293 name
= malloc(xp
-cp
+ 1);
294 strncpy(name
, cp
, xp
-cp
);
296 cgiDecodeString (name
);
298 if ((cp
= strstr (line
, "filename=\"")) == NULL
)
301 if ((xp
= strchr (cp
, '\"')) == NULL
)
303 fname
= malloc(xp
-cp
+ 1);
304 strncpy(fname
, cp
, xp
-cp
);
306 cgiDecodeString (fname
);
307 } else if (header
&& !type
&& !strncasecmp (line
, "Content-Type: ", 14)) {
317 tmpfile
= cgiReadFile (stdin
, boundary
);
324 name
= fname
= type
= NULL
;
327 cgiDebugOutput (2, "Wrote %s (%s) to file: %s", name
, fname
, tmpfile
);
329 if (!strlen (fname
)) {
330 cgiDebugOutput (3, "Found empty filename, removing");
337 name
= fname
= type
= NULL
;
339 if ((file
= (s_file
*)malloc (sizeof (s_file
))) == NULL
) {
340 cgiDebugOutput (3, "malloc failed, ignoring %s=%s", name
, fname
);
347 name
= fname
= type
= NULL
;
353 file
->tmpfile
= tmpfile
;
354 if ((cp
= rindex (fname
, '/')) == NULL
)
355 file
->filename
= fname
;
357 file
->filename
= strdup (++cp
);
360 name
= type
= fname
= NULL
;
363 if ((files
= (s_file
**)malloc(2*sizeof (s_file
*))) == NULL
) {
364 cgiDebugOutput (3, "malloc failed, ignoring %s=%s", name
, fname
);
373 free (file
->filename
);
377 memset (files
, 0, 2*sizeof (s_file
*));
380 for (index
=0; files
[index
]; index
++);
381 if ((tmpf
= (s_file
**)realloc(files
, (index
+2)*sizeof (s_file
*))) == NULL
) {
382 cgiDebugOutput (3, "realloc failed, ignoring %s=%s", name
, fname
);
388 free (file
->filename
);
390 name
= type
= fname
= NULL
;
394 memset (files
+ index
, 0, 2*sizeof (s_file
*));
408 cgiDecodeString(line
);
409 luci_setvar(L
, name
, line
, append
);
410 if (!append
) /* beginning of variable contents */
416 /* parse the request header and store variables
417 * in the array supplied as function argument 1 on the stack
419 int luci_parse_header (lua_State
*L
)
424 char *cp
= NULL
, *ip
= NULL
, *esp
= NULL
;
428 if (!lua_istable(L
, lua_upvalueindex(1)))
429 luaL_error(L
, "Invalid argument");
431 if (!lua_istable(L
, lua_upvalueindex(2)))
432 luaL_error(L
, "Invalid argument");
434 ct
= luci_getenv(L
, "content_type");
436 ct
= cp
= strdup(ct
);
438 if (cp
&& strstr(cp
, "multipart/form-data") && strstr(cp
, "boundary=")) {
439 cp
= strstr(cp
, "boundary=") + strlen ("boundary=") - 2;
441 luci_parse_multipart(L
, cp
);
447 ct
= luci_getenv(L
, "request_method");
448 il
= luci_getenv(L
, "content_length");
451 fprintf(stderr
, "no request method!\n");
455 if (!strcmp(ct
, "POST")) {
460 line
= (char *)malloc (length
+2);
462 fgets(line
, length
+1, stdin
);
464 } else if (!strcmp(ct
, "GET")) {
465 ct
= luci_getenv(L
, "query_string");
468 if (esp
&& strlen(esp
)) {
469 line
= (char *)malloc (strlen(esp
)+2);
480 * From now on all cgi variables are stored in the variable line
481 * and look like foo=bar&foobar=barfoo&foofoo=
483 for (cp
=line
; *cp
; cp
++)
488 for (numargs
=1,cp
=line
; *cp
; cp
++)
489 if (*cp
== '&' || *cp
== ';' ) numargs
++;
499 if ((ip
= (char *)strchr(cp
, '&')) != NULL
) {
501 } else if ((ip
= (char *)strchr(cp
, ';')) != NULL
) {
504 ip
= cp
+ strlen(cp
);
506 if ((esp
=(char *)strchr(cp
, '=')) == NULL
)
517 cgiDecodeString (name
);
521 cgiDecodeString (value
);
523 luci_setvar(L
, name
, value
, false);