diff options
author | sternenseemann <0rpkxez4ksa01gb3typccl0i@systemli.org> | 2021-06-07 00:36:06 +0200 |
---|---|---|
committer | sternenseemann <0rpkxez4ksa01gb3typccl0i@systemli.org> | 2021-06-07 00:36:06 +0200 |
commit | 0ba9f89610a55f2cec6617f3b8864a7b94df886e (patch) | |
tree | 493b41b742e7856bae92142a9bbdd9df0bfe9be5 | |
parent | bee1aa3d3c48cf9600cf0502fb78ac8ca3c9972c (diff) |
refactor: return enum-ed error codes instead of HTTP status
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | entry.c | 45 | ||||
-rw-r--r-- | error.c | 32 | ||||
-rw-r--r-- | error.h | 26 | ||||
-rw-r--r-- | index.c | 11 | ||||
-rw-r--r-- | main.c | 25 |
6 files changed, 101 insertions, 40 deletions
diff --git a/Makefile b/Makefile index ea40383..fd31f4a 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ include config.mk ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) -sternenblog.cgi: xml.o entry.o index.o stringutil.o cgiutil.o timeutil.o $(TEMPLATE).o main.o +sternenblog.cgi: xml.o entry.o index.o stringutil.o cgiutil.o timeutil.o error.o $(TEMPLATE).o main.o $(CC) $(CFLAGS) -o $@ $^ main.o: main.c timeutil.h config.h diff --git a/entry.c b/entry.c index aac705d..112b2e9 100644 --- a/entry.c +++ b/entry.c @@ -10,15 +10,13 @@ #include <sys/types.h> #include <unistd.h> +#include "error.h" #include "config.h" // TODO: make independent? #include "cgiutil.h" #include "entry.h" int make_entry(const char *blog_dir, char *script_name, char *path_info, struct entry *entry) { // TODO: allow subdirectories? - // TODO: no status code return? - - // TODO: url encoding of links // intialize pointers entry->time = 0; @@ -33,7 +31,7 @@ int make_entry(const char *blog_dir, char *script_name, char *path_info, struct // validate path_info if(path_info == NULL) { fprintf(stderr, "Missing PATH_INFO\n"); - return 500; + return STERNENBLOG_ERROR_CGI; } size_t path_info_len = strlen(path_info); @@ -42,7 +40,7 @@ int make_entry(const char *blog_dir, char *script_name, char *path_info, struct // as per RFC3875 expect it to start with a slash if(path_info_len == 0 || path_info[0] != '/') { fprintf(stderr, "Malformed PATH_INFO: \"%s\"\n", path_info); - return 400; + return STERNENBLOG_ERROR_REQUEST; } // check if the path_info segments are alright @@ -54,11 +52,11 @@ int make_entry(const char *blog_dir, char *script_name, char *path_info, struct case '/': // TODO: necessary? fprintf(stderr, "Double slash in PATH_INFO: \"%s\"\n", path_info); - return 400; + return STERNENBLOG_ERROR_REQUEST; break; case '.': fprintf(stderr, "Dot file or dir in PATH_INFO: \"%s\"\n", path_info); - return 403; + return STERNENBLOG_ERROR_FORBIDDEN; break; default: last_was_slash = 0; @@ -71,7 +69,7 @@ int make_entry(const char *blog_dir, char *script_name, char *path_info, struct // set title (PATH_INFO without the slash) if(path_info_len < 2) { // shouldn't be called with just "/" - return 500; + return STERNENBLOG_ERROR_UNEXPECTED; } // title length is exactly path_info_len (-1 for slash, +1 for null byte) @@ -97,7 +95,7 @@ int make_entry(const char *blog_dir, char *script_name, char *path_info, struct memset(&file_info, 0, sizeof(struct stat)); if(stat(entry->path, &file_info) == -1) { - return http_errno(errno); + return error_from_errno(); } int regular_file = (file_info.st_mode & S_IFMT) == S_IFREG; @@ -112,9 +110,9 @@ int make_entry(const char *blog_dir, char *script_name, char *path_info, struct } if(!access) { - return http_errno(EACCES); + return STERNENBLOG_ERROR_FORBIDDEN; } else if(!regular_file) { - return http_errno(ENOENT); + return STERNENBLOG_ERROR_NOT_FOUND; } // use POSIX compatible version, since we don't need nanoseconds @@ -123,7 +121,7 @@ int make_entry(const char *blog_dir, char *script_name, char *path_info, struct // build the link using SCRIPT_NAME if(script_name == NULL) { fprintf(stderr, "Missing SCRIPT_NAME\n"); - return 500; + return STERNENBLOG_ERROR_CGI; } // don't check SCRIPT_NAME validity, since we @@ -143,51 +141,54 @@ int make_entry(const char *blog_dir, char *script_name, char *path_info, struct entry->link[link_size - 1] = '\0'; if(urlencode_realloc(&entry->link, link_size) <= 0) { - return 500; + return STERNENBLOG_ERROR_SYSTEM; } - return 200; + return STERNENBLOG_OK; } int entry_get_text(struct entry *entry) { - // TODO set errno correctly in all cases if(entry->text != NULL) { // nothing to do - return 0; + return STERNENBLOG_OK; } int fd = open(entry->path, O_RDONLY); if(fd == -1) { - return -1; + return error_from_errno(); } struct stat file_info; if(fstat(fd, &file_info) == -1) { - return -1; + return error_from_errno(); } if(file_info.st_size == 0) { close(fd); - return 0; + return STERNENBLOG_OK; } entry->text = mmap(NULL, file_info.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if(entry->text == MAP_FAILED) { + int old_errno = errno; + entry->text = NULL; close(fd); - return -1; + + errno = old_errno; + return STERNENBLOG_ERROR_SYSTEM; } entry->text_size = file_info.st_size; if(close(fd) == -1) { - return -1; + return STERNENBLOG_ERROR_SYSTEM; } - return 0; + return STERNENBLOG_OK; } void entry_unget_text(struct entry *entry) { diff --git a/error.c b/error.c new file mode 100644 index 0000000..1f51455 --- /dev/null +++ b/error.c @@ -0,0 +1,32 @@ +#include <errno.h> +#include "error.h" + +int error_http_status(enum sternenblog_error err) { + switch(err) { + case STERNENBLOG_OK: + return 200; + case STERNENBLOG_ERROR_NOT_FOUND: + return 404; + case STERNENBLOG_ERROR_FORBIDDEN: + return 403; + case STERNENBLOG_ERROR_REQUEST: + return 400; + case STERNENBLOG_ERROR_SYSTEM: + case STERNENBLOG_ERROR_CGI: + case STERNENBLOG_ERROR_UNEXPECTED: + default: + return 500; + } +} + +int error_from_errno(void) { + switch(errno) { + case EPERM: + case EACCES: + return STERNENBLOG_ERROR_FORBIDDEN; + case ENOENT: + return STERNENBLOG_ERROR_NOT_FOUND; + default: + return STERNENBLOG_ERROR_SYSTEM; + } +} diff --git a/error.h b/error.h new file mode 100644 index 0000000..2128eea --- /dev/null +++ b/error.h @@ -0,0 +1,26 @@ +#ifndef STERNENBLOG_ERROR_H +#define STERNENBLOG_ERROR_H + +enum sternenblog_error { + //! No error + STERNENBLOG_OK = 0, + //! libc call returned error, check `errno` for details + STERNENBLOG_ERROR_SYSTEM = -1, + //! requested item doesn't exist + STERNENBLOG_ERROR_NOT_FOUND = -2, + //! access to the requested item isn't allowed (either by system or us) + STERNENBLOG_ERROR_FORBIDDEN = -3, + //! CGI environment is not correctly set up + STERNENBLOG_ERROR_CGI = -4, + //! User send a request that doesn't make sense to us + STERNENBLOG_ERROR_REQUEST = -5, + //! The unexpected happened like an assumption not holding. + //! If this error is generated it is likely a bug + STERNENBLOG_ERROR_UNEXPECTED = -6, +}; + +int error_http_status(enum sternenblog_error err); + +int error_from_errno(void); + +#endif diff --git a/index.c b/index.c index 9cf673e..144f80a 100644 --- a/index.c +++ b/index.c @@ -6,6 +6,7 @@ #include <string.h> #include <sys/types.h> +#include "error.h" #include "index.h" /*! @@ -36,11 +37,11 @@ int entries_timesort_r(struct entry *a, struct entry *b) { int make_index(const char *blog_dir, char *script_name, bool get_text, struct entry *entries[]) { if(*entries != NULL) { - return -1; + return STERNENBLOG_ERROR_UNEXPECTED; } if(script_name == NULL) { - return -1; + return STERNENBLOG_ERROR_CGI; } size_t index_count = 0; @@ -49,7 +50,7 @@ int make_index(const char *blog_dir, char *script_name, bool get_text, struct en dir = opendir(blog_dir); if(dir == NULL) { - return -1; + return error_from_errno(); } struct dirent *ent; @@ -58,7 +59,7 @@ int make_index(const char *blog_dir, char *script_name, bool get_text, struct en *entries = malloc(sizeof(struct entry) * size); if(*entries == NULL) { - return -1; + return STERNENBLOG_ERROR_SYSTEM; } // losely based on musl's scandir(3) @@ -79,7 +80,7 @@ int make_index(const char *blog_dir, char *script_name, bool get_text, struct en int result = make_entry(blog_dir, script_name, path_info, &tmp_entry); - if(result == 200) { + if(result == STERNENBLOG_OK) { // increase array size if necessary if(index_count >= size) { size += BASE_INDEX_SIZE; diff --git a/main.c b/main.c index d7a9987..0aec826 100644 --- a/main.c +++ b/main.c @@ -86,6 +86,7 @@ #include <time.h> #include <unistd.h> +#include "error.h" #include "config.h" #include "cgiutil.h" #include "entry.h" @@ -127,7 +128,7 @@ int main(void) { struct entry *entries = NULL; int count = 0; - int status = 500; + int status = STERNENBLOG_ERROR_UNEXPECTED; // Routing: determine page_type // already allocate data for single entries @@ -147,24 +148,24 @@ int main(void) { // populate data necessary for responses or switch to error page type if(page_type == PAGE_TYPE_INDEX || page_type == PAGE_TYPE_FEED) { - count = make_index(BLOG_DIR, script_name, 0, &entries); + status = make_index(BLOG_DIR, script_name, 0, &entries); - if(count < 0) { - page_type = PAGE_TYPE_ERROR; - status = 500; + if(status > 0) { + count = status; + status = STERNENBLOG_OK; } else { - status = 200; + page_type = PAGE_TYPE_ERROR; } } else { // single entry is just a special index entries = malloc(sizeof(struct entry)); if(entries == NULL) { - status = 500; + status = STERNENBLOG_ERROR_SYSTEM; } else { status = make_entry(BLOG_DIR, script_name, path_info, entries); } - if(status == 200 && entry_get_text(entries) != -1) { + if(status == STERNENBLOG_OK && (status = entry_get_text(entries)) == STERNENBLOG_OK) { count = 1; } else { page_type = PAGE_TYPE_ERROR; @@ -172,13 +173,13 @@ int main(void) { } // confirm status and page_type match - assert(status == 200 || page_type == PAGE_TYPE_ERROR); - assert(page_type != PAGE_TYPE_ERROR || status != 200); + assert(status == STERNENBLOG_OK || page_type == PAGE_TYPE_ERROR); + assert(page_type != PAGE_TYPE_ERROR || status != STERNENBLOG_OK); // initial contents of data, changed in loop for PAGE_TYPE_INDEX struct template_data data; data.page_type = page_type; - data.status = status; + data.status = error_http_status(status); data.script_name = script_name; if(path_info == NULL) { data.path_info = ""; @@ -201,7 +202,7 @@ int main(void) { // render response switch(page_type) { case PAGE_TYPE_ERROR: - send_standard_headers(status, "text/html"); + send_standard_headers(error_http_status(status), "text/html"); template_header(data); template_main(data); |