From 073faa9daabed86280f98fdf6e03c930b0c97d71 Mon Sep 17 00:00:00 2001 From: Ingo Schwarze Date: Thu, 17 Mar 2016 21:22:59 +0000 Subject: support short URIs for man.openbsd.org --- cgi.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/cgi.c b/cgi.c index 0b01d066..cb041b68 100644 --- a/cgi.c +++ b/cgi.c @@ -1,4 +1,4 @@ -/* $Id: cgi.c,v 1.116 2016/01/04 12:36:26 schwarze Exp $ */ +/* $Id: cgi.c,v 1.117 2016/03/17 21:22:59 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons * Copyright (c) 2014, 2015 Ingo Schwarze @@ -64,6 +64,7 @@ static void html_putchar(char); static int http_decode(char *); static void http_parse(struct req *, const char *); static void pathgen(struct req *); +static void path_parse(struct req *req, const char *path); static void pg_error_badrequest(const char *); static void pg_error_internal(void); static void pg_index(const struct req *); @@ -1033,11 +1034,21 @@ main(void) memset(&req, 0, sizeof(struct req)); pathgen(&req); - /* Next parse out the query string. */ + /* Parse the path info and the query string. */ - if (NULL != (querystring = getenv("QUERY_STRING"))) + if ((path = getenv("PATH_INFO")) == NULL) + path = ""; + else if (*path == '/') + path++; + + if (*path != '\0' && access(path, F_OK) == -1) { + path_parse(&req, path); + path = ""; + } else if ((querystring = getenv("QUERY_STRING")) != NULL) http_parse(&req, querystring); + /* Validate parsed data and add defaults. */ + if (req.q.manpath == NULL) req.q.manpath = mandoc_strdup(req.p[0]); else if ( ! validate_manpath(&req, req.q.manpath)) { @@ -1054,12 +1065,6 @@ main(void) /* Dispatch to the three different pages. */ - path = getenv("PATH_INFO"); - if (NULL == path) - path = ""; - else if ('/' == *path) - path++; - if ('\0' != *path) pg_show(&req, path); else if (NULL != req.q.query) @@ -1077,6 +1082,61 @@ main(void) return EXIT_SUCCESS; } +/* + * If PATH_INFO is not a file name, translate it to a query. + */ +static void +path_parse(struct req *req, const char *path) +{ + int dir_done; + + req->q.equal = 1; + req->q.manpath = mandoc_strdup(path); + + /* Mandatory manual page name. */ + if ((req->q.query = strrchr(req->q.manpath, '/')) == NULL) { + req->q.query = req->q.manpath; + req->q.manpath = NULL; + } else + *req->q.query++ = '\0'; + + /* Optional trailing section. */ + if ((req->q.sec = strrchr(req->q.query, '.')) != NULL) { + if(isdigit((unsigned char)req->q.sec[1])) { + *req->q.sec++ = '\0'; + req->q.sec = mandoc_strdup(req->q.sec); + } else + req->q.sec = NULL; + } + + /* Handle the case of name[.section] only. */ + if (req->q.manpath == NULL) { + req->q.arch = NULL; + return; + } + req->q.query = mandoc_strdup(req->q.query); + + /* Optional architecture. */ + dir_done = 0; + for (;;) { + if ((req->q.arch = strrchr(req->q.manpath, '/')) == NULL) + break; + *req->q.arch++ = '\0'; + if (dir_done || strncmp(req->q.arch, "man", 3)) { + req->q.arch = mandoc_strdup(req->q.arch); + break; + } + + /* Optional directory name. */ + req->q.arch += 3; + if (*req->q.arch != '\0') { + free(req->q.sec); + req->q.sec = mandoc_strdup(req->q.arch); + } + dir_done = 1; + } +} + /* * Scan for indexable paths. */ -- cgit v1.2.3-56-ge451