[PATCH cgi-io 04/12] Refactor utility functions into static library

Petr Štetiar ynezz at true.cz
Mon Oct 12 08:37:10 EDT 2020


For reusability during testing.

Signed-off-by: Petr Štetiar <ynezz at true.cz>
---
 CMakeLists.txt |   7 +-
 main.c         | 270 +----------------------------------------------
 util.c         | 276 +++++++++++++++++++++++++++++++++++++++++++++++++
 util.h         |  11 ++
 4 files changed, 293 insertions(+), 271 deletions(-)
 create mode 100644 util.c
 create mode 100644 util.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c7c9d40caa07..693830a85274 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,7 +19,10 @@ IF(APPLE)
   LINK_DIRECTORIES(/opt/local/lib)
 ENDIF()
 
-ADD_EXECUTABLE(cgi-io main.c multipart_parser.c)
-TARGET_LINK_LIBRARIES(cgi-io ${ubox} ${ubus})
+ADD_LIBRARY(cgi-lib STATIC multipart_parser.c util.c)
+
+ADD_EXECUTABLE(cgi-io main.c)
+TARGET_LINK_LIBRARIES(cgi-io cgi-lib ${ubox} ${ubus})
+
 
 INSTALL(TARGETS cgi-io RUNTIME DESTINATION sbin)
diff --git a/main.c b/main.c
index 53c672836294..ff9bb63f5cd8 100644
--- a/main.c
+++ b/main.c
@@ -35,6 +35,7 @@
 #include <libubus.h>
 #include <libubox/blobmsg.h>
 
+#include "util.h"
 #include "multipart_parser.h"
 
 #ifndef O_TMPFILE
@@ -42,7 +43,6 @@
 #endif
 
 #define READ_BLOCK 4096
-#define POST_LIMIT 131072
 
 enum part {
 	PART_UNKNOWN,
@@ -173,201 +173,6 @@ checksum(const char *applet, size_t sumlen, const char *file)
 	return chksum;
 }
 
-static char *
-datadup(const void *in, size_t len)
-{
-	char *out = malloc(len + 1);
-
-	if (!out)
-		return NULL;
-
-	memcpy(out, in, len);
-
-	*(out + len) = 0;
-
-	return out;
-}
-
-static bool
-urldecode(char *buf)
-{
-	char *c, *p;
-
-	if (!buf || !*buf)
-		return true;
-
-#define hex(x) \
-	(((x) <= '9') ? ((x) - '0') : \
-		(((x) <= 'F') ? ((x) - 'A' + 10) : \
-			((x) - 'a' + 10)))
-
-	for (c = p = buf; *p; c++)
-	{
-		if (*p == '%')
-		{
-			if (!isxdigit(*(p + 1)) || !isxdigit(*(p + 2)))
-				return false;
-
-			*c = (char)(16 * hex(*(p + 1)) + hex(*(p + 2)));
-
-			p += 3;
-		}
-		else if (*p == '+')
-		{
-			*c = ' ';
-			p++;
-		}
-		else
-		{
-			*c = *p++;
-		}
-	}
-
-	*c = 0;
-
-	return true;
-}
-
-static char *
-postdecode(char **fields, int n_fields)
-{
-	const char *var;
-	char *p, *postbuf;
-	int i, field, found = 0;
-	ssize_t len = 0, rlen = 0, content_length = 0;
-
-	var = getenv("CONTENT_TYPE");
-
-	if (!var || strncmp(var, "application/x-www-form-urlencoded", 33))
-		return NULL;
-
-	var = getenv("CONTENT_LENGTH");
-
-	if (!var)
-		return NULL;
-
-	content_length = strtol(var, &p, 10);
-
-	if (p == var || content_length <= 0 || content_length >= POST_LIMIT)
-		return NULL;
-
-	postbuf = calloc(1, content_length + 1);
-
-	if (postbuf == NULL)
-		return NULL;
-
-	for (len = 0; len < content_length; )
-	{
-		rlen = read(0, postbuf + len, content_length - len);
-
-		if (rlen <= 0)
-			break;
-
-		len += rlen;
-	}
-
-	if (len < content_length)
-	{
-		free(postbuf);
-		return NULL;
-	}
-
-	for (p = postbuf, i = 0; i <= len; i++)
-	{
-		if (postbuf[i] == '=')
-		{
-			postbuf[i] = 0;
-
-			for (field = 0; field < (n_fields * 2); field += 2)
-			{
-				if (!strcmp(p, fields[field]))
-				{
-					fields[field + 1] = postbuf + i + 1;
-					found++;
-				}
-			}
-		}
-		else if (postbuf[i] == '&' || postbuf[i] == '\0')
-		{
-			postbuf[i] = 0;
-
-			if (found >= n_fields)
-				break;
-
-			p = postbuf + i + 1;
-		}
-	}
-
-	for (field = 0; field < (n_fields * 2); field += 2)
-	{
-		if (!urldecode(fields[field + 1]))
-		{
-			free(postbuf);
-			return NULL;
-		}
-	}
-
-	return postbuf;
-}
-
-static char *
-canonicalize_path(const char *path, size_t len)
-{
-	char *canonpath, *cp;
-	const char *p, *e;
-
-	if (path == NULL || *path == '\0')
-		return NULL;
-
-	canonpath = datadup(path, len);
-
-	if (canonpath == NULL)
-		return NULL;
-
-	/* normalize */
-	for (cp = canonpath, p = path, e = path + len; p < e; ) {
-		if (*p != '/')
-			goto next;
-
-		/* skip repeating / */
-		if ((p + 1 < e) && (p[1] == '/')) {
-			p++;
-			continue;
-		}
-
-		/* /./ or /../ */
-		if ((p + 1 < e) && (p[1] == '.')) {
-			/* skip /./ */
-			if ((p + 2 >= e) || (p[2] == '/')) {
-				p += 2;
-				continue;
-			}
-
-			/* collapse /x/../ */
-			if ((p + 2 < e) && (p[2] == '.') && ((p + 3 >= e) || (p[3] == '/'))) {
-				while ((cp > canonpath) && (*--cp != '/'))
-					;
-
-				p += 3;
-				continue;
-			}
-		}
-
-next:
-		*cp++ = *p++;
-	}
-
-	/* remove trailing slash if not root / */
-	if ((cp > canonpath + 1) && (cp[-1] == '/'))
-		cp--;
-	else if (cp == canonpath)
-		*cp++ = '/';
-
-	*cp = '\0';
-
-	return canonpath;
-}
-
 static int
 response(bool success, const char *message)
 {
@@ -916,79 +721,6 @@ lookup_executable(const char *cmd)
 	return NULL;
 }
 
-static char **
-parse_command(const char *cmdline)
-{
-	const char *p = cmdline, *s;
-	char **argv = NULL, *out;
-	size_t arglen = 0;
-	int argnum = 0;
-	bool esc;
-
-	while (isspace(*cmdline))
-		cmdline++;
-
-	for (p = cmdline, s = p, esc = false; p; p++) {
-		if (esc) {
-			esc = false;
-		}
-		else if (*p == '\\' && p[1] != 0) {
-			esc = true;
-		}
-		else if (isspace(*p) || *p == 0) {
-			if (p > s) {
-				argnum += 1;
-				arglen += sizeof(char *) + (p - s) + 1;
-			}
-
-			s = p + 1;
-		}
-
-		if (*p == 0)
-			break;
-	}
-
-	if (arglen == 0)
-		return NULL;
-
-	argv = calloc(1, arglen + sizeof(char *));
-
-	if (!argv)
-		return NULL;
-
-	out = (char *)argv + sizeof(char *) * (argnum + 1);
-	argv[0] = out;
-
-	for (p = cmdline, s = p, esc = false, argnum = 0; p; p++) {
-		if (esc) {
-			esc = false;
-			*out++ = *p;
-		}
-		else if (*p == '\\' && p[1] != 0) {
-			esc = true;
-		}
-		else if (isspace(*p) || *p == 0) {
-			if (p > s) {
-				*out++ = ' ';
-				argv[++argnum] = out;
-			}
-
-			s = p + 1;
-		}
-		else {
-			*out++ = *p;
-		}
-
-		if (*p == 0)
-			break;
-	}
-
-	argv[argnum] = NULL;
-	out[-1] = 0;
-
-	return argv;
-}
-
 static int
 main_exec(int argc, char **argv)
 {
diff --git a/util.c b/util.c
new file mode 100644
index 000000000000..9eb7b485e5fa
--- /dev/null
+++ b/util.c
@@ -0,0 +1,276 @@
+#include <ctype.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+
+char **
+parse_command(const char *cmdline)
+{
+	const char *p = cmdline, *s;
+	char **argv = NULL, *out;
+	size_t arglen = 0;
+	int argnum = 0;
+	bool esc;
+
+	while (isspace(*cmdline))
+		cmdline++;
+
+	for (p = cmdline, s = p, esc = false; p; p++) {
+		if (esc) {
+			esc = false;
+		}
+		else if (*p == '\\' && p[1] != 0) {
+			esc = true;
+		}
+		else if (isspace(*p) || *p == 0) {
+			if (p > s) {
+				argnum += 1;
+				arglen += sizeof(char *) + (p - s) + 1;
+			}
+
+			s = p + 1;
+		}
+
+		if (*p == 0)
+			break;
+	}
+
+	if (arglen == 0)
+		return NULL;
+
+	argv = calloc(1, arglen + sizeof(char *));
+
+	if (!argv)
+		return NULL;
+
+	out = (char *)argv + sizeof(char *) * (argnum + 1);
+	argv[0] = out;
+
+	for (p = cmdline, s = p, esc = false, argnum = 0; p; p++) {
+		if (esc) {
+			esc = false;
+			*out++ = *p;
+		}
+		else if (*p == '\\' && p[1] != 0) {
+			esc = true;
+		}
+		else if (isspace(*p) || *p == 0) {
+			if (p > s) {
+				*out++ = ' ';
+				argv[++argnum] = out;
+			}
+
+			s = p + 1;
+		}
+		else {
+			*out++ = *p;
+		}
+
+		if (*p == 0)
+			break;
+	}
+
+	argv[argnum] = NULL;
+	out[-1] = 0;
+
+	return argv;
+}
+
+char *
+postdecode(char **fields, int n_fields)
+{
+	const char *var;
+	char *p, *postbuf;
+	int i, field, found = 0;
+	ssize_t len = 0, rlen = 0, content_length = 0;
+
+	var = getenv("CONTENT_TYPE");
+
+	if (!var || strncmp(var, "application/x-www-form-urlencoded", 33))
+		return NULL;
+
+	var = getenv("CONTENT_LENGTH");
+
+	if (!var)
+		return NULL;
+
+	content_length = strtol(var, &p, 10);
+
+	if (p == var || content_length <= 0 || content_length >= POST_LIMIT)
+		return NULL;
+
+	postbuf = calloc(1, content_length + 1);
+
+	if (postbuf == NULL)
+		return NULL;
+
+	for (len = 0; len < content_length; )
+	{
+		rlen = read(0, postbuf + len, content_length - len);
+
+		if (rlen <= 0)
+			break;
+
+		len += rlen;
+	}
+
+	if (len < content_length)
+	{
+		free(postbuf);
+		return NULL;
+	}
+
+	for (p = postbuf, i = 0; i <= len; i++)
+	{
+		if (postbuf[i] == '=')
+		{
+			postbuf[i] = 0;
+
+			for (field = 0; field < (n_fields * 2); field += 2)
+			{
+				if (!strcmp(p, fields[field]))
+				{
+					fields[field + 1] = postbuf + i + 1;
+					found++;
+				}
+			}
+		}
+		else if (postbuf[i] == '&' || postbuf[i] == '\0')
+		{
+			postbuf[i] = 0;
+
+			if (found >= n_fields)
+				break;
+
+			p = postbuf + i + 1;
+		}
+	}
+
+	for (field = 0; field < (n_fields * 2); field += 2)
+	{
+		if (!urldecode(fields[field + 1]))
+		{
+			free(postbuf);
+			return NULL;
+		}
+	}
+
+	return postbuf;
+}
+
+char *
+datadup(const void *in, size_t len)
+{
+	char *out = malloc(len + 1);
+
+	if (!out)
+		return NULL;
+
+	memcpy(out, in, len);
+
+	*(out + len) = 0;
+
+	return out;
+}
+
+char *
+canonicalize_path(const char *path, size_t len)
+{
+	char *canonpath, *cp;
+	const char *p, *e;
+
+	if (path == NULL || *path == '\0')
+		return NULL;
+
+	canonpath = datadup(path, len);
+
+	if (canonpath == NULL)
+		return NULL;
+
+	/* normalize */
+	for (cp = canonpath, p = path, e = path + len; p < e; ) {
+		if (*p != '/')
+			goto next;
+
+		/* skip repeating / */
+		if ((p + 1 < e) && (p[1] == '/')) {
+			p++;
+			continue;
+		}
+
+		/* /./ or /../ */
+		if ((p + 1 < e) && (p[1] == '.')) {
+			/* skip /./ */
+			if ((p + 2 >= e) || (p[2] == '/')) {
+				p += 2;
+				continue;
+			}
+
+			/* collapse /x/../ */
+			if ((p + 2 < e) && (p[2] == '.') && ((p + 3 >= e) || (p[3] == '/'))) {
+				while ((cp > canonpath) && (*--cp != '/'))
+					;
+
+				p += 3;
+				continue;
+			}
+		}
+
+next:
+		*cp++ = *p++;
+	}
+
+	/* remove trailing slash if not root / */
+	if ((cp > canonpath + 1) && (cp[-1] == '/'))
+		cp--;
+	else if (cp == canonpath)
+		*cp++ = '/';
+
+	*cp = '\0';
+
+	return canonpath;
+}
+
+bool
+urldecode(char *buf)
+{
+	char *c, *p;
+
+	if (!buf || !*buf)
+		return true;
+
+#define hex(x) \
+	(((x) <= '9') ? ((x) - '0') : \
+		(((x) <= 'F') ? ((x) - 'A' + 10) : \
+			((x) - 'a' + 10)))
+
+	for (c = p = buf; *p; c++)
+	{
+		if (*p == '%')
+		{
+			if (!isxdigit(*(p + 1)) || !isxdigit(*(p + 2)))
+				return false;
+
+			*c = (char)(16 * hex(*(p + 1)) + hex(*(p + 2)));
+
+			p += 3;
+		}
+		else if (*p == '+')
+		{
+			*c = ' ';
+			p++;
+		}
+		else
+		{
+			*c = *p++;
+		}
+	}
+
+	*c = 0;
+
+	return true;
+}
diff --git a/util.h b/util.h
new file mode 100644
index 000000000000..0001195df38a
--- /dev/null
+++ b/util.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <stdbool.h>
+
+#define POST_LIMIT 131072
+
+char** parse_command(const char *cmdline);
+char* postdecode(char **fields, int n_fields);
+char* canonicalize_path(const char *path, size_t len);
+bool urldecode(char *buf);
+char* datadup(const void *in, size_t len);



More information about the openwrt-devel mailing list