source@mandoc.bsd.lv
 help / color / mirror / Atom feed
From: schwarze@mdocml.bsd.lv
To: source@mdocml.bsd.lv
Subject: mdocml: Rewrite http_parse() completely: 1.
Date: Fri, 25 Jul 2014 12:07:13 -0400 (EDT)	[thread overview]
Message-ID: <201407251607.s6PG7D3i000189@krisdoz.my.domain> (raw)

Log Message:
-----------
Rewrite http_parse() completely:
1. Make sure the last occurrence of each key is used, even if
it is empty, in which case it resets the value to the default.
2. When there is an HTTP encoding error, skip the affected
key-value pair only, but not all subsequent key-value pairs.
3. Do not modify a string returned from getenv(3).
4. Do not assume the NULL pointer is all null bits.

Modified Files:
--------------
    mdocml:
        cgi.c

Revision Data
-------------
Index: cgi.c
===================================================================
RCS file: /usr/vhosts/mdocml.bsd.lv/cvs/mdocml/cgi.c,v
retrieving revision 1.82
retrieving revision 1.83
diff -Lcgi.c -Lcgi.c -u -p -r1.82 -r1.83
--- cgi.c
+++ cgi.c
@@ -39,10 +39,10 @@
  * A query as passed to the search function.
  */
 struct	query {
-	const char	*manpath; /* desired manual directory */
-	const char	*arch; /* architecture */
-	const char	*sec; /* manual section */
-	const char	*expr; /* unparsed expression string */
+	char		*manpath; /* desired manual directory */
+	char		*arch; /* architecture */
+	char		*sec; /* manual section */
+	char		*expr; /* unparsed expression string */
 	int		 equal; /* match whole names, not substrings */
 };
 
@@ -58,7 +58,7 @@ 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_parse(struct req *, const char *);
 static	void		 http_print(const char *);
 static	void 		 http_putchar(char);
 static	void		 http_printquery(const struct req *);
@@ -213,65 +213,114 @@ html_print(const char *p)
 }
 
 /*
- * Parse out key-value pairs from an HTTP request variable.
- * This can be either a cookie or a POST/GET string, although man.cgi
- * uses only GET for simplicity.
+ * Transfer the responsibility for the allocated string *val
+ * to the query structure.
  */
 static void
-http_parse(struct req *req, char *p)
+set_query_attr(char **attr, char **val)
 {
-	char            *key, *val;
 
-	memset(&req->q, 0, sizeof(struct query));
-	req->q.manpath = req->p[0];
-	req->q.equal = 1;
+	free(*attr);
+	if (**val == '\0') {
+		*attr = NULL;
+		free(*val);
+	} else
+		*attr = *val;
+	*val = NULL;
+}
 
-	while ('\0' != *p) {
-		key = p;
-		val = NULL;
+/*
+ * Parse the QUERY_STRING for key-value pairs
+ * and store the values into the query structure.
+ */
+static void
+http_parse(struct req *req, const char *qs)
+{
+	char		*key, *val;
+	size_t		 keysz, valsz;
 
-		p += (int)strcspn(p, ";&");
-		if ('\0' != *p)
-			*p++ = '\0';
-		if (NULL != (val = strchr(key, '=')))
-			*val++ = '\0';
+	req->q.manpath	= NULL;
+	req->q.arch	= NULL;
+	req->q.sec	= NULL;
+	req->q.expr	= NULL;
+	req->q.equal	= 1;
 
-		if ('\0' == *key || NULL == val || '\0' == *val)
-			continue;
+	key = val = NULL;
+	while (*qs != '\0') {
+
+		/* Parse one key. */
 
-		/* Just abort handling. */
+		keysz = strcspn(qs, "=;&");
+		key = mandoc_strndup(qs, keysz);
+		qs += keysz;
+		if (*qs != '=')
+			goto next;
 
-		if ( ! http_decode(key))
-			break;
-		if (NULL != val && ! http_decode(val))
-			break;
-
-		if (0 == strcmp(key, "query"))
-			req->q.expr = val;
-		else if (0 == strcmp(key, "manpath")) {
+		/* Parse one value. */
+
+		valsz = strcspn(++qs, ";&");
+		val = mandoc_strndup(qs, valsz);
+		qs += valsz;
+
+		/* Decode and catch encoding errors. */
+
+		if ( ! (http_decode(key) && http_decode(val)))
+			goto next;
+
+		/* Handle key-value pairs. */
+
+		if ( ! strcmp(key, "query"))
+			set_query_attr(&req->q.expr, &val);
+
+		else if ( ! strcmp(key, "apropos"))
+			req->q.equal = !strcmp(val, "0");
+
+		else if ( ! strcmp(key, "manpath")) {
 #ifdef COMPAT_OLDURI
-			if (0 == strncmp(val, "OpenBSD ", 8)) {
+			if ( ! strncmp(val, "OpenBSD ", 8)) {
 				val[7] = '-';
 				if ('C' == val[8])
 					val[8] = 'c';
 			}
 #endif
-			req->q.manpath = val;
-		} else if (0 == strcmp(key, "apropos"))
-			req->q.equal = !strcmp(val, "0");
-		else if (0 == strcmp(key, "sec")) {
-			if (strcmp(val, "0"))
-				req->q.sec = val;
+			set_query_attr(&req->q.manpath, &val);
+		}
+
+		else if ( ! (strcmp(key, "sec")
 #ifdef COMPAT_OLDURI
-		} else if (0 == strcmp(key, "sektion")) {
-			if (strcmp(val, "0"))
-				req->q.sec = val;
+		    && strcmp(key, "sektion")
 #endif
-		} else if (0 == strcmp(key, "arch")) {
-			if (strcmp(val, "default"))
-				req->q.arch = val;
+		    )) {
+			if ( ! strcmp(val, "0"))
+				*val = '\0';
+			set_query_attr(&req->q.sec, &val);
 		}
+
+		else if ( ! strcmp(key, "arch")) {
+			if ( ! strcmp(val, "default"))
+				*val = '\0';
+			set_query_attr(&req->q.arch, &val);
+		}
+
+		/*
+		 * The key must be freed in any case.
+		 * The val may have been handed over to the query
+		 * structure, in which case it is now NULL.
+		 */
+next:
+		free(key);
+		key = NULL;
+		free(val);
+		val = NULL;
+
+		if (*qs != '\0')
+			qs++;
 	}
+
+	/* Fall back to the default manpath. */
+
+	if (req->q.manpath == NULL)
+		req->q.manpath = mandoc_strdup(req->p[0]);
 }
 
 static void
@@ -895,8 +944,10 @@ pg_show(struct req *req, const char *pat
 		return;
 	}
 
-	if (strcmp(path, "mandoc"))
-		req->q.manpath = path;
+	if (strcmp(path, "mandoc")) {
+		free(req->q.manpath);
+		req->q.manpath = mandoc_strdup(path);
+	}
 
 	resp_begin_html(200, NULL);
 	resp_searchform(req);
@@ -987,7 +1038,7 @@ main(void)
 {
 	struct req	 req;
 	const char	*path;
-	char		*querystring;
+	const char	*querystring;
 	int		 i;
 
 	/* Scan our run-time environment. */
@@ -1050,6 +1101,10 @@ main(void)
 	else
 		pg_index(&req);
 
+	free(req.q.manpath);
+	free(req.q.arch);
+	free(req.q.sec);
+	free(req.q.expr);
 	for (i = 0; i < (int)req.psz; i++)
 		free(req.p[i]);
 	free(req.p);
--
 To unsubscribe send an email to source+unsubscribe@mdocml.bsd.lv

                 reply	other threads:[~2014-07-25 16:07 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=201407251607.s6PG7D3i000189@krisdoz.my.domain \
    --to=schwarze@mdocml.bsd.lv \
    --cc=source@mdocml.bsd.lv \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).