about summary refs log tree commit diff
path: root/sternenblog/cgiutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'sternenblog/cgiutil.c')
-rw-r--r--sternenblog/cgiutil.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/sternenblog/cgiutil.c b/sternenblog/cgiutil.c
new file mode 100644
index 0000000..7dc8114
--- /dev/null
+++ b/sternenblog/cgiutil.c
@@ -0,0 +1,130 @@
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "stringutil.h"
+
+void send_header(char key[], char val[]) {
+    fputs(key, stdout);
+    fputs(": ", stdout);
+    fputs(val, stdout);
+    puts("\r");
+}
+
+void terminate_headers(void) {
+    puts("\r");
+}
+
+char *http_status_line(int status) {
+    switch(status) {
+        case 200:
+            return "200 OK";
+        case 400:
+            return "400 Bad Request";
+        case 401:
+            return "401 Unauthorized";
+        case 403:
+            return "403 Forbidden";
+        case 404:
+            return "404 Not Found";
+        default:
+            // default to 500
+            return "500 Internal Server Error";
+    }
+}
+
+int http_errno(int err) {
+    switch(err) {
+        case EACCES:
+            return 403;
+        case ENOENT:
+            return 404;
+        case ENOTDIR:
+            return 404;
+        default:
+            return 500;
+    }
+}
+
+int urlencode_realloc(char **input, int size) {
+    if(*input == NULL || size <= 0) {
+        return -1;
+    }
+
+    int output_size = size;
+    char *output = malloc(output_size);
+    int output_pos = 0;
+
+    if(output == NULL) {
+        return -1;
+    }
+
+    for(int i = 0; i < size; i++) {
+        char c = *(*input + i);
+        bool needs_escape;
+        switch(c) {
+            // generic delimiters
+            // we assume we never need to escape '/'. This
+            // should hold since on unix filenames won't
+            // contain slashes and the basis for all URLs
+            // in sternenblog are actual files
+            case ':': case '?': case '#': case '[': case ']': case '@':
+            // sub delimiters
+            case '!': case '$': case '&': case '\'': case '(': case ')':
+            case '*': case '+': case ',': case ';': case '=':
+            // other characters to encode
+            case '%': case ' ':
+                needs_escape = 1;
+                break;
+            // in order to simplify the code we just assume
+            // everything else doesn't have to be encoded
+            //
+            // otherwise we'd need to be UTF-8 aware here
+            // and consider more than one byte at a time.
+            default:
+                needs_escape = 0;
+        }
+
+        int necessary_space = needs_escape ? 3 : 1;
+
+        if(output_pos + necessary_space >= output_size) {
+            output_size += necessary_space;
+            char *tmp = realloc(output, output_size);
+            if(tmp == NULL) {
+                free(output);
+                return -1;
+            } else {
+                output = tmp;
+            }
+        }
+
+        if(needs_escape) {
+            short a = (c & 0xf0) >> 4;
+            short b = c & 0x0f;
+            output[output_pos++] = '%';
+            output[output_pos++] = nibble_hex(a);
+            output[output_pos++] = nibble_hex(b);
+        } else {
+            output[output_pos++] = c;
+        }
+    }
+
+    free(*input);
+    *input = output;
+
+    return output_size;
+}
+
+char *server_url(bool https) {
+    char *server_name = getenv("SERVER_NAME");
+    char *server_port = getenv("SERVER_PORT");
+
+    if(server_name == NULL || server_port == NULL) {
+        return NULL;
+    }
+
+    char *proto = https ? "https://" : "http://";
+
+    return catn_alloc(4, proto, server_name, ":", server_port);
+}