From e5967f7ead9859f86008e99fde4e380dd8e5d66f Mon Sep 17 00:00:00 2001 From: Nate Choe Date: Thu, 10 Feb 2022 09:30:54 -0600 Subject: [PATCH] Added the ability to throw an error --- documentation/sitefiles.md | 1 + example/site/index.html | 1 + example/sitefile | 1 + src/include/responseutil.h | 10 ++++++---- src/include/sitefile.h | 1 + src/include/sockets.h | 2 +- src/responses.c | 15 +++++++++++---- src/responseutil.c | 25 +++++++++++++++++++++---- src/sitefile.c | 26 ++++++++++++-------------- src/sockets.c | 2 +- 10 files changed, 56 insertions(+), 28 deletions(-) diff --git a/documentation/sitefiles.md b/documentation/sitefiles.md index 9ff2739..d231b4a 100644 --- a/documentation/sitefiles.md +++ b/documentation/sitefiles.md @@ -15,6 +15,7 @@ sitefiles also allow comments with # * ```define [variable] [value]``` - sets some global variable * ```read [http path] [file path]``` - if the requested path matches ```[http path]```, return the contents of ```[file path]```. If [file path] is a directory, then the http path is appended to [file path] and that is read instead. * ```exec [http path] [file path]``` - if the requested path matches ```[http path]```, execute ```[file path]``` and send the the contents of stdout. ```argv[0]``` is the ```[file path]```, ```argv[1]``` is a header, ```argv[2]``` is the value for that header, ```argv[3]``` is the next header, and so on. +* ```throw [http path] [error code]``` - If the requested path matches ```[http path]```, send back the http error code ```[error code]```. For standardization purposes, these error codes are just the number. ##### Other than set, commands should take in a regex as argument 1 and operate on a file specified in argument 2. diff --git a/example/site/index.html b/example/site/index.html index 0ff4c5f..ed0818e 100644 --- a/example/site/index.html +++ b/example/site/index.html @@ -4,3 +4,4 @@ 2021-1-25 2021-1-31 +The forbidden blog post diff --git a/example/sitefile b/example/sitefile index da9fcf3..c707a5f 100644 --- a/example/sitefile +++ b/example/sitefile @@ -6,6 +6,7 @@ define timeout 2000 set host localhost:8000 read / site/index.html read /hello site/hello.html +throw /blog/forbidden 403 exec /blog/2022-1-31 site/blog/blog/2022-1-31.sh read /blog/.* site/blog/ #/blog/2021-1-25.html turns into site/blog//blog/2021-1-25.html diff --git a/src/include/responseutil.h b/src/include/responseutil.h index c898315..5f2d8dc 100644 --- a/src/include/responseutil.h +++ b/src/include/responseutil.h @@ -25,9 +25,11 @@ #define ERROR_404 "404 Not Found" #define ERROR_500 "500 Internal Server Error" -int sendStringResponse(Connection *conn, char *status, char *str); -int sendBinaryResponse(Connection *conn, char *status, void *data, size_t len); -int sendErrorResponse(Connection *conn, char *error); +char *getCode(int code); +int sendStringResponse(Connection *conn, const char *status, char *str); +int sendBinaryResponse(Connection *conn, const char *status, + void *data, size_t len); +int sendErrorResponse(Connection *conn, const char *error); //sendErrorResponse(conn, ERROR_404); -int sendHeader(Connection *conn, char *status, size_t len); +int sendHeader(Connection *conn, const char *status, size_t len); #endif diff --git a/src/include/sitefile.h b/src/include/sitefile.h index 3b4f4d6..5f5eb0a 100644 --- a/src/include/sitefile.h +++ b/src/include/sitefile.h @@ -24,6 +24,7 @@ typedef enum { READ, EXEC, + THROW, } Command; typedef struct { diff --git a/src/include/sockets.h b/src/include/sockets.h index 942ce05..0fbc34b 100644 --- a/src/include/sockets.h +++ b/src/include/sockets.h @@ -50,7 +50,7 @@ Stream *acceptStream(Listener *listener, int flags); void freeListener(Listener *listener); void freeStream(Stream *stream); -ssize_t sendStream(Stream *stream, void *data, size_t len); +ssize_t sendStream(Stream *stream, const void *data, size_t len); ssize_t recvStream(Stream *stream, void *data, size_t len); //return value is the same as the read and write syscalls. #endif diff --git a/src/responses.c b/src/responses.c index 02af4f5..d6845a8 100644 --- a/src/responses.c +++ b/src/responses.c @@ -30,14 +30,16 @@ #include #include -static int resilientSend(Stream *stream, char *buff, size_t len) { +static int resilientSend(Stream *stream, const void *buff, size_t len) { //Will either write len bytes, or return 1 for error. + const char *data = (const char *) buff; + //using character pointers to do pointer arithmetic while (len > 0) { - ssize_t sent = sendStream(stream, buff, len); + ssize_t sent = sendStream(stream, data, len); if (sent < 0) return 1; len -= sent; - buff += sent; + data += sent; } return 0; } @@ -142,7 +144,8 @@ static int execResponse(Connection *conn, char *path) { close(1); close(output[0]); dup2(output[1], 1); - char **args = malloc((conn->fieldCount*2 + 2) * sizeof(char *)); + char **args = + malloc((conn->fieldCount*2 + 2) * sizeof(char *)); if (args == NULL) { close(output[1]); exit(EXIT_FAILURE); @@ -239,6 +242,10 @@ int sendResponse(Connection *conn, Sitefile *site) { execResponse(conn, site->content[i].arg); break; + case THROW: + sendErrorResponse(conn, + site->content[i].arg); + break; default: sendErrorResponse(conn, ERROR_500); return 1; diff --git a/src/responseutil.c b/src/responseutil.c index 4efb38b..5733eb1 100644 --- a/src/responseutil.c +++ b/src/responseutil.c @@ -48,7 +48,24 @@ static int sendConnection(Connection *conn, char *format, ...) { return 0; } -int sendStringResponse(Connection *conn, char *status, char *str) { +char *getCode(int code) { + switch (code) { + case 200: + return strdup(CODE_200); + case 400: + return strdup(ERROR_400); + case 403: + return strdup(ERROR_403); + case 404: + return strdup(ERROR_404); + case 500: + return strdup(ERROR_500); + default: + return NULL; + } +} + +int sendStringResponse(Connection *conn, const char *status, char *str) { return sendConnection(conn, "HTTP/1.1 %s\r\n" CONST_FIELDS @@ -59,7 +76,7 @@ int sendStringResponse(Connection *conn, char *status, char *str) { ); } -int sendErrorResponse(Connection *conn, char *error) { +int sendErrorResponse(Connection *conn, const char *error) { const char *template = "" "

" @@ -73,7 +90,7 @@ int sendErrorResponse(Connection *conn, char *error) { return ret; } -int sendBinaryResponse(Connection *conn, char *status, +int sendBinaryResponse(Connection *conn, const char *status, void *data, size_t len) { if (sendConnection(conn, "HTTP/1.1 %s\r\n" @@ -86,7 +103,7 @@ int sendBinaryResponse(Connection *conn, char *status, return sendStream(conn->stream, data, len) < len; } -int sendHeader(Connection *conn, char *status, size_t len) { +int sendHeader(Connection *conn, const char *status, size_t len) { return (sendConnection(conn, "HTTP/1.1 %s\r\n" CONST_FIELDS diff --git a/src/sitefile.c b/src/sitefile.c index 300f3dc..218dfd8 100644 --- a/src/sitefile.c +++ b/src/sitefile.c @@ -22,6 +22,7 @@ #include #include +#include typedef enum { SUCCESS, @@ -156,15 +157,6 @@ error: return ERROR; } -static char *copyString(char *str) { - size_t len = strlen(str); - char *ret = malloc(len + 1); - if (ret == NULL) - return NULL; - memcpy(ret, str, len + 1); - return ret; -} - Sitefile *parseSitefile(char *path) { FILE *file = fopen(path, "r"); if (file == NULL) @@ -211,7 +203,7 @@ Sitefile *parseSitefile(char *path) { else if (strcmp(argv[1], "host") == 0) { if (ret->size == lasthostset) free(host); - host = copyString(argv[2]); + host = strdup(argv[2]); lasthostset = ret->size; } else @@ -230,9 +222,9 @@ Sitefile *parseSitefile(char *path) { goto error; } else if (strcmp(argv[1], "key") == 0) - ret->key = copyString(argv[2]); + ret->key = strdup(argv[2]); else if (strcmp(argv[1], "cert") == 0) - ret->cert = copyString(argv[2]); + ret->cert = strdup(argv[2]); else if (strcmp(argv[1], "timeout") == 0) ret->timeout = atoi(argv[2]); else @@ -255,17 +247,23 @@ Sitefile *parseSitefile(char *path) { goto error; if (strcmp(argv[0], "read") == 0) { - ret->content[ret->size].arg = copyString(argv[2]); + ret->content[ret->size].arg = strdup(argv[2]); if (ret->content[ret->size].arg == NULL) goto error; ret->content[ret->size].command = READ; } else if (strcmp(argv[0], "exec") == 0) { - ret->content[ret->size].arg = copyString(argv[2]); + ret->content[ret->size].arg = strdup(argv[2]); if (ret->content[ret->size].arg == NULL) goto error; ret->content[ret->size].command = EXEC; } + else if (strcmp(argv[0], "throw") == 0) { + ret->content[ret->size].arg = getCode(atoi(argv[2])); + if (ret->content[ret->size].arg == NULL) + goto error; + ret->content[ret->size].command = THROW; + } else goto error; freeTokens(argc, argv); diff --git a/src/sockets.c b/src/sockets.c index 84b8f02..24ae6fd 100644 --- a/src/sockets.c +++ b/src/sockets.c @@ -154,7 +154,7 @@ void freeStream(Stream *stream) { free(stream); } -ssize_t sendStream(Stream *stream, void *data, size_t len) { +ssize_t sendStream(Stream *stream, const void *data, size_t len) { switch (stream->type) { case TCP: return write(stream->fd, data, len);