=================================================================== RCS file: /cvs/mandoc/cgi.c,v retrieving revision 1.31 retrieving revision 1.36 diff -u -p -r1.31 -r1.36 --- mandoc/cgi.c 2011/12/14 13:36:59 1.31 +++ mandoc/cgi.c 2011/12/16 18:37:12 1.36 @@ -1,4 +1,4 @@ -/* $Id: cgi.c,v 1.31 2011/12/14 13:36:59 kristaps Exp $ */ +/* $Id: cgi.c,v 1.36 2011/12/16 18:37:12 kristaps Exp $ */ /* * Copyright (c) 2011 Kristaps Dzonsons * @@ -80,13 +80,17 @@ struct req { }; static int atou(const char *, unsigned *); -static void catman(const char *); +static void catman(const struct req *, const char *); static int cmp(const void *, const void *); -static void format(const char *); +static void format(const struct req *, const char *); static void html_print(const char *); +static void html_printquery(const struct req *); static void html_putchar(char); static int http_decode(char *); static void http_parse(struct req *, char *); +static void http_print(const char *); +static void http_putchar(char); +static void http_printquery(const struct req *); static int pathstop(DIR *); static void pathgen(DIR *, char *, struct req *); static void pg_index(const struct req *, char *); @@ -163,7 +167,41 @@ html_putchar(char c) break; } } +static void +http_printquery(const struct req *req) +{ + printf("&expr="); + http_print(req->q.expr ? req->q.expr : ""); + printf("&sec="); + http_print(req->q.sec ? req->q.sec : ""); + printf("&arch="); + http_print(req->q.arch ? req->q.arch : ""); +} + + +static void +html_printquery(const struct req *req) +{ + + printf("&expr="); + html_print(req->q.expr ? req->q.expr : ""); + printf("&sec="); + html_print(req->q.sec ? req->q.sec : ""); + printf("&arch="); + html_print(req->q.arch ? req->q.arch : ""); +} + +static void +http_print(const char *p) +{ + + if (NULL == p) + return; + while ('\0' != *p) + http_putchar(*p++); +} + /* * Call through to html_putchar(). * Accepts NULL strings. @@ -187,7 +225,6 @@ static void http_parse(struct req *req, char *p) { char *key, *val, *manroot; - size_t sz; int i, legacy; memset(&req->q, 0, sizeof(struct query)); @@ -196,42 +233,24 @@ http_parse(struct req *req, char *p) legacy = -1; manroot = NULL; - while (p && '\0' != *p) { - while (' ' == *p) - p++; - + while ('\0' != *p) { key = p; val = NULL; - if (NULL != (p = strchr(p, '='))) { + p += (int)strcspn(p, ";&"); + if ('\0' != *p) *p++ = '\0'; - val = p; + if (NULL != (val = strchr(key, '='))) + *val++ = '\0'; - sz = strcspn(p, ";&"); - /* LINTED */ - p += sz; - - if ('\0' != *p) - *p++ = '\0'; - } else { - p = key; - sz = strcspn(p, ";&"); - /* LINTED */ - p += sz; - - if ('\0' != *p) - p++; + if ('\0' == *key || NULL == val || '\0' == *val) continue; - } - if ('\0' == *key || '\0' == *val) - continue; - /* Just abort handling. */ if ( ! http_decode(key)) break; - if ( ! http_decode(val)) + if (NULL != val && ! http_decode(val)) break; if (0 == strcmp(key, "expr")) @@ -284,6 +303,20 @@ http_parse(struct req *req, char *p) } } +static void +http_putchar(char c) +{ + + if (isalnum((unsigned char)c)) { + putchar((unsigned char)c); + return; + } else if (' ' == c) { + putchar('+'); + return; + } + printf("%%%.2x", c); +} + /* * HTTP-decode a string. The standard explanation is that this turns * "%4e+foo" into "n foo" in the regular way. This is done in-place @@ -346,12 +379,14 @@ resp_begin_html(int code, const char *msg) "\n" "\n" - "\n" + "\n" "System Manpage Reference\n" "\n" "\n" - "\n", css); + "\n", css, css); } static void @@ -368,7 +403,8 @@ resp_searchform(const struct req *req) int i; puts(""); - printf("
\n" + printf("
\n" + "\n" "
\n" "Search Parameters\n" "\n" "
\n" - ""); + "\n" + "
"); puts(""); } @@ -474,17 +511,19 @@ resp_search(struct res *r, size_t sz, void *arg) req = (const struct req *)arg; assert(req->q.manroot >= 0); - + if (1 == sz) { /* * If we have just one result, then jump there now * without any delay. */ puts("Status: 303 See Other"); - printf("Location: http://%s%s/show/%d/%u/%u.html\n", + printf("Location: http://%s%s/show/%d/%u/%u.html?", host, progname, req->q.manroot, r[0].volume, r[0].rec); - puts("Content-Type: text/html; charset=utf-8\n"); + http_printquery(req); + puts("\n" + "Content-Type: text/html; charset=utf-8\n"); return; } @@ -493,34 +532,35 @@ resp_search(struct res *r, size_t sz, void *arg) resp_begin_html(200, NULL); resp_searchform(req); + puts("
"); + if (0 == sz) { printf("

\n" "No %s results found.\n", req->q.whatis ? "whatis" : "apropos"); if (req->q.whatis) { - printf("(Try q.expr ? req->q.expr : ""); - printf("&sec="); - html_print(req->q.sec ? req->q.sec : ""); - printf("&arch="); - html_print(req->q.arch ? req->q.arch : ""); + printf("(Try " + "apropos?)"); } puts("

"); + puts("
"); resp_end_html(); return; } - puts("

\n" - ""); + puts("
"); for (i = 0; i < (int)sz; i++) { printf("\n" ""); } - puts("
\n" - "", + "q.manroot, r[i].volume, r[i].rec); + html_printquery(req); + printf("\">"); html_print(r[i].title); putchar('('); html_print(r[i].cat); @@ -536,7 +576,8 @@ resp_search(struct res *r, size_t sz, void *arg) "
"); + puts("\n" + ""); resp_end_html(); } @@ -549,7 +590,7 @@ pg_index(const struct req *req, char *path) } static void -catman(const char *file) +catman(const struct req *req, const char *file) { FILE *f; size_t len; @@ -562,21 +603,10 @@ catman(const char *file) return; } - resp_begin_http(200, NULL); - printf("\n" - "\n" - "\n" - "\n" - "\n" - "System Manpage Reference\n" - "\n" - "\n" - "\n" - "
\n", css);
+	resp_begin_html(200, NULL);
+	resp_searchform(req);
+	puts("
\n" + "
");
 
 	while (NULL != (p = fgetln(f, &len))) {
 		bold = italic = 0;
@@ -688,6 +718,7 @@ catman(const char *file)
 	}
 
 	puts("
\n" + "
\n" "\n" ""); @@ -695,7 +726,7 @@ catman(const char *file) } static void -format(const char *file) +format(const struct req *req, const char *file) { struct mparse *mp; int fd; @@ -719,23 +750,31 @@ format(const char *file) return; } - snprintf(opts, sizeof(opts), "style=%s/man.css," + snprintf(opts, sizeof(opts), "fragment," "man=%s/search.html?sec=%%S&expr=%%N," /*"includes=/cgi-bin/man.cgi/usr/include/%%I"*/, - css, progname); + progname); mparse_result(mp, &mdoc, &man); + if (NULL == man && NULL == mdoc) { + resp_baddb(); + mparse_free(mp); + return; + } + + resp_begin_html(200, NULL); + resp_searchform(req); + vp = html_alloc(opts); - if (NULL != mdoc) { - resp_begin_http(200, NULL); + if (NULL != mdoc) html_mdoc(vp, mdoc); - } else if (NULL != man) { - resp_begin_http(200, NULL); + else html_man(vp, man); - } else - resp_baddb(); + puts("\n" + ""); + html_free(vp); mparse_free(mp); } @@ -744,10 +783,11 @@ static void pg_show(const struct req *req, char *path) { struct manpaths ps; + size_t sz; char *sub; char file[MAXPATHLEN]; - const char *fn, *cp; - int rc; + const char *cp; + int rc, catm; unsigned int vol, rec, mr; DB *idx; DBT key, val; @@ -799,7 +839,8 @@ pg_show(const struct req *req, char *path) goto out; } - strlcpy(file, ps.paths[vol], MAXPATHLEN); + sz = strlcpy(file, ps.paths[vol], MAXPATHLEN); + assert(sz < MAXPATHLEN); strlcat(file, "/mandoc.index", MAXPATHLEN); /* Open the index recno(3) database. */ @@ -817,21 +858,24 @@ pg_show(const struct req *req, char *path) if (0 != (rc = (*idx->get)(idx, &key, &val, 0))) { rc < 0 ? resp_baddb() : resp_error400(); goto out; - } + } else if (0 == val.size) { + resp_baddb(); + goto out; + } cp = (char *)val.data; + catm = 'c' == *cp++; - if (NULL == (fn = memchr(cp, '\0', val.size))) + if (NULL == memchr(cp, '\0', val.size - 1)) resp_baddb(); - else if (++fn - cp >= (int)val.size) - resp_baddb(); - else if (NULL == memchr(fn, '\0', val.size - (fn - cp))) - resp_baddb(); else { - if (0 == strcmp(cp, "cat")) - catman(fn + 1); + file[(int)sz] = '\0'; + strlcat(file, "/", MAXPATHLEN); + strlcat(file, cp, MAXPATHLEN); + if (catm) + catman(req, file); else - format(fn + 1); + format(req, file); } out: if (idx)