diff --git a/documentation/dynamicpages.md b/documentation/dynamicpages.md index 4f7dbab..654ad82 100644 --- a/documentation/dynamicpages.md +++ b/documentation/dynamicpages.md @@ -38,10 +38,30 @@ typedef enum { * */ } RequestType; +typedef struct { + char *data; + /* data is guarunteed to be NULL terminated, although not necessarily + * once. */ + size_t len; + size_t allocatedLen; + /* The amount of bytes allocated, for internal use. */ +} BinaryString; + +typedef struct { + BinaryString var; + BinaryString value; +} PathField; + +typedef struct { + BinaryString path; + long fieldCount; + PathField *fields; +} Path; + typedef struct { long fieldCount; Field *fields; - char *path; + Path path; RequestType type; } Request; /*HTTP request, pretty self explanatory*/ diff --git a/documentation/sitefiles.md b/documentation/sitefiles.md index 504df27..2d0e4d7 100644 --- a/documentation/sitefiles.md +++ b/documentation/sitefiles.md @@ -14,7 +14,6 @@ sitefiles also allow comments with # * ```set [variable] [value]``` - sets some local variable for the following pages * ```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 requested path, ```argv[1]``` is a header, ```argv[2]``` is the value for that header, ```argv[3]``` is the next header, and so on. * ```linked``` - Run getResponse() from the library loaded from the library global variable * ```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. diff --git a/example/library.c b/example/library.c index f4e697a..69834f1 100644 --- a/example/library.c +++ b/example/library.c @@ -5,7 +5,10 @@ #include int getResponse(Request *request, Response *response) { - char *str = request->path; + printf("%d\n", request->path.fieldCount); + for (int i = 0; i < request->path.fieldCount; i++) + printf("%s: %s\n", request->path.fields[i].var.data, request->path.fields[i].value.data); + char *str = request->path.path.data; response->type = BUFFER; response->response.buffer.data = malloc(100); strcpy(response->response.buffer.data, str); diff --git a/example/site/blog/blog/2022-1-31.sh b/example/site/blog/blog/2022-1-31.sh deleted file mode 100755 index 8536551..0000000 --- a/example/site/blog/blog/2022-1-31.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -echo "

By the way today's date is $(date)

" diff --git a/example/site/index.html b/example/site/index.html index ed0818e..f741b18 100644 --- a/example/site/index.html +++ b/example/site/index.html @@ -3,5 +3,4 @@

It's not very polished but it's certainly a website

2021-1-25 -2021-1-31 The forbidden blog post diff --git a/example/sitefile b/example/sitefile index 3a63b61..d8d93b2 100644 --- a/example/sitefile +++ b/example/sitefile @@ -10,7 +10,6 @@ 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 linked /library diff --git a/src/connections.c b/src/connections.c index 5be58d0..5f05004 100644 --- a/src/connections.c +++ b/src/connections.c @@ -16,6 +16,7 @@ along with this program. If not, see . */ #include +#include #include #include #include @@ -45,7 +46,15 @@ int newConnection(Stream *stream, Connection *ret) { return 1; } - ret->path = NULL; + ret->allocatedPathFields = 10; + ret->pathFields = malloc(ret->allocatedPathFields * sizeof(PathField)); + if (ret->pathFields == NULL) { + free(ret->currLine); + free(ret->fields); + return 1; + } + ret->pathFieldCount = 0; + ret->body = NULL; /* * pointers to things that are allocated within functions should be @@ -54,6 +63,8 @@ int newConnection(Stream *stream, Connection *ret) { if (clock_gettime(CLOCK_MONOTONIC, ¤tTime) < 0) { free(ret->currLine); + free(ret->fields); + free(ret->pathFields); return 1; } memcpy(&ret->lastdata, ¤tTime, sizeof(struct timespec)); @@ -61,20 +72,146 @@ int newConnection(Stream *stream, Connection *ret) { } void resetConnection(Connection *conn) { + long i; conn->progress = RECEIVE_REQUEST; conn->fieldCount = 0; free(conn->body); - free(conn->path); conn->body = NULL; - conn->path = NULL; + conn->pathFieldCount = 0; + for (i = 0; i < conn->pathFieldCount; i++) { + free(conn->pathFields[i].var.data); + free(conn->pathFields[i].value.data); + } } void freeConnection(Connection *conn) { + long i; freeStream(conn->stream); free(conn->currLine); - free(conn->path); free(conn->fields); free(conn->body); + for (i = 0; i < conn->fieldCount; i++) { + free(conn->pathFields[i].var.data); + free(conn->pathFields[i].value.data); + } + free(conn->pathFields); +} + +static int createBinaryString(BinaryString *ret) { + ret->allocatedLen = 50; + ret->data = malloc(ret->allocatedLen); + if (ret->data == NULL) + return 1; + ret->len = 0; + return 0; +} + +static int appendBinaryString(BinaryString *ret, char c) { + if (ret->len >= ret->allocatedLen) { + char *newdata; + ret->allocatedLen *= 2; + newdata = realloc(ret->data, ret->allocatedLen); + if (newdata == NULL) { + free(ret->data); + return 1; + } + ret->data = newdata; + } + ret->data[ret->len++] = c; + return 0; +} + +static int hexval(char c) { + if (isdigit(c)) + return c - '0'; + if ('a' <= c && c <= 'f') + return c - 'a' + 10; + if ('A' <= c && c <= 'F') + return c - 'A' + 10; + return -1; +} + +static int getBinaryString(BinaryString *ret, char *path, char stop, + long *lenReturn) { + long i; + createBinaryString(ret); + for (i = 0; path[i] != stop && path[i] != '\0'; i++) { + char c; + if (path[i] == '%') { + int v; + v = hexval(path[i + 1]); + if (v < 0) { + free(ret->data); + return 1; + } + c = v << 4; + v = hexval(path[i + 2]); + if (v < 0) { + free(ret->data); + return 1; + } + c |= v; + i += 2; + } + else + c = path[i]; + appendBinaryString(ret, c); + } + appendBinaryString(ret, '\0'); + *lenReturn = i; + return 0; +} + +static int processPath(Connection *conn, char *path) { + long len; + if (getBinaryString(&conn->path, path, '?', &len)) + return 1; + path += len; + while (path[0] != '\0') { + if (conn->pathFieldCount >= conn->allocatedPathFields) { + PathField *newPathFields; + + conn->allocatedPathFields *= 2; + newPathFields = realloc(conn->pathFields, + conn->allocatedPathFields * + sizeof(PathField)); + if (newPathFields == NULL) + goto error; + conn->pathFields = newPathFields; + } + + path++; + if (getBinaryString( + &conn->pathFields[conn->pathFieldCount].var, + path, '=', &len)) + goto error; + path += len; + if (path[0] == '\0') { + free(conn->pathFields[conn->pathFieldCount].var.data); + goto error; + } + path++; + if (getBinaryString( + &conn->pathFields[conn->pathFieldCount].value, + path, '&', &len)) { + free(conn->pathFields[conn->pathFieldCount].var.data); + goto error; + } + conn->pathFieldCount++; + path += len; + } + return 0; +error: + { + long i; + for (i = 0; i < conn->fieldCount; i++) { + free(conn->pathFields[i].var.data); + free(conn->pathFields[i].value.data); + } + free(conn->pathFields); + free(conn->path.data); + return 1; + } } static int processRequest(Connection *conn) { @@ -102,10 +239,8 @@ static int processRequest(Connection *conn) { for (i = 0;; i++) { if (line[i] == ' ') { line[i] = '\0'; - conn->path = malloc(i + 1); - if (conn->path == NULL) + if (processPath(conn, line)) return 1; - memcpy(conn->path, line, i + 1); line += i + 1; break; } @@ -231,14 +366,8 @@ int updateConnection(Connection *conn, Sitefile *site) { diff(&conn->lastdata, ¤tTime) > site->timeout) return 1; received = recvStream(conn->stream, buff, sizeof(buff)); - if (received < 0) { - char log[200]; - sprintf(log, -"recvStream() returned %ld, with errno %d, received %lu bytes this iteration " -"of updateConnection", - received, errno, totalReceived); + if (received < 0) return errno != EAGAIN; - } if (received == 0) return 1; totalReceived += received; diff --git a/src/responses.c b/src/responses.c index 10b5adf..3659636 100644 --- a/src/responses.c +++ b/src/responses.c @@ -37,8 +37,8 @@ static int readResponse(Connection *conn, char *path) { return 1; } if (S_ISDIR(statbuf.st_mode)) { - long reqPathLen = strlen(conn->path); - long pathLen = strlen(path); + size_t reqPathLen = conn->path.len; + size_t pathLen = strlen(path); char *assembledPath = malloc(reqPathLen + pathLen + 1); char requestPath[PATH_MAX], responsePath[PATH_MAX]; size_t responsePathLen; @@ -46,7 +46,8 @@ static int readResponse(Connection *conn, char *path) { if (assembledPath == NULL) goto error; memcpy(assembledPath, path, pathLen); - memcpy(assembledPath + pathLen, conn->path, reqPathLen + 1); + memcpy(assembledPath + pathLen, + conn->path.data, reqPathLen + 1); if (realpath(assembledPath, requestPath) == NULL) { if (errno == ENOENT) { @@ -101,56 +102,6 @@ forbidden: return 1; } -static int execResponse(Connection *conn, char *path) { - int output[2]; - int status; - pid_t pid; - if (pipe(output)) - goto error; - - pid = fork(); - if (pid < 0) - goto error; - if (pid == 0) { - char **args; - int i; - close(1); - close(output[0]); - dup2(output[1], 1); - args = malloc((conn->fieldCount*2 + 2) * sizeof(char *)); - if (args == NULL) { - close(output[1]); - exit(EXIT_FAILURE); - } - args[0] = conn->path; - for (i = 0; i < conn->fieldCount; i++) { - args[i * 2 + 1] = conn->fields[i].field; - args[i * 2 + 2] = conn->fields[i].value; - } - args[conn->fieldCount*2 + 1] = NULL; - if (execv(path, args) < 0) { - close(output[1]); - free(args); - exit(EXIT_FAILURE); - } - close(output[1]); - free(args); - exit(EXIT_SUCCESS); - } - - close(output[1]); - - status = sendPipe(conn->stream, CODE_200, output[0]); - { - int exitcode; - waitpid(pid, &exitcode, 0); - } - return status; -error: - sendErrorResponse(conn->stream, ERROR_500); - return 1; -} - static int linkedResponse(Connection *conn, int (*getResponse)(Request *request, Response *response)) { Request request; @@ -160,7 +111,9 @@ static int linkedResponse(Connection *conn, request.fieldCount = conn->fieldCount; request.fields = conn->fields; - request.path = conn->path; + request.path.path = conn->path; + request.path.fieldCount = conn->pathFieldCount; + request.path.fields = conn->pathFields; request.type = conn->type; request.body = conn->body; request.bodylen = conn->bodylen; @@ -212,16 +165,12 @@ int sendResponse(Connection *conn, Sitefile *site) { continue; if (fullmatch(&site->content[i].host, host)) continue; - if (fullmatch(&site->content[i].path, conn->path) == 0) { + if (fullmatch(&site->content[i].path, conn->path.data) == 0) { switch (site->content[i].command) { case READ: readResponse(conn, site->content[i].arg); break; - case EXEC: - execResponse(conn, - site->content[i].arg); - break; case THROW: sendErrorResponse(conn->stream, site->content[i].arg); diff --git a/src/runner.c b/src/runner.c index 4fa4927..24bbd5a 100644 --- a/src/runner.c +++ b/src/runner.c @@ -71,12 +71,6 @@ remove: if (fds[0].revents & POLLIN) { Stream *newstream; - { - char log[200]; - sprintf(log, -"Thread %d received a connection (it now has %d connections)", - id, connCount); - } if (connCount >= allocConns) { struct pollfd *newfds; Connection *newconns; diff --git a/src/sitefile.c b/src/sitefile.c index e8d5f84..991fdfe 100644 --- a/src/sitefile.c +++ b/src/sitefile.c @@ -287,14 +287,6 @@ Sitefile *parseSitefile(char *path) { goto error; ret->content[ret->size].command = READ; } - else if (strcmp(argv[0], "exec") == 0) { - if (argc < 3) - goto error; - 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) { if (argc < 3) goto error; diff --git a/src/swebs/connections.h b/src/swebs/connections.h index f097f7f..438e6a3 100644 --- a/src/swebs/connections.h +++ b/src/swebs/connections.h @@ -18,6 +18,7 @@ #ifndef HAVE_CONNECTIONS #define HAVE_CONNECTIONS +#include #include #include #include @@ -36,7 +37,10 @@ typedef struct Connection { /* the last time that data was received from this connection. */ RequestType type; - char *path; + BinaryString path; + long pathFieldCount; + long allocatedPathFields; + PathField *pathFields; /* ephemeral */ Field *fields; diff --git a/src/swebs/sitefile.h b/src/swebs/sitefile.h index b64f5e9..19b19de 100644 --- a/src/swebs/sitefile.h +++ b/src/swebs/sitefile.h @@ -25,7 +25,6 @@ typedef enum { READ, - EXEC, THROW, LINKED } Command; diff --git a/src/swebs/types.h b/src/swebs/types.h index 39d16a7..7474ac2 100644 --- a/src/swebs/types.h +++ b/src/swebs/types.h @@ -41,6 +41,26 @@ typedef enum { * */ } RequestType; +typedef struct { + char *data; + /* data is guarunteed to be NULL terminated, although not necessarily + * once. */ + size_t len; + size_t allocatedLen; + /* The amount of bytes allocated, for internal use. */ +} BinaryString; + +typedef struct { + BinaryString var; + BinaryString value; +} PathField; + +typedef struct { + BinaryString path; + long fieldCount; + PathField *fields; +} Path; + typedef struct { char *field; char *value; @@ -49,7 +69,7 @@ typedef struct { typedef struct { long fieldCount; Field *fields; - char *path; + Path path; RequestType type; void *body; size_t bodylen;