Annotation of mandoc/cgi.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: html.c,v 1.2 2011/11/04 15:53:19 kristaps Exp $ */
! 2: #include <assert.h>
! 3: #include <fcntl.h>
! 4: #include <regex.h>
! 5: #include <stdio.h>
! 6: #include <stdarg.h>
! 7: #include <stdlib.h>
! 8: #include <string.h>
! 9:
! 10: #include "apropos.h"
! 11: #include "mandoc.h"
! 12:
! 13: /*
! 14: * The page a request is trying to make.
! 15: */
! 16: enum page {
! 17: PAGE_INDEX,
! 18: PAGE_SEARCH,
! 19: PAGE__MAX
! 20: };
! 21:
! 22: /*
! 23: * Key-value pair.
! 24: * Both key and val are on the heap.
! 25: */
! 26: struct kval {
! 27: char *key;
! 28: char *val;
! 29: };
! 30:
! 31: /*
! 32: * The media type, determined by suffix, of the requesting or responding
! 33: * context.
! 34: */
! 35: enum media {
! 36: MEDIA_HTML,
! 37: MEDIA__MAX
! 38: };
! 39:
! 40: /*
! 41: * An HTTP request.
! 42: */
! 43: struct req {
! 44: struct kval *fields; /* query fields */
! 45: size_t fieldsz;
! 46: enum media media;
! 47: enum page page;
! 48: };
! 49:
! 50: static void html_printtext(const char *);
! 51: static int kval_decode(char *);
! 52: static void kval_parse(struct kval **, size_t *, char *);
! 53: static void kval_free(struct kval *, size_t);
! 54: static void pg_index(const struct req *, char *);
! 55: static void pg_search(const struct req *, char *);
! 56: static void pg_searchres(struct rec *, size_t, void *);
! 57:
! 58: static const char * const pages[PAGE__MAX] = {
! 59: "index", /* PAGE_INDEX */
! 60: "search", /* PAGE_SEARCH */
! 61: };
! 62:
! 63: static const char * const medias[MEDIA__MAX] = {
! 64: "html", /* MEDIA_HTML */
! 65: };
! 66:
! 67: static void
! 68: html_printtext(const char *p)
! 69: {
! 70: char c;
! 71:
! 72: while ('\0' != *p)
! 73: switch ((c = *p++)) {
! 74: case ('"'):
! 75: printf(""e;");
! 76: break;
! 77: case ('&'):
! 78: printf("&");
! 79: break;
! 80: case ('>'):
! 81: printf(">");
! 82: break;
! 83: case ('<'):
! 84: printf("<");
! 85: break;
! 86: default:
! 87: putchar((unsigned char)c);
! 88: break;
! 89: }
! 90: }
! 91:
! 92: static void
! 93: kval_free(struct kval *p, size_t sz)
! 94: {
! 95: int i;
! 96:
! 97: for (i = 0; i < (int)sz; i++) {
! 98: free(p[i].key);
! 99: free(p[i].val);
! 100: }
! 101: free(p);
! 102: }
! 103:
! 104: /*
! 105: * Parse out key-value pairs from an HTTP request variable.
! 106: * This can be either a cookie or a POST/GET string.
! 107: */
! 108: static void
! 109: kval_parse(struct kval **kv, size_t *kvsz, char *p)
! 110: {
! 111: char *key, *val;
! 112: size_t sz, cur;
! 113:
! 114: cur = 0;
! 115:
! 116: while (p && '\0' != *p) {
! 117: while (' ' == *p)
! 118: p++;
! 119:
! 120: key = p;
! 121: val = NULL;
! 122:
! 123: if (NULL != (p = strchr(p, '='))) {
! 124: *p++ = '\0';
! 125: val = p;
! 126:
! 127: sz = strcspn(p, ";&");
! 128: /* LINTED */
! 129: p += sz;
! 130:
! 131: if ('\0' != *p)
! 132: *p++ = '\0';
! 133: } else {
! 134: p = key;
! 135: sz = strcspn(p, ";&");
! 136: /* LINTED */
! 137: p += sz;
! 138:
! 139: if ('\0' != *p)
! 140: p++;
! 141: continue;
! 142: }
! 143:
! 144: if ('\0' == *key || '\0' == *val)
! 145: continue;
! 146:
! 147: /* Just abort handling. */
! 148:
! 149: if ( ! kval_decode(key))
! 150: return;
! 151: if ( ! kval_decode(val))
! 152: return;
! 153:
! 154: if (*kvsz + 1 >= cur) {
! 155: cur++;
! 156: *kv = mandoc_realloc
! 157: (*kv, cur * sizeof(struct kval));
! 158: }
! 159:
! 160: (*kv)[(int)*kvsz].key = mandoc_strdup(key);
! 161: (*kv)[(int)*kvsz].val = mandoc_strdup(val);
! 162: (*kvsz)++;
! 163: }
! 164: }
! 165:
! 166: /*
! 167: * In-place HTTP-decode a string. The standard explanation is that this
! 168: * turns "%4e+foo" into "n foo" in the regular way. This is done
! 169: * in-place over the allocated string.
! 170: */
! 171: static int
! 172: kval_decode(char *p)
! 173: {
! 174: char hex[3];
! 175: int c;
! 176:
! 177: hex[2] = '\0';
! 178:
! 179: for ( ; '\0' != *p; p++) {
! 180: if ('%' == *p) {
! 181: if ('\0' == (hex[0] = *(p + 1)))
! 182: return(0);
! 183: if ('\0' == (hex[1] = *(p + 2)))
! 184: return(0);
! 185: if (1 != sscanf(hex, "%x", &c))
! 186: return(0);
! 187: if ('\0' == c)
! 188: return(0);
! 189:
! 190: *p = (char)c;
! 191: memmove(p + 1, p + 3, strlen(p + 3) + 1);
! 192: } else
! 193: *p = '+' == *p ? ' ' : *p;
! 194: }
! 195:
! 196: *p = '\0';
! 197: return(1);
! 198: }
! 199:
! 200:
! 201: /* ARGSUSED */
! 202: static void
! 203: pg_index(const struct req *req, char *path)
! 204: {
! 205:
! 206: }
! 207:
! 208: static void
! 209: pg_searchres(struct rec *recs, size_t sz, void *arg)
! 210: {
! 211: int i;
! 212: const char *pg;
! 213:
! 214: if (NULL == (pg = getenv("SCRIPT_NAME")))
! 215: pg = "";
! 216:
! 217: for (i = 0; i < (int)sz; i++) {
! 218: printf("<A HREF=\"%s/show/%u.html\">",
! 219: pg, recs[i].rec);
! 220: html_printtext(recs[i].title);
! 221: putchar('(');
! 222: html_printtext(recs[i].cat);
! 223: puts(")</A>");
! 224: }
! 225: }
! 226:
! 227: static void
! 228: pg_search(const struct req *req, char *path)
! 229: {
! 230: int i;
! 231: struct opts opt;
! 232:
! 233: for (i = 0; i < (int)req->fieldsz; i++)
! 234: if (0 == strcmp(req->fields[i].key, "key"))
! 235: break;
! 236:
! 237: if (i == (int)req->fieldsz)
! 238: return;
! 239:
! 240: memset(&opt, 0, sizeof(struct opts));
! 241: opt.types = TYPE_NAME | TYPE_DESC;
! 242: apropos_search(&opt, req->fields[i].val, NULL, pg_searchres);
! 243: }
! 244:
! 245: int
! 246: main(void)
! 247: {
! 248: int i;
! 249: struct req req;
! 250: char *p;
! 251: char *path, *subpath, *suffix;
! 252:
! 253: memset(&req, 0, sizeof(struct req));
! 254:
! 255: if (NULL != (p = getenv("QUERY_STRING")))
! 256: kval_parse(&req.fields, &req.fieldsz, p);
! 257:
! 258: suffix = subpath = path = NULL;
! 259:
! 260: req.media = MEDIA_HTML;
! 261: req.page = PAGE__MAX;
! 262:
! 263: if (NULL == (path = getenv("PATH_INFO")) || '\0' == *path)
! 264: req.page = PAGE_INDEX;
! 265: if (NULL != path && '/' == *path && '\0' == *++path)
! 266: req.page = PAGE_INDEX;
! 267:
! 268: if (NULL != path && NULL != (suffix = strrchr(path, '.')))
! 269: if (NULL != suffix && NULL == strchr(suffix, '/'))
! 270: *suffix++ = '\0';
! 271:
! 272: if (NULL != path && NULL != (subpath = strchr(path, '/')))
! 273: *subpath++ = '\0';
! 274:
! 275: if (NULL != suffix && '\0' != *suffix)
! 276: for (i = 0; i < (int)MEDIA__MAX; i++)
! 277: if (0 == strcmp(medias[i], suffix)) {
! 278: req.media = (enum media)i;
! 279: break;
! 280: }
! 281:
! 282: if (NULL != path && '\0' != *path)
! 283: for (i = 0; i < (int)PAGE__MAX; i++)
! 284: if (0 == strcmp(pages[i], path)) {
! 285: req.page = (enum page)i;
! 286: break;
! 287: }
! 288:
! 289: switch (req.page) {
! 290: case (PAGE_INDEX):
! 291: pg_index(&req, subpath);
! 292: break;
! 293: case (PAGE_SEARCH):
! 294: pg_search(&req, subpath);
! 295: break;
! 296: default:
! 297: /* Blah */
! 298: break;
! 299: }
! 300:
! 301: kval_free(req.fields, req.fieldsz);
! 302: return(EXIT_SUCCESS);
! 303: }
CVSweb