Added the ability to throw an error

This commit is contained in:
Nate Choe
2022-02-10 09:30:54 -06:00
parent 8ae835510e
commit e5967f7ead
10 changed files with 56 additions and 28 deletions

View File

@@ -15,6 +15,7 @@ sitefiles also allow comments with #
* ```define [variable] [value]``` - sets some global variable * ```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. * ```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. * ```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. ##### Other than set, commands should take in a regex as argument 1 and operate on a file specified in argument 2.

View File

@@ -4,3 +4,4 @@
<a href="blog/2022-1-25.html">2021-1-25</a> <a href="blog/2022-1-25.html">2021-1-25</a>
<a href="blog/2022-1-31">2021-1-31</a> <a href="blog/2022-1-31">2021-1-31</a>
<a href="blog/forbidden">The forbidden blog post</a>

View File

@@ -6,6 +6,7 @@ define timeout 2000
set host localhost:8000 set host localhost:8000
read / site/index.html read / site/index.html
read /hello site/hello.html read /hello site/hello.html
throw /blog/forbidden 403
exec /blog/2022-1-31 site/blog/blog/2022-1-31.sh exec /blog/2022-1-31 site/blog/blog/2022-1-31.sh
read /blog/.* site/blog/ read /blog/.* site/blog/
#/blog/2021-1-25.html turns into site/blog//blog/2021-1-25.html #/blog/2021-1-25.html turns into site/blog//blog/2021-1-25.html

View File

@@ -25,9 +25,11 @@
#define ERROR_404 "404 Not Found" #define ERROR_404 "404 Not Found"
#define ERROR_500 "500 Internal Server Error" #define ERROR_500 "500 Internal Server Error"
int sendStringResponse(Connection *conn, char *status, char *str); char *getCode(int code);
int sendBinaryResponse(Connection *conn, char *status, void *data, size_t len); int sendStringResponse(Connection *conn, const char *status, char *str);
int sendErrorResponse(Connection *conn, char *error); int sendBinaryResponse(Connection *conn, const char *status,
void *data, size_t len);
int sendErrorResponse(Connection *conn, const char *error);
//sendErrorResponse(conn, ERROR_404); //sendErrorResponse(conn, ERROR_404);
int sendHeader(Connection *conn, char *status, size_t len); int sendHeader(Connection *conn, const char *status, size_t len);
#endif #endif

View File

@@ -24,6 +24,7 @@
typedef enum { typedef enum {
READ, READ,
EXEC, EXEC,
THROW,
} Command; } Command;
typedef struct { typedef struct {

View File

@@ -50,7 +50,7 @@ Stream *acceptStream(Listener *listener, int flags);
void freeListener(Listener *listener); void freeListener(Listener *listener);
void freeStream(Stream *stream); 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); ssize_t recvStream(Stream *stream, void *data, size_t len);
//return value is the same as the read and write syscalls. //return value is the same as the read and write syscalls.
#endif #endif

View File

@@ -30,14 +30,16 @@
#include <responses.h> #include <responses.h>
#include <responseutil.h> #include <responseutil.h>
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. //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) { while (len > 0) {
ssize_t sent = sendStream(stream, buff, len); ssize_t sent = sendStream(stream, data, len);
if (sent < 0) if (sent < 0)
return 1; return 1;
len -= sent; len -= sent;
buff += sent; data += sent;
} }
return 0; return 0;
} }
@@ -142,7 +144,8 @@ static int execResponse(Connection *conn, char *path) {
close(1); close(1);
close(output[0]); close(output[0]);
dup2(output[1], 1); 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) { if (args == NULL) {
close(output[1]); close(output[1]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@@ -239,6 +242,10 @@ int sendResponse(Connection *conn, Sitefile *site) {
execResponse(conn, execResponse(conn,
site->content[i].arg); site->content[i].arg);
break; break;
case THROW:
sendErrorResponse(conn,
site->content[i].arg);
break;
default: default:
sendErrorResponse(conn, ERROR_500); sendErrorResponse(conn, ERROR_500);
return 1; return 1;

View File

@@ -48,7 +48,24 @@ static int sendConnection(Connection *conn, char *format, ...) {
return 0; 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, return sendConnection(conn,
"HTTP/1.1 %s\r\n" "HTTP/1.1 %s\r\n"
CONST_FIELDS 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 = const char *template =
"<meta charset=utf-8>" "<meta charset=utf-8>"
"<h1 text-align=center>" "<h1 text-align=center>"
@@ -73,7 +90,7 @@ int sendErrorResponse(Connection *conn, char *error) {
return ret; return ret;
} }
int sendBinaryResponse(Connection *conn, char *status, int sendBinaryResponse(Connection *conn, const char *status,
void *data, size_t len) { void *data, size_t len) {
if (sendConnection(conn, if (sendConnection(conn,
"HTTP/1.1 %s\r\n" "HTTP/1.1 %s\r\n"
@@ -86,7 +103,7 @@ int sendBinaryResponse(Connection *conn, char *status,
return sendStream(conn->stream, data, len) < len; 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, return (sendConnection(conn,
"HTTP/1.1 %s\r\n" "HTTP/1.1 %s\r\n"
CONST_FIELDS CONST_FIELDS

View File

@@ -22,6 +22,7 @@
#include <util.h> #include <util.h>
#include <sitefile.h> #include <sitefile.h>
#include <responseutil.h>
typedef enum { typedef enum {
SUCCESS, SUCCESS,
@@ -156,15 +157,6 @@ error:
return 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) { Sitefile *parseSitefile(char *path) {
FILE *file = fopen(path, "r"); FILE *file = fopen(path, "r");
if (file == NULL) if (file == NULL)
@@ -211,7 +203,7 @@ Sitefile *parseSitefile(char *path) {
else if (strcmp(argv[1], "host") == 0) { else if (strcmp(argv[1], "host") == 0) {
if (ret->size == lasthostset) if (ret->size == lasthostset)
free(host); free(host);
host = copyString(argv[2]); host = strdup(argv[2]);
lasthostset = ret->size; lasthostset = ret->size;
} }
else else
@@ -230,9 +222,9 @@ Sitefile *parseSitefile(char *path) {
goto error; goto error;
} }
else if (strcmp(argv[1], "key") == 0) else if (strcmp(argv[1], "key") == 0)
ret->key = copyString(argv[2]); ret->key = strdup(argv[2]);
else if (strcmp(argv[1], "cert") == 0) else if (strcmp(argv[1], "cert") == 0)
ret->cert = copyString(argv[2]); ret->cert = strdup(argv[2]);
else if (strcmp(argv[1], "timeout") == 0) else if (strcmp(argv[1], "timeout") == 0)
ret->timeout = atoi(argv[2]); ret->timeout = atoi(argv[2]);
else else
@@ -255,17 +247,23 @@ Sitefile *parseSitefile(char *path) {
goto error; goto error;
if (strcmp(argv[0], "read") == 0) { 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) if (ret->content[ret->size].arg == NULL)
goto error; goto error;
ret->content[ret->size].command = READ; ret->content[ret->size].command = READ;
} }
else if (strcmp(argv[0], "exec") == 0) { 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) if (ret->content[ret->size].arg == NULL)
goto error; goto error;
ret->content[ret->size].command = EXEC; 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 else
goto error; goto error;
freeTokens(argc, argv); freeTokens(argc, argv);

View File

@@ -154,7 +154,7 @@ void freeStream(Stream *stream) {
free(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) { switch (stream->type) {
case TCP: case TCP:
return write(stream->fd, data, len); return write(stream->fd, data, len);