2 cgi.c - Some simple routines for CGI programming
3 Copyright (c) 1996-9,2007 Martin Schulze <joey@infodrom.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 as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
28 char *cgiHeaderString = NULL;
31 extern s_cookie **cgiReadCookies();
33 int cgiSetHeader (char *name, char *value)
35 char *cp, *vp, *pivot;
38 if (!name || !strlen (name) || !value || !strlen (value))
41 for (cp=name;*cp && *cp!=' ' && *cp!='\r' && *cp!='\n' && *cp!=':';cp++);
42 for (vp=value;*vp && *vp!='\r' && *vp!='\n';vp++);
44 if (cgiHeaderString) {
45 len = (strlen (cgiHeaderString) + cp-name + vp-value + 5) * sizeof (char);
46 if ((pivot = (char *)realloc (cgiHeaderString,len)) == NULL)
48 cgiHeaderString = pivot;
49 pivot += strlen (cgiHeaderString);
51 len = (cp-name + vp-value + 5) * sizeof (char);
52 if ((cgiHeaderString = (char *)malloc (len)) == NULL)
54 pivot = cgiHeaderString;
56 strncpy (pivot, name, cp-name);
57 strncat (pivot, ": ", 2);
58 strncat (pivot, value, vp-value);
59 strncat (pivot, "\r\n", 2);
64 int cgiSetType (char *type)
69 if (!type || !strlen (type))
74 for (cp=type;*cp && *cp!='\r' && *cp!='\n';cp++);
76 len = (cp-type+1) * sizeof (char);
77 if ((cgiType = (char *)malloc (len+20)) == NULL)
79 memset (cgiType, 0, len);
80 strncpy (cgiType, type, cp-type);
88 printf ("Content-type: %s\r\n", cgiType);
90 printf ("Content-type: text/html\r\n");
92 printf ("%s", cgiHeaderString);
96 void cgiDebug (int level, int where)
99 cgiDebugLevel = level;
104 cgiDebugType = where;
110 char *cgiDecodeString (char *text)
114 for (cp=text,xp=text; *cp; cp++) {
116 if (strchr("0123456789ABCDEFabcdef", *(cp+1))
117 && strchr("0123456789ABCDEFabcdef", *(cp+2))) {
118 if (islower(*(cp+1)))
119 *(cp+1) = toupper(*(cp+1));
120 if (islower(*(cp+2)))
121 *(cp+2) = toupper(*(cp+2));
122 *(xp) = (*(cp+1) >= 'A' ? *(cp+1) - 'A' + 10 : *(cp+1) - '0' ) * 16
123 + (*(cp+2) >= 'A' ? *(cp+2) - 'A' + 10 : *(cp+2) - '0');
130 memset(xp, 0, cp-xp);
134 /* cgiReadVariables()
136 * Read from stdin if no string is provided via CGI. Variables that
137 * doesn't have a value associated with it doesn't get stored.
139 s_var **cgiReadVariables ()
144 char *cp, *ip, *esp, *sptr;
149 cp = getenv("REQUEST_METHOD");
150 ip = getenv("CONTENT_LENGTH");
152 if (cp && !strcmp(cp, "POST")) {
155 if ((line = (char *)malloc (length+2)) == NULL)
157 fgets(line, length+1, stdin);
160 } else if (cp && !strcmp(cp, "GET")) {
161 esp = getenv("QUERY_STRING");
162 if (esp && strlen(esp)) {
163 if ((line = (char *)malloc (strlen(esp)+2)) == NULL)
165 sprintf (line, "%s", esp);
170 printf ("(offline mode: enter name=value pairs on standard input)\n");
171 memset (tmp, 0, sizeof(tmp));
172 while((cp = fgets (tmp, 100, stdin)) != NULL) {
174 if (tmp[strlen(tmp)-1] == '\n')
175 tmp[strlen(tmp)-1] = '&';
177 length += strlen(tmp);
178 len = (length+1) * sizeof(char);
179 if ((line = (char *)realloc (line, len)) == NULL)
183 length = strlen(tmp);
184 len = (length+1) * sizeof(char);
185 if ((line = (char *)malloc (len)) == NULL)
187 memset (line, 0, len);
191 memset (tmp, 0, sizeof(tmp));
195 if (line[strlen(line)-1] == '&')
196 line[strlen(line)-1] = '\0';
200 * From now on all cgi variables are stored in the variable line
201 * and look like foo=bar&foobar=barfoo&foofoo=
204 cgiDebugOutput (1, "Received cgi input: %s\n", line);
206 for (cp=line; *cp; cp++)
211 for (numargs=1,cp=line; *cp; cp++)
212 if (*cp == '&' || *cp == ';' ) numargs++;
215 cgiDebugOutput (1, "%d cgi variables found.\n", numargs);
217 len = (numargs+1) * sizeof(s_var *);
218 if ((result = (s_var **)malloc (len)) == NULL)
220 memset (result, 0, len);
225 if ((ip = (char *)strchr(cp, '&')) != NULL) {
227 } else if ((ip = (char *)strchr(cp, ';')) != NULL) {
230 ip = cp + strlen(cp);
232 if ((esp=(char *)strchr(cp, '=')) == NULL) {
244 /* try to find out if there's already such a variable */
245 for (k=0; k<i && (strncmp (result[k]->name,cp, esp-cp) || !(strlen (result[k]->name) == esp-cp)); k++);
247 if (k == i) { /* No such variable yet */
248 if ((result[i] = (s_var *)malloc(sizeof(s_var))) == NULL)
250 if ((result[i]->name = (char *)malloc((esp-cp+1) * sizeof(char))) == NULL)
252 memset (result[i]->name, 0, esp-cp+1);
253 strncpy(result[i]->name, cp, esp-cp);
255 if ((result[i]->value = (char *)malloc((ip-esp+1) * sizeof(char))) == NULL)
257 memset (result[i]->value, 0, ip-esp+1);
258 strncpy(result[i]->value, cp, ip-esp);
259 result[i]->value = cgiDecodeString(result[i]->value);
260 cgiDebugOutput (1, "%s: %s\n", result[i]->name, result[i]->value);
262 } else { /* There is already such a name, suppose a mutiple field */
264 len = (strlen(result[k]->value)+(ip-esp)+2) * sizeof (char);
265 if ((sptr = (char *)malloc(len)) == NULL)
267 memset (sptr, 0, len);
268 sprintf (sptr, "%s\n", result[k]->value);
269 strncat(sptr, cp, ip-esp);
270 free(result[k]->value);
271 result[k]->value = cgiDecodeString (sptr);
281 * Read from stdin if no string is provided via CGI. Variables that
282 * doesn't have a value associated with it doesn't get stored.
290 vars = cgiReadVariables ();
291 cookies = cgiReadCookies ();
293 if (!vars && !cookies)
296 if ((res = (s_cgi *)malloc (sizeof (s_cgi))) == NULL)
299 res->cookies = cookies;
304 char *cgiGetValue (s_cgi *parms, const char *name)
308 if (!parms || !parms->vars)
310 for (i=0;parms->vars[i]; i++)
311 if (!strcmp(name,parms->vars[i]->name)) {
312 cgiDebugOutput (1, "%s found as %s\n", name, parms->vars[i]->value);
313 if (strlen(parms->vars[i]->value) > 0)
314 return parms->vars[i]->value;
318 cgiDebugOutput (1, "%s not found\n", name);
322 char **cgiGetVariables (s_cgi *parms)
328 if (!parms || !parms->vars)
330 for (i=0;parms->vars[i]; i++);
331 len = sizeof (char *) * ++i;
332 if ((res = (char **)malloc (len)) == NULL)
334 memset (res, 0, len);
335 for (i=0;parms->vars[i]; i++) {
336 len = strlen (parms->vars[i]->name) +1;
337 if ((res[i] = (char *)malloc (len)) == NULL)
339 memset (res[i], 0, len);
340 strcpy (res[i], parms->vars[i]->name);
345 void cgiRedirect (const char *url)
347 if (url && strlen(url)) {
348 printf ("Content-type: text/html\r\nContent-length: %d\r\n", 77+(strlen(url)*2));
349 printf ("Status: 302 Temporal Relocation\r\n");
350 printf ("Location: %s\r\n\r\n", url);
351 printf ("<html>\n<body>\nThe page has been moved to <a href=\"%s\">%s</a>\n</body>\n</html>\n", url, url);
355 void cgiFreeList (char **list)
359 for (i=0; list[i] != NULL; i++)
364 void cgiFree (s_cgi *parms)
371 for (i=0;parms->vars[i]; i++) {
372 if (parms->vars[i]->name)
373 free (parms->vars[i]->name);
374 if (parms->vars[i]->value)
375 free (parms->vars[i]->value);
376 free (parms->vars[i]);
380 if (parms->cookies) {
381 if (parms->cookies[0]->version)
382 free (parms->cookies[0]->version);
383 for (i=0;parms->cookies[i]; i++) {
384 if (parms->cookies[i]->name)
385 free (parms->cookies[i]->name);
386 if (parms->cookies[i]->value)
387 free (parms->cookies[i]->value);
388 if (parms->cookies[i]->path)
389 free (parms->cookies[i]->path);
390 if (parms->cookies[i]->domain)
391 free (parms->cookies[i]->domain);
392 free (parms->cookies[i]);
394 free (parms->cookies);
398 if (cgiHeaderString) {
399 free (cgiHeaderString);
400 cgiHeaderString = NULL;