Added url variables, removed exec pages
This commit is contained in:
@@ -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*/
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
#include <swebs/swebs.h>
|
||||
|
||||
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);
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "<p>By the way today's date is $(date)</p>"
|
||||
@@ -3,5 +3,4 @@
|
||||
<h3>It's not very polished but it's certainly a website</h3>
|
||||
|
||||
<a href="blog/2022-1-25.html">2021-1-25</a>
|
||||
<a href="blog/2022-1-31">2021-1-31</a>
|
||||
<a href="blog/forbidden">The forbidden blog post</a>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef HAVE_CONNECTIONS
|
||||
#define HAVE_CONNECTIONS
|
||||
|
||||
#include <swebs/types.h>
|
||||
#include <swebs/runner.h>
|
||||
#include <swebs/sockets.h>
|
||||
#include <swebs/sitefile.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
typedef enum {
|
||||
READ,
|
||||
EXEC,
|
||||
THROW,
|
||||
LINKED
|
||||
} Command;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user