diff options
Diffstat (limited to 'sternenblog/cgiutil.c')
-rw-r--r-- | sternenblog/cgiutil.c | 130 |
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); +} |