Refactor utility functions into static library
authorPetr Štetiar <ynezz@true.cz>
Sun, 11 Oct 2020 10:43:40 +0000 (12:43 +0200)
committerPetr Štetiar <ynezz@true.cz>
Tue, 27 Oct 2020 22:03:04 +0000 (23:03 +0100)
For reusability during testing.

Signed-off-by: Petr Štetiar <ynezz@true.cz>
CMakeLists.txt
main.c
util.c [new file with mode: 0644]
util.h [new file with mode: 0644]

index c7c9d40caa0761299bf63922782e9be9e753bf7f..693830a85274b4fb1e1cd6ab3a818bdd93d2fc7d 100644 (file)
@@ -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 53c672836294df7f97074ef4492dd48030dcd056..ff9bb63f5cd8fabbb91aa06c61095c93379e8189 100644 (file)
--- 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 (file)
index 0000000..9eb7b48
--- /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 (file)
index 0000000..0001195
--- /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);