=================================================================== RCS file: /cvs/mandoc/cgi.c,v retrieving revision 1.54 retrieving revision 1.61 diff -u -p -r1.54 -r1.61 --- mandoc/cgi.c 2014/07/09 09:19:03 1.54 +++ mandoc/cgi.c 2014/07/10 00:52:50 1.61 @@ -1,4 +1,4 @@ -/* $Id: cgi.c,v 1.54 2014/07/09 09:19:03 schwarze Exp $ */ +/* $Id: cgi.c,v 1.61 2014/07/10 00:52:50 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons * Copyright (c) 2014 Ingo Schwarze @@ -20,6 +20,7 @@ #endif #include +#include #include #include #include @@ -27,13 +28,6 @@ #include #include -#if defined(__sun) -/* for stat() */ -#include -#include -#include -#endif - #include "mandoc.h" #include "mandoc_aux.h" #include "main.h" @@ -51,7 +45,7 @@ enum page { * A query as passed to the search function. */ struct query { - const char *manroot; /* manual root directory */ + const char *manpath; /* desired manual directory */ const char *arch; /* architecture */ const char *sec; /* manual section */ const char *expr; /* unparsed expression string */ @@ -59,10 +53,10 @@ struct query { }; struct req { - struct query q; - char **p; /* array of available manroots */ - size_t psz; - enum page page; + struct query q; + char **p; /* array of available manpaths */ + size_t psz; /* number of available manpaths */ + enum page page; }; static void catman(const struct req *, const char *); @@ -80,22 +74,23 @@ static void pathgen(struct req *); static void pg_index(const struct req *, char *); static void pg_search(const struct req *, char *); static void pg_show(const struct req *, char *); -static void resp_bad(void); -static void resp_baddb(void); -static void resp_error400(void); -static void resp_error404(const char *); static void resp_begin_html(int, const char *); static void resp_begin_http(int, const char *); static void resp_end_html(void); +static void resp_error_badrequest(const char *); +static void resp_error_internal(void); +static void resp_error_notfound(const char *); static void resp_index(const struct req *); +static void resp_noresult(const struct req *, + const char *); static void resp_search(const struct req *, struct manpage *, size_t); static void resp_searchform(const struct req *); -static const char *progname; /* cgi script name */ -static const char *cache; /* cache directory */ -static const char *css; /* css directory */ -static const char *host; /* hostname */ +static const char *scriptname; /* CGI script name */ +static const char *mandir; /* contains all manpath directories */ +static const char *cssdir; /* css directory */ +static const char *httphost; /* hostname used in the URIs */ static const char * const pages[PAGE__MAX] = { "index", /* PAGE_INDEX */ @@ -129,13 +124,14 @@ html_putchar(char c) break; } } + static void http_printquery(const struct req *req) { - if (NULL != req->q.manroot) { + if (NULL != req->q.manpath) { printf("&manpath="); - http_print(req->q.manroot); + http_print(req->q.manpath); } if (NULL != req->q.sec) { printf("&sec="); @@ -151,14 +147,13 @@ http_printquery(const struct req *req) } } - static void html_printquery(const struct req *req) { - if (NULL != req->q.manroot) { + if (NULL != req->q.manpath) { printf("&manpath="); - html_print(req->q.manroot); + html_print(req->q.manpath); } if (NULL != req->q.sec) { printf("&sec="); @@ -210,7 +205,7 @@ http_parse(struct req *req, char *p) int legacy; memset(&req->q, 0, sizeof(struct query)); - req->q.manroot = req->p[0]; + req->q.manpath = req->p[0]; legacy = -1; while ('\0' != *p) { @@ -244,7 +239,7 @@ http_parse(struct req *req, char *p) else if (0 == strcmp(key, "arch")) req->q.arch = val; else if (0 == strcmp(key, "manpath")) - req->q.manroot = val; + req->q.manpath = val; else if (0 == strcmp(key, "apropos")) legacy = 0 == strcmp(val, "0"); } @@ -349,7 +344,8 @@ resp_begin_html(int code, const char *msg) "System Manpage Reference\n" "\n" "\n" - "\n", css, css); + "\n", + cssdir, cssdir); } static void @@ -371,9 +367,9 @@ resp_searchform(const struct req *req) "
\n" "Search Parameters\n" " for manuals satisfying \n" + " VALUE=\"Search\"> for manuals matching \n" "q.expr ? req->q.expr : ""); printf("\">, section " "q.arch ? req->q.arch : ""); printf("\">"); if (req->psz > 1) { - puts(", "); for (i = 0; i < (int)req->psz; i++) { printf("
\n" "\n" @@ -412,26 +408,48 @@ resp_index(const struct req *req) { resp_begin_html(200, NULL); + puts("

\n" + "Online manuals with " + "mandoc\n" + "

"); resp_searchform(req); + puts("

\n" + "This web interface is documented in the " + "" + "man.cgi manual, and the " + "" + "apropos manual explains the query syntax.\n" + "

"); resp_end_html(); } static void -resp_error400(void) +resp_noresult(const struct req *req, const char *msg) { + resp_begin_html(200, NULL); + resp_searchform(req); + puts("

"); + puts(msg); + puts("

"); + resp_end_html(); +} - resp_begin_html(400, "Query Malformed"); - printf("

Malformed Query

\n" - "

\n" - "The query your entered was malformed.\n" - "Try again from the\n" - "main page.\n" - "

", progname); +static void +resp_error_badrequest(const char *msg) +{ + + resp_begin_html(400, "Bad Request"); + puts("

Bad Request

\n" + "

\n"); + puts(msg); + printf("Try again from the\n" + "main page.\n" + "

", scriptname); resp_end_html(); } static void -resp_error404(const char *page) +resp_error_notfound(const char *page) { resp_begin_html(404, "Not Found"); @@ -443,29 +461,20 @@ resp_error404(const char *page) printf(",\n" "could not be found.\n" "Try searching from the\n" - "main page.\n" - "

", progname); + "main page.\n" + "

", scriptname); resp_end_html(); } static void -resp_bad(void) +resp_error_internal(void) { resp_begin_html(500, "Internal Server Error"); - puts("

Generic badness happened.

"); + puts("

Internal Server Error

"); resp_end_html(); } static void -resp_baddb(void) -{ - - resp_begin_html(500, "Internal Server Error"); - puts("

Your database is broken.

"); - resp_end_html(); -} - -static void resp_search(const struct req *req, struct manpage *r, size_t sz) { size_t i; @@ -477,36 +486,25 @@ resp_search(const struct req *req, struct manpage *r, */ puts("Status: 303 See Other"); printf("Location: http://%s%s/show/%s/%s?", - host, progname, req->q.manroot, r[0].file); + httphost, scriptname, req->q.manpath, r[0].file); http_printquery(req); puts("\n" "Content-Type: text/html; charset=utf-8\n"); return; } + qsort(r, sz, sizeof(struct manpage), cmp); + resp_begin_html(200, NULL); resp_searchform(req); - puts("
"); - - if (0 == sz) { - puts("

\n" - "No results found.\n" - "

\n" - "
"); - resp_end_html(); - return; - } - - qsort(r, sz, sizeof(struct manpage), cmp); - puts(""); for (i = 0; i < sz; i++) { printf("\n" "
\n" "q.manroot, r[i].file); + scriptname, req->q.manpath, r[i].file); html_printquery(req); printf("\">"); html_print(r[i].names); @@ -541,7 +539,8 @@ catman(const struct req *req, const char *file) int italic, bold; if (NULL == (f = fopen(file, "r"))) { - resp_baddb(); + resp_error_badrequest( + "You specified an invalid manual file."); return; } @@ -679,26 +678,32 @@ format(const struct req *req, const char *file) char opts[PATH_MAX + 128]; if (-1 == (fd = open(file, O_RDONLY, 0))) { - resp_baddb(); + resp_error_badrequest( + "You specified an invalid manual file."); return; } - mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, NULL); + mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL, + req->q.manpath); rc = mparse_readfd(mp, fd, file); close(fd); if (rc >= MANDOCLEVEL_FATAL) { - resp_baddb(); + fprintf(stderr, "fatal mandoc error: %s/%s\n", + req->q.manpath, file); + resp_error_internal(); return; } snprintf(opts, sizeof(opts), "fragment,man=%s/search?sec=%%S&expr=Nm~^%%N$", - progname); + scriptname); mparse_result(mp, &mdoc, &man, NULL); if (NULL == man && NULL == mdoc) { - resp_baddb(); + fprintf(stderr, "fatal mandoc error: %s/%s\n", + req->q.manpath, file); + resp_error_internal(); mparse_free(mp); return; } @@ -726,20 +731,21 @@ pg_show(const struct req *req, char *path) char *sub; if (NULL == path || NULL == (sub = strchr(path, '/'))) { - resp_error400(); + resp_error_badrequest( + "You did not specify a page to show."); return; } *sub++ = '\0'; /* - * Begin by chdir()ing into the manroot. + * Begin by chdir()ing into the manpath. * This way we can pick up the database files, which are * relative to the manpath root. */ if (-1 == chdir(path)) { - perror(path); - resp_baddb(); + resp_error_badrequest( + "You specified an invalid manpath."); return; } @@ -766,9 +772,9 @@ pg_search(const struct req *req, char *path) * relative to the manpath root. */ - if (-1 == (chdir(req->q.manroot))) { - perror(req->q.manroot); - resp_search(req, NULL, 0); + if (-1 == (chdir(req->q.manpath))) { + resp_error_badrequest( + "You specified an invalid manpath."); return; } @@ -804,10 +810,12 @@ pg_search(const struct req *req, char *path) ep++; } - if (mansearch(&search, &paths, sz, cp, "Nd", &res, &ressz)) - resp_search(req, res, ressz); + if (0 == mansearch(&search, &paths, sz, cp, "Nd", &res, &ressz)) + resp_noresult(req, "You entered an invalid query."); + else if (0 == ressz) + resp_noresult(req, "No results found."); else - resp_baddb(); + resp_search(req, res, ressz); for (i = 0; i < sz; i++) free(cp[i]); @@ -829,31 +837,32 @@ main(void) { int i; struct req req; - char *p, *path, *subpath; + char *querystring, *path, *subpath; /* Scan our run-time environment. */ - if (NULL == (cache = getenv("CACHE_DIR"))) - cache = "/cache/man.cgi"; + if (NULL == (mandir = getenv("MAN_DIR"))) + mandir = "/man"; - if (NULL == (progname = getenv("SCRIPT_NAME"))) - progname = ""; + if (NULL == (scriptname = getenv("SCRIPT_NAME"))) + scriptname = ""; - if (NULL == (css = getenv("CSS_DIR"))) - css = ""; + if (NULL == (cssdir = getenv("CSS_DIR"))) + cssdir = ""; - if (NULL == (host = getenv("HTTP_HOST"))) - host = "localhost"; + if (NULL == (httphost = getenv("HTTP_HOST"))) + httphost = "localhost"; /* - * First we change directory into the cache directory so that + * First we change directory into the mandir so that * subsequent scanning for manpath directories is rooted * relative to the same position. */ - if (-1 == chdir(cache)) { - perror(cache); - resp_bad(); + if (-1 == chdir(mandir)) { + fprintf(stderr, "MAN_DIR: %s: %s\n", + mandir, strerror(errno)); + resp_error_internal(); return(EXIT_FAILURE); } @@ -862,8 +871,8 @@ main(void) /* Next parse out the query string. */ - if (NULL != (p = getenv("QUERY_STRING"))) - http_parse(&req, p); + if (NULL != (querystring = getenv("QUERY_STRING"))) + http_parse(&req, querystring); /* * Now juggle paths to extract information. @@ -908,7 +917,7 @@ main(void) pg_show(&req, subpath); break; default: - resp_error404(path); + resp_error_notfound(path); break; } @@ -940,6 +949,8 @@ pathgen(struct req *req) return; while (NULL != (dp = fgetln(fp, &dpsz))) { + if ('\n' == dp[dpsz - 1]) + dpsz--; req->p = mandoc_realloc(req->p, (req->psz + 1) * sizeof(char *)); req->p[req->psz++] = mandoc_strndup(dp, dpsz);