From be8e081cca8f5bcd31ad9ef1ce2a728a82769791 Mon Sep 17 00:00:00 2001 From: Nate Choe Date: Sat, 22 Jan 2022 21:20:57 -0600 Subject: [PATCH] Implemented regex and directories --- documentation/sitefiles.md | 2 +- src/include/sitefile.h | 4 +- src/responses.c | 78 ++++++++++++++++++++++++++++++-------- src/sitefile.c | 6 +-- 4 files changed, 69 insertions(+), 21 deletions(-) diff --git a/documentation/sitefiles.md b/documentation/sitefiles.md index 371e410..bc9e777 100644 --- a/documentation/sitefiles.md +++ b/documentation/sitefiles.md @@ -12,7 +12,7 @@ sitefiles also allow comments with # # Part 2: Commands * ```set [variable] [value]``` - sets some variable for the following pages -* ```read [http path] [file path]``` - if the requested path matches ```[http path]```, return the contents of ```[file path]``` +* ```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. ##### Other than set, commands should take in a regex as argument 1 and operate on a file specified in argument 2. diff --git a/src/include/sitefile.h b/src/include/sitefile.h index db8fcf7..9adc50f 100644 --- a/src/include/sitefile.h +++ b/src/include/sitefile.h @@ -17,6 +17,8 @@ */ #ifndef _HAVE_SITEFILE #define _HAVE_SITEFILE +#include + #include typedef enum { @@ -26,7 +28,7 @@ typedef enum { typedef struct { RequestType respondto; Command command; - char *path; + regex_t path; char *arg; } SiteCommand; diff --git a/src/responses.c b/src/responses.c index 51c38e0..0a415b7 100644 --- a/src/responses.c +++ b/src/responses.c @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include @@ -35,23 +37,51 @@ static int sendConnection(Connection *conn, char *format, ...) { va_start(ap, format); vsnprintf(data, len + 1, format, ap); - write(conn->fd, data, len); + if (write(conn->fd, data, len) < len) { + free(data); + return 1; + } free(data); return 0; } static void readResponse(Connection *conn, char *path) { - FILE *file = fopen(path, "r"); - if (file == NULL) { - sendConnection(conn, - "HTTP/1.1 403 Forbidden\r\n" - "Content-Type: text/html; charset=UTF-8\r\n" - "Server: swebs/0.1\r\n" - "Content-Length: 21\r\n" - "\r\n" - "

Invalid page

\n" - ); + FILE *file; + struct stat statbuf; + if (stat(path, &statbuf)) return; + if (S_ISDIR(statbuf.st_mode)) { + long reqPathLen = strlen(conn->path); + long pathLen = strlen(path); + char *assembledPath = malloc(reqPathLen + pathLen + 1); + if (assembledPath == NULL) + return; + memcpy(assembledPath, path, pathLen); + memcpy(assembledPath + pathLen, conn->path, reqPathLen + 1); + + char requestPath[PATH_MAX]; + if (realpath(assembledPath, requestPath) == NULL) { + free(assembledPath); + return; + } + char responsePath[PATH_MAX]; + if (realpath(path, responsePath) == NULL) { + free(assembledPath); + return; + } + size_t responsePathLen = strlen(responsePath); + if (memcmp(requestPath, responsePath, responsePathLen)) { + free(assembledPath); + goto forbidden; + } + + file = fopen(requestPath, "r"); + free(assembledPath); + } + else + file = fopen(path, "r"); + if (file == NULL) { + goto forbidden; } fseek(file, 0, SEEK_END); long len = ftell(file); @@ -59,7 +89,8 @@ static void readResponse(Connection *conn, char *path) { if (data == NULL) return; fseek(file, 0, SEEK_SET); - fread(data, 1, len, file); + if (fread(data, 1, len, file) < len) + goto error; fclose(file); sendConnection(conn, "HTTP/1.1 200 OK\r\n" @@ -67,18 +98,33 @@ static void readResponse(Connection *conn, char *path) { "Content-Length: %ld\r\n" "\r\n", len ); - write(conn->fd, data, len); + if (write(conn->fd, data, len) < len) + goto error; free(data); fsync(conn->fd); + return; +error: + fclose(file); + return; +forbidden: + sendConnection(conn, + "HTTP/1.1 403 Forbidden\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Server: swebs/0.1\r\n" + "Content-Length: 21\r\n" + "\r\n" + "

Invalid page

\n" + ); + return; } int sendResponse(Connection *conn, Sitefile *site) { - if (conn->path == NULL) - return 1; + puts(conn->path); for (int i = 0; i < site->size; i++) { if (site->content[i].respondto != conn->type) continue; - if (strcmp(conn->path, site->content[i].path) == 0) { + if (regexec(&site->content[i].path, conn->path, 0, NULL, 0) + == 0) { switch (site->content[i].command) { case READ: readResponse(conn, site->content[i].arg); diff --git a/src/sitefile.c b/src/sitefile.c index 1248cf9..a0b531b 100644 --- a/src/sitefile.c +++ b/src/sitefile.c @@ -216,8 +216,8 @@ Sitefile *parseFile(char *path) { if (argc < 3) goto error; - ret->content[ret->size].path = copyString(argv[1]); - if (ret->content[ret->size].path == NULL) + if (regcomp(&ret->content[ret->size].path, argv[1], + REG_EXTENDED | REG_NOSUB)) goto error; if (strcmp(argv[0], "read") == 0) { @@ -239,7 +239,7 @@ nterror: void freeSitefile(Sitefile *site) { for (long i = 0; i < site->size; i++) { - free(site->content[i].path); + regfree(&site->content[i].path); free(site->content[i].arg); } free(site->content);