Annotation of libaitwww/src/aitwww.c, revision 1.1
1.1 ! misho 1: /*************************************************************************
! 2: * (C) 2012 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
! 3: * by Michael Pounov <misho@elwix.org>
! 4: *
! 5: * $Author: misho $
! 6: * $Id: array.c,v 1.7 2012/02/02 21:32:42 misho Exp $
! 7: *
! 8: **************************************************************************
! 9: The ELWIX and AITNET software is distributed under the following
! 10: terms:
! 11:
! 12: All of the documentation and software included in the ELWIX and AITNET
! 13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
! 14:
! 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
! 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
! 17:
! 18: Redistribution and use in source and binary forms, with or without
! 19: modification, are permitted provided that the following conditions
! 20: are met:
! 21: 1. Redistributions of source code must retain the above copyright
! 22: notice, this list of conditions and the following disclaimer.
! 23: 2. Redistributions in binary form must reproduce the above copyright
! 24: notice, this list of conditions and the following disclaimer in the
! 25: documentation and/or other materials provided with the distribution.
! 26: 3. All advertising materials mentioning features or use of this software
! 27: must display the following acknowledgement:
! 28: This product includes software developed by Michael Pounov <misho@elwix.org>
! 29: ELWIX - Embedded LightWeight unIX and its contributors.
! 30: 4. Neither the name of AITNET nor the names of its contributors
! 31: may be used to endorse or promote products derived from this software
! 32: without specific prior written permission.
! 33:
! 34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
! 35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 44: SUCH DAMAGE.
! 45: */
! 46: #include "global.h"
! 47: #include "tools.h"
! 48: #include "mime.h"
! 49:
! 50:
! 51: #pragma GCC visibility push(hidden)
! 52:
! 53: int www_Errno;
! 54: char www_Error[STRSIZ];
! 55:
! 56: #pragma GCC visibility pop
! 57:
! 58: // www_GetErrno() Get error code of last operation
! 59: inline int
! 60: www_GetErrno()
! 61: {
! 62: return www_Errno;
! 63: }
! 64:
! 65: // www_GetError() Get error text of last operation
! 66: inline const char *
! 67: www_GetError()
! 68: {
! 69: return www_Error;
! 70: }
! 71:
! 72: // www_SetErr() Set error to variables for internal use!!!
! 73: inline void
! 74: www_SetErr(int eno, char *estr, ...)
! 75: {
! 76: va_list lst;
! 77:
! 78: www_Errno = eno;
! 79: memset(www_Error, 0, STRSIZ);
! 80: va_start(lst, estr);
! 81: vsnprintf(www_Error, STRSIZ, estr, lst);
! 82: va_end(lst);
! 83: }
! 84:
! 85: /* -------------------------------------------------------------- */
! 86:
! 87: /*
! 88: * www_initCGI() - Init CGI program
! 89: *
! 90: * return: NULL error or allocated cgi session
! 91: */
! 92: cgi_t *
! 93: www_initCGI(void)
! 94: {
! 95: char *s, *str;
! 96: int ctlen, rlen;
! 97: register int i;
! 98: cgi_t *cgi = NULL;
! 99:
! 100: str = getenv("REQUEST_METHOD");
! 101: if (!str) {
! 102: www_SetErr(EBADMSG, "Request method not found");
! 103: return NULL;
! 104: }
! 105: if (!strcmp(str, "GET") || !strcmp(str, "HEAD")) {
! 106: /* GET | HEAD */
! 107: str = getenv("QUERY_STRING");
! 108: if (!str) {
! 109: www_SetErr(EBADMSG, "Query string not found");
! 110: return NULL;
! 111: }
! 112: cgi = www_parseQuery(str);
! 113: } else if (!strcmp(str, "POST")) {
! 114: /* POST */
! 115: str = getenv("CONTENT_LENGTH");
! 116: if (!str) {
! 117: www_SetErr(EBADMSG, "Content length not found");
! 118: return NULL;
! 119: } else
! 120: ctlen = strtol(str, NULL, 0);
! 121:
! 122: s = getenv("CONTENT_TYPE");
! 123: if (!s) {
! 124: www_SetErr(EBADMSG, "Content type not found");
! 125: return NULL;
! 126: }
! 127: if (www_cmp(s, "multipart/form-data") &&
! 128: www_cmp(s, "application/x-www-form-urlencoded")) {
! 129: www_SetErr(EBADMSG, "MIME parts are broken");
! 130: return NULL;
! 131: }
! 132:
! 133: /* allocated space for post data */
! 134: str = malloc(ctlen + 1);
! 135: if (!str) {
! 136: LOGERR;
! 137: return NULL;
! 138: }
! 139: for (i = 0; i < ctlen && (rlen =
! 140: read(STDIN_FILENO, (void*) str + i, ctlen - i)) > 0; i += rlen);
! 141: str[ctlen] = 0;
! 142:
! 143: if (!www_cmp(s, "application/x-www-form-urlencoded"))
! 144: cgi = www_parseQuery(str);
! 145: else if (!www_cmp(s, "multipart/form-data"))
! 146: cgi = www_parseMultiPart(str, ctlen, s);
! 147:
! 148: free(str);
! 149: } else {
! 150: /* Unknown method */
! 151: www_SetErr(EBADMSG, "Unknown request method");
! 152: return NULL;
! 153: }
! 154:
! 155: return cgi;
! 156: }
! 157:
! 158: /*
! 159: * www_closeCGI() - Close and free all CGI resources
! 160: *
! 161: * @cgi = Inited cgi session
! 162: * return: none
! 163: */
! 164: void
! 165: www_closeCGI(cgi_t ** __restrict cgi)
! 166: {
! 167: struct tagCGI *t;
! 168:
! 169: if (!cgi || !*cgi)
! 170: return;
! 171:
! 172: while ((t = SLIST_FIRST(*cgi))) {
! 173: if (t->cgi_name)
! 174: free(t->cgi_name);
! 175: if (t->cgi_value)
! 176: free(t->cgi_value);
! 177:
! 178: SLIST_REMOVE_HEAD(*cgi, cgi_node);
! 179: free(t);
! 180: }
! 181:
! 182: free(*cgi);
! 183: *cgi = NULL;
! 184: }
! 185:
! 186: /*
! 187: * www_parseQuery() - Parse CGI query string
! 188: *
! 189: * @str = String
! 190: * return: NULL error or allocated cgi session
! 191: */
! 192: cgi_t *
! 193: www_parseQuery(const char *str)
! 194: {
! 195: char *base, *wrk;
! 196: cgi_t *cgi;
! 197: struct tagCGI *t, *old = NULL;
! 198:
! 199: if (!str) {
! 200: www_SetErr(EINVAL, "String is NULL");
! 201: return NULL;
! 202: }
! 203:
! 204: cgi = malloc(sizeof(cgi_t));
! 205: if (!cgi) {
! 206: LOGERR;
! 207: return NULL;
! 208: } else {
! 209: memset(cgi, 0, sizeof(cgi_t));
! 210: SLIST_INIT(cgi);
! 211: }
! 212:
! 213: base = wrk = strdup(str);
! 214:
! 215: while (*wrk) {
! 216: t = malloc(sizeof(struct tagCGI));
! 217: if (!t) {
! 218: LOGERR;
! 219: www_closeCGI(&cgi);
! 220: return NULL;
! 221: } else
! 222: memset(t, 0, sizeof(struct tagCGI));
! 223:
! 224: t->cgi_name = www_getpair(&wrk, "=");
! 225: www_unescape(t->cgi_name);
! 226:
! 227: t->cgi_value = www_getpair(&wrk, "&;");
! 228: www_unescape(t->cgi_value);
! 229:
! 230: if (!old)
! 231: SLIST_INSERT_HEAD(cgi, t, cgi_node);
! 232: else
! 233: SLIST_INSERT_AFTER(old, t, cgi_node);
! 234: old = t;
! 235: }
! 236:
! 237: free(base);
! 238: return 0;
! 239: }
! 240:
! 241: /*
! 242: * www_getValue() - Get Value from CGI session
! 243: *
! 244: * @cgi = Inited cgi session
! 245: * @name = Name of cgi variable
! 246: * return: NULL not found or !=NULL value
! 247: */
! 248: inline const char *
! 249: www_getValue(cgi_t * __restrict cgi, const char *name)
! 250: {
! 251: struct tagCGI *t;
! 252:
! 253: if (!cgi || !name) {
! 254: www_SetErr(EINVAL, "Invalid argument(s)");
! 255: return NULL;
! 256: }
! 257:
! 258: SLIST_FOREACH(t, cgi, cgi_node)
! 259: if (t->cgi_name && !strcmp(name, t->cgi_name))
! 260: break;
! 261:
! 262: return t->cgi_value;
! 263: }
! 264:
! 265: /*
! 266: * www_addValue() - Add new or update if exists CGI variable
! 267: *
! 268: * @cgi = Inited cgi session
! 269: * @name = Name of cgi variable
! 270: * @value = Value of cgi variable
! 271: * return: -1 error, 0 add new one or 1 updated variable
! 272: */
! 273: int
! 274: www_addValue(cgi_t * __restrict cgi, const char *name, const char *value)
! 275: {
! 276: struct tagCGI *t, *tmp;
! 277:
! 278: if (!cgi || !name) {
! 279: www_SetErr(EINVAL, "Invalid argument(s)");
! 280: return -1;
! 281: }
! 282:
! 283: /* search for update */
! 284: SLIST_FOREACH_SAFE(t, cgi, cgi_node, tmp) {
! 285: if (t->cgi_name && !strcmp(name, t->cgi_name)) {
! 286: if (t->cgi_value)
! 287: free(t->cgi_value);
! 288: if (value)
! 289: t->cgi_value = strdup(value);
! 290: /* update */
! 291: return 1;
! 292: }
! 293: /* save last cgi pair */
! 294: if (!tmp)
! 295: break;
! 296: }
! 297:
! 298: /* add new one */
! 299: tmp = malloc(sizeof(struct tagCGI));
! 300: if (!tmp) {
! 301: LOGERR;
! 302: return -1;
! 303: } else
! 304: memset(tmp, 0, sizeof(struct tagCGI));
! 305:
! 306: tmp->cgi_name = strdup(name);
! 307: if (value)
! 308: tmp->cgi_value = strdup(value);
! 309:
! 310: SLIST_INSERT_AFTER(t, tmp, cgi_node);
! 311: return 0;
! 312: }
! 313:
! 314: /*
! 315: * www_delPair() - Delete CGI variable from session
! 316: *
! 317: * @cgi = Inited cgi session
! 318: * @name = Name of cgi variable
! 319: * return: -1 error, 0 not found or 1 deleted ok
! 320: */
! 321: int
! 322: www_delPair(cgi_t * __restrict cgi, const char *name)
! 323: {
! 324: struct tagCGI *t;
! 325:
! 326: if (!cgi || !name) {
! 327: www_SetErr(EINVAL, "Invalid argument(s)");
! 328: return -1;
! 329: }
! 330:
! 331: /* search for delete */
! 332: SLIST_FOREACH(t, cgi, cgi_node)
! 333: if (t->cgi_name && !strcmp(name, t->cgi_name)) {
! 334: SLIST_REMOVE(cgi, t, tagCGI, cgi_node);
! 335: return 1;
! 336: }
! 337:
! 338: return 0;
! 339: }
! 340:
! 341: /*
! 342: * www_header() - Output initial html header
! 343: *
! 344: * @output = file handle
! 345: * return: <1 error or >0 writed bytes
! 346: */
! 347: inline int
! 348: www_header(FILE *output)
! 349: {
! 350: FILE *f = output ? output : stdout;
! 351:
! 352: return fputs("Content-type: text/html\n\n", f);
! 353: }
! 354:
! 355: static char *
! 356: quotStr(const char *str, const char **end)
! 357: {
! 358: char *s, *e;
! 359: int n, len = 0;
! 360: register int i;
! 361:
! 362: /* get str w/o " */
! 363: if (*str != '"') {
! 364: n = strspn(str, "!#$%&'*+-.0123456789?ABCDEFGHIJKLMNOPQRSTUVWXYZ"
! 365: "^_`abcdefghijklmnopqrstuvwxyz{|}~");
! 366: s = malloc(n + 1);
! 367: if (!s) {
! 368: LOGERR;
! 369: return NULL;
! 370: } else {
! 371: strncpy(s, str, n);
! 372: s[n] = 0;
! 373: *end = str + n;
! 374: return s;
! 375: }
! 376: } else
! 377: str++;
! 378: /* get quoted string */
! 379: if (!(e = strchr(str, '"')))
! 380: return NULL;
! 381: else
! 382: len = e - str;
! 383: s = malloc(len + 1);
! 384: if (!s) {
! 385: LOGERR;
! 386: return NULL;
! 387: }
! 388:
! 389: for (i = 0; i < len; i++, str++) {
! 390: if (*str == '\\' || *str == '\n')
! 391: s[i] = *++str;
! 392: else if (*str == '"')
! 393: break;
! 394: else
! 395: s[i] = *str;
! 396: }
! 397: s[i] = 0;
! 398:
! 399: *end = ++str;
! 400: return s;
! 401: }
! 402:
! 403: static struct tagCGI *
! 404: addAttr(const char **ct)
! 405: {
! 406: struct tagCGI *a;
! 407: const char *c, *eq;
! 408: char *name, *value;
! 409:
! 410: if (!*ct || !(c = strchr(*ct, ';')))
! 411: return NULL;
! 412: else
! 413: c++;
! 414: while (isspace(*c))
! 415: c++;
! 416:
! 417: if (!(eq = strchr(c, '=')))
! 418: return NULL;
! 419:
! 420: /* parse name */
! 421: name = malloc(eq - c + 1);
! 422: if (!name) {
! 423: LOGERR;
! 424: return NULL;
! 425: } else {
! 426: strncpy(name, c, eq - c);
! 427: name[eq - c] = 0;
! 428: }
! 429: /* parse value */
! 430: value = quotStr(++eq, &c);
! 431: if (!value) {
! 432: free(name);
! 433: return NULL;
! 434: }
! 435:
! 436: /* fill tagCGI */
! 437: a = malloc(sizeof(struct tagCGI));
! 438: if (!a) {
! 439: LOGERR;
! 440: return NULL;
! 441: } else {
! 442: a->cgi_name = name;
! 443: a->cgi_value = value;
! 444: *ct = c;
! 445: }
! 446: return a;
! 447: }
! 448:
! 449: /*
! 450: * www_parseMultiPart() - Parse Multi part POST CGI query string
! 451: *
! 452: * @str = String
! 453: * @ctlen = Content length
! 454: * @ct = Content type
! 455: * return: NULL error or allocated cgi session
! 456: */
! 457: cgi_t *
! 458: www_parseMultiPart(const char *str, int ctlen, const char *ct)
! 459: {
! 460: cgi_t *cgi, *attr;
! 461: mime_t *mime = NULL;
! 462: struct tagMIME *m;
! 463: struct tagCGI *t, *old = NULL;
! 464: const char *s;
! 465: int len;
! 466:
! 467: if (!str) {
! 468: www_SetErr(EINVAL, "String is NULL");
! 469: return NULL;
! 470: }
! 471:
! 472: cgi = malloc(sizeof(cgi_t));
! 473: if (!cgi) {
! 474: LOGERR;
! 475: return NULL;
! 476: } else {
! 477: memset(cgi, 0, sizeof(cgi_t));
! 478: SLIST_INIT(cgi);
! 479: }
! 480:
! 481: /* parse MIME messages */
! 482: attr = www_parseAttributes(&ct);
! 483: if (!attr) {
! 484: www_closeCGI(&cgi);
! 485: return NULL;
! 486: }
! 487: mime = mime_parseMultiPart(str, ctlen, www_getAttribute(attr, "boundary"), NULL);
! 488: www_freeAttributes(&attr);
! 489:
! 490: SLIST_FOREACH(m, mime, mime_node) {
! 491: s = mime_getValue(m, "content-disposition");
! 492: attr = www_parseAttributes(&s);
! 493:
! 494: t = malloc(sizeof(struct tagCGI));
! 495: if (!t) {
! 496: LOGERR;
! 497: mime_close(&mime);
! 498: www_closeCGI(&cgi);
! 499: return NULL;
! 500: } else
! 501: memset(t, 0, sizeof(struct tagCGI));
! 502:
! 503: t->cgi_name = strdup(www_getAttribute(attr, "name"));
! 504: len = mime_calcRawSize(m);
! 505: t->cgi_value = malloc(len + 1);
! 506: if (t->cgi_value) {
! 507: len = mime_getRawData(m, t->cgi_value, len + 1);
! 508: t->cgi_value[len] = 0;
! 509: }
! 510:
! 511: www_freeAttributes(&attr);
! 512:
! 513: if (!old)
! 514: SLIST_INSERT_HEAD(cgi, t, cgi_node);
! 515: else
! 516: SLIST_INSERT_AFTER(old, t, cgi_node);
! 517: old = t;
! 518: }
! 519:
! 520: mime_close(&mime);
! 521: return cgi;
! 522: }
! 523:
! 524: /*
! 525: * www_parseAttributes() - Parse attributes
! 526: *
! 527: * @ct = Content type
! 528: * return: NULL error or !=NULL attributes
! 529: */
! 530: inline cgi_t *
! 531: www_parseAttributes(const char **ct)
! 532: {
! 533: struct tagCGI *t, *old = NULL;
! 534: cgi_t *attr = NULL;
! 535:
! 536: if (!ct) {
! 537: www_SetErr(EINVAL, "String is NULL");
! 538: return NULL;
! 539: }
! 540:
! 541: attr = malloc(sizeof(cgi_t));
! 542: if (!attr) {
! 543: LOGERR;
! 544: return NULL;
! 545: } else {
! 546: memset(attr, 0, sizeof(cgi_t));
! 547: SLIST_INIT(attr);
! 548: }
! 549:
! 550: /* get mime attributes */
! 551: while ((t = addAttr(ct))) {
! 552: if (!old)
! 553: SLIST_INSERT_HEAD(attr, t, cgi_node);
! 554: else
! 555: SLIST_INSERT_AFTER(old, t, cgi_node);
! 556: old = t;
! 557: }
! 558:
! 559: return attr;
! 560: }
! 561:
! 562: /*
! 563: * www_freeAttributes() - Free attributes
! 564: *
! 565: * @attr = Attributes
! 566: * return: none
! 567: */
! 568: inline void
! 569: www_freeAttributes(cgi_t ** __restrict attr)
! 570: {
! 571: struct tagCGI *t;
! 572:
! 573: if (!attr || !*attr)
! 574: return;
! 575:
! 576: /* free mime attributes */
! 577: while ((t = SLIST_FIRST(*attr))) {
! 578: if (t->cgi_name)
! 579: free(t->cgi_name);
! 580: if (t->cgi_value)
! 581: free(t->cgi_value);
! 582: SLIST_REMOVE_HEAD(*attr, cgi_node);
! 583: free(t);
! 584: }
! 585:
! 586: free(*attr);
! 587: *attr = NULL;
! 588: }
! 589:
! 590: /*
! 591: * www_getAttribute() - Get attribute by name
! 592: *
! 593: * @attr = Attributes
! 594: * @name = Name of attribute
! 595: * return: NULL not found or !=NULL attribute value
! 596: */
! 597: inline const char *
! 598: www_getAttribute(cgi_t * __restrict attr, const char *name)
! 599: {
! 600: struct tagCGI *t;
! 601:
! 602: SLIST_FOREACH(t, attr, cgi_node)
! 603: if (!strcasecmp(t->cgi_name, name))
! 604: return t->cgi_value;
! 605:
! 606: return NULL;
! 607: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>