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);