Rewrote sitefile parsing
This commit is contained in:
401
src/sitefile.c
401
src/sitefile.c
@@ -33,6 +33,7 @@
|
|||||||
* good.
|
* good.
|
||||||
* */
|
* */
|
||||||
|
|
||||||
|
#define CFLAGS (REG_EXTENDED | REG_ICASE)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ARG,
|
ARG,
|
||||||
@@ -185,27 +186,223 @@ static int getports(unsigned short **ports, int *portcount, char *data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sitefile *parseSitefile(char *path) {
|
typedef struct {
|
||||||
FILE *file;
|
RequestType respondto;
|
||||||
RequestType respondto = GET;
|
char *host;
|
||||||
const int cflags = REG_EXTENDED | REG_ICASE;
|
|
||||||
char *host = NULL;
|
|
||||||
int argc;
|
|
||||||
char **argv;
|
|
||||||
Sitefile *ret;
|
|
||||||
unsigned short *ports;
|
unsigned short *ports;
|
||||||
int portcount;
|
int portcount;
|
||||||
char *contenttype;
|
char *contenttype;
|
||||||
|
} LocalVars;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DATA_CHANGE,
|
||||||
|
SITE_SPEC,
|
||||||
|
COMMAND_RET_ERROR
|
||||||
|
} CommandReturn;
|
||||||
|
|
||||||
|
static CommandReturn localvar(LocalVars *vars, Sitefile *sitefile,
|
||||||
|
int argc, char **argv) {
|
||||||
|
if (argc < 3)
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
if (strcmp(argv[1], "respondto") == 0) {
|
||||||
|
if ((vars->respondto = getType(argv[2])) == INVALID)
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
return DATA_CHANGE;
|
||||||
|
}
|
||||||
|
if (strcmp(argv[1], "host") == 0) {
|
||||||
|
free(vars->host);
|
||||||
|
vars->host = xstrdup(argv[2]);
|
||||||
|
return DATA_CHANGE;
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[1], "port") == 0) {
|
||||||
|
free(vars->ports);
|
||||||
|
if (getports(&vars->ports, &vars->portcount, argv[2])) {
|
||||||
|
fprintf(stderr, "Invalid port list %s\n", argv[2]);
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
}
|
||||||
|
return DATA_CHANGE;
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[1], "type") == 0) {
|
||||||
|
free(vars->contenttype);
|
||||||
|
vars->contenttype = strdup(argv[2]);
|
||||||
|
return DATA_CHANGE;
|
||||||
|
}
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CommandReturn globalvar(LocalVars *vars, Sitefile *sitefile,
|
||||||
|
int argc, char **argv) {
|
||||||
|
if (argc < 3)
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
if (strcmp(argv[1], "library") == 0) {
|
||||||
|
#if DYNAMIC_LINKED_PAGES
|
||||||
|
sitefile->getResponse = loadGetResponse(argv[2]);
|
||||||
|
return DATA_CHANGE;
|
||||||
|
#else
|
||||||
|
fputs("This version of swebs has no dynamic page support\n",
|
||||||
|
stderr);
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CommandReturn declareport(LocalVars *vars, Sitefile *sitefile,
|
||||||
|
int argc, char **argv) {
|
||||||
|
Port newport;
|
||||||
|
int i;
|
||||||
|
if (argc < 3) {
|
||||||
|
fputs("Usage: declare [transport] [port]\n", stderr);
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
}
|
||||||
|
newport.num = atoi(argv[2]);
|
||||||
|
|
||||||
|
for (i = 0; i < sitefile->portcount; ++i) {
|
||||||
|
if (sitefile->ports[i].num == newport.num) {
|
||||||
|
fprintf(stderr, "Port %hu declared multiple times\n",
|
||||||
|
newport.num);
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "TCP") == 0)
|
||||||
|
newport.type = TCP;
|
||||||
|
else if (strcmp(argv[1], "TLS") == 0)
|
||||||
|
newport.type = TLS;
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Invalid transport %s\n", argv[1]);
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
}
|
||||||
|
newport.timeout = 2000;
|
||||||
|
newport.key = newport.cert = NULL;
|
||||||
|
if (sitefile->portcount >= sitefile->portalloc) {
|
||||||
|
sitefile->portalloc *= 2;
|
||||||
|
sitefile->ports = xrealloc(sitefile->ports,
|
||||||
|
sitefile->portalloc * sizeof *sitefile->ports);
|
||||||
|
}
|
||||||
|
memcpy(sitefile->ports + sitefile->portcount, &newport,
|
||||||
|
sizeof newport);
|
||||||
|
++sitefile->portcount;
|
||||||
|
return DATA_CHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CommandReturn portvar(LocalVars *vars, Sitefile *sitefile,
|
||||||
|
int argc, char **argv) {
|
||||||
|
#define PORT_ATTRIBUTE(name, func) \
|
||||||
|
if (strcmp(argv[0], #name) == 0) { \
|
||||||
|
int i; \
|
||||||
|
unsigned short port; \
|
||||||
|
if (argc < 3) { \
|
||||||
|
fputs("Usage: " #name " [" #name "] [port]\n", \
|
||||||
|
stderr); \
|
||||||
|
return COMMAND_RET_ERROR; \
|
||||||
|
} \
|
||||||
|
port = atoi(argv[2]); \
|
||||||
|
for (i = 0; i < sitefile->portcount; ++i) \
|
||||||
|
if (sitefile->ports[i].num == port) \
|
||||||
|
sitefile->ports[i].name = func(argv[1]); \
|
||||||
|
return DATA_CHANGE; \
|
||||||
|
}
|
||||||
|
PORT_ATTRIBUTE(key, xstrdup)
|
||||||
|
PORT_ATTRIBUTE(cert, xstrdup)
|
||||||
|
PORT_ATTRIBUTE(timeout, atoi)
|
||||||
|
#undef PORT_ATTRIBUTE
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int expandsitefile(Sitefile *sitefile, char *regex) {
|
||||||
|
if (sitefile->size >= sitefile->alloc) {
|
||||||
|
SiteCommand *newcontent;
|
||||||
|
sitefile->alloc *= 2;
|
||||||
|
newcontent = xrealloc(sitefile->content, sitefile->alloc *
|
||||||
|
sizeof *newcontent);
|
||||||
|
sitefile->content = newcontent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return regcomp(&sitefile->content[sitefile->size].path, regex, CFLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *getcodestring(const char *str) {
|
||||||
|
return getCode(atoi(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
static CommandReturn defsitespec(LocalVars *vars, Sitefile *sitefile,
|
||||||
|
int argc, char **argv) {
|
||||||
|
const struct {
|
||||||
|
char *command;
|
||||||
|
char *(*getarg)(const char *);
|
||||||
|
Command type;
|
||||||
|
} sitespecs[] = {
|
||||||
|
{"read", strdup, READ},
|
||||||
|
{"throw", getcodestring, THROW},
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
if (argc < 3)
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
expandsitefile(sitefile, argv[1]);
|
||||||
|
for (i = 0; i < LEN(sitespecs); ++i) {
|
||||||
|
if (strcmp(argv[0], sitespecs[i].command) == 0) {
|
||||||
|
sitefile->content[sitefile->size].arg =
|
||||||
|
sitespecs[i].getarg(argv[2]);
|
||||||
|
if (sitefile->content[sitefile->size].arg == NULL)
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
sitefile->content[sitefile->size].command =
|
||||||
|
sitespecs[i].type;
|
||||||
|
return SITE_SPEC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CommandReturn linkedsitespec(LocalVars *vars, Sitefile *sitefile,
|
||||||
|
int argc, char **argv) {
|
||||||
|
#if DYNAMIC_LINKED_PAGES
|
||||||
|
if (argc < 2)
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
expandsitefile(sitefile, argv[1]);
|
||||||
|
sitefile->content[sitefile->size].command = LINKED;
|
||||||
|
return SITE_SPEC;
|
||||||
|
#else
|
||||||
|
fputs("This version of swebs doesn't have linked page support", stderr);
|
||||||
|
return COMMAND_RET_ERROR;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Sitefile *parseSitefile(char *path) {
|
||||||
|
FILE *file;
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
Sitefile *ret;
|
||||||
|
const struct {
|
||||||
|
char *name;
|
||||||
|
CommandReturn (*updatesitefile)(LocalVars *vars,
|
||||||
|
Sitefile *sitefile,
|
||||||
|
int argc, char **argv);
|
||||||
|
} commandspec[] = {
|
||||||
|
{"set", localvar},
|
||||||
|
{"define", globalvar},
|
||||||
|
{"read", defsitespec},
|
||||||
|
{"throw", defsitespec},
|
||||||
|
{"linked", linkedsitespec},
|
||||||
|
{"declare", declareport},
|
||||||
|
{"key", portvar},
|
||||||
|
{"cert", portvar},
|
||||||
|
{"timeout", portvar},
|
||||||
|
};
|
||||||
|
LocalVars vars;
|
||||||
|
|
||||||
file = fopen(path, "r");
|
file = fopen(path, "r");
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
vars.respondto = GET;
|
||||||
|
vars.host = xstrdup(".*");
|
||||||
|
vars.ports = xmalloc(sizeof *vars.ports);
|
||||||
|
vars.ports[0] = 80;
|
||||||
|
vars.portcount = 1;
|
||||||
|
vars.contenttype = xstrdup("text/html");
|
||||||
|
|
||||||
ret = xmalloc(sizeof *ret);
|
ret = xmalloc(sizeof *ret);
|
||||||
|
|
||||||
ports = malloc(sizeof *ports);
|
|
||||||
ports[0] = 80;
|
|
||||||
portcount = 1;
|
|
||||||
|
|
||||||
ret->size = 0;
|
ret->size = 0;
|
||||||
ret->alloc = 50;
|
ret->alloc = 50;
|
||||||
ret->content = xmalloc(ret->alloc * sizeof *ret->content);
|
ret->content = xmalloc(ret->alloc * sizeof *ret->content);
|
||||||
@@ -216,15 +413,13 @@ Sitefile *parseSitefile(char *path) {
|
|||||||
ret->getResponse = NULL;
|
ret->getResponse = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
contenttype = xstrdup("text/html");
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int i;
|
int i;
|
||||||
CommandType commandtype;
|
CommandType commandtype;
|
||||||
|
nextcommand:
|
||||||
commandtype = getcommand(file, &argc, &argv);
|
commandtype = getcommand(file, &argc, &argv);
|
||||||
switch (commandtype) {
|
switch (commandtype) {
|
||||||
case PAST_END:
|
case PAST_END:
|
||||||
free(ports);
|
|
||||||
for (i = 0; i < ret->portcount; ++i) {
|
for (i = 0; i < ret->portcount; ++i) {
|
||||||
Port *port = ret->ports + i;
|
Port *port = ret->ports + i;
|
||||||
if (port->type == TLS &&
|
if (port->type == TLS &&
|
||||||
@@ -235,8 +430,9 @@ Sitefile *parseSitefile(char *path) {
|
|||||||
goto nterror;
|
goto nterror;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(contenttype);
|
free(vars.ports);
|
||||||
free(host);
|
free(vars.contenttype);
|
||||||
|
free(vars.host);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
return ret;
|
return ret;
|
||||||
case COMMAND_ERROR:
|
case COMMAND_ERROR:
|
||||||
@@ -244,168 +440,43 @@ Sitefile *parseSitefile(char *path) {
|
|||||||
case NORMAL:
|
case NORMAL:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (strcmp(argv[0], "set") == 0) {
|
for (i = 0; i < LEN(commandspec); ++i) {
|
||||||
if (argc < 3)
|
if (strcmp(argv[0], commandspec[i].name) == 0) {
|
||||||
goto error;
|
switch (commandspec[i].updatesitefile(&vars,
|
||||||
if (strcmp(argv[1], "respondto") == 0) {
|
ret, argc, argv)) {
|
||||||
respondto = getType(argv[2]);
|
case DATA_CHANGE:
|
||||||
if (respondto == INVALID)
|
goto nextcommand;
|
||||||
|
case SITE_SPEC:
|
||||||
|
goto newsitespec;
|
||||||
|
case COMMAND_RET_ERROR:
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "host") == 0) {
|
break;
|
||||||
free(host);
|
|
||||||
host = xstrdup(argv[2]);
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[1], "port") == 0) {
|
|
||||||
free(ports);
|
|
||||||
if (getports(&ports, &portcount, argv[2])) {
|
|
||||||
fprintf(stderr, "Invalid port list %s\n",
|
|
||||||
argv[2]);
|
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "type") == 0) {
|
|
||||||
free(contenttype);
|
|
||||||
contenttype = strdup(argv[2]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
goto error;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[0], "define") == 0) {
|
|
||||||
if (argc < 3)
|
|
||||||
goto error;
|
|
||||||
else if (strcmp(argv[1], "library") == 0) {
|
|
||||||
#if DYNAMIC_LINKED_PAGES
|
|
||||||
ret->getResponse = loadGetResponse(argv[2]);
|
|
||||||
#else
|
|
||||||
fputs(
|
|
||||||
"This version of swebs has no dynamic page support\n", stderr);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
goto error;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[0], "declare") == 0) {
|
|
||||||
Port newport;
|
|
||||||
if (argc < 3) {
|
|
||||||
fputs(
|
|
||||||
"Usage: declare [transport] [port]\n", stderr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
newport.num = atoi(argv[2]);
|
|
||||||
|
|
||||||
for (i = 0; i < ret->portcount; ++i) {
|
|
||||||
if (ret->ports[i].num == newport.num) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Port %hu declared multiple times\n", newport.num);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(argv[1], "TCP") == 0)
|
|
||||||
newport.type = TCP;
|
|
||||||
else if (strcmp(argv[1], "TLS") == 0)
|
|
||||||
newport.type = TLS;
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "Invalid transport %s\n",
|
|
||||||
argv[1]);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
newport.timeout = 2000;
|
|
||||||
newport.key = newport.cert = NULL;
|
|
||||||
if (ret->portcount >= ret->portalloc) {
|
|
||||||
ret->portalloc *= 2;
|
|
||||||
ret->ports = xrealloc(ret->ports,
|
|
||||||
ret->portalloc * sizeof *ret->ports);
|
|
||||||
}
|
|
||||||
memcpy(ret->ports + ret->portcount, &newport,
|
|
||||||
sizeof newport);
|
|
||||||
++ret->portcount;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#define PORT_ATTRIBUTE(name, func) \
|
|
||||||
else if (strcmp(argv[0], #name) == 0) { \
|
|
||||||
unsigned short port; \
|
|
||||||
if (argc < 3) { \
|
|
||||||
fputs("Usage: " #name " [" #name "] [port]\n", \
|
|
||||||
stderr); \
|
|
||||||
goto error; \
|
|
||||||
} \
|
|
||||||
port = atoi(argv[2]); \
|
|
||||||
for (i = 0; i < ret->portcount; ++i) \
|
|
||||||
if (ret->ports[i].num == port) \
|
|
||||||
ret->ports[i].name = func(argv[1]); \
|
|
||||||
continue; \
|
|
||||||
}
|
|
||||||
PORT_ATTRIBUTE(key, xstrdup)
|
|
||||||
PORT_ATTRIBUTE(cert, xstrdup)
|
|
||||||
PORT_ATTRIBUTE(timeout, atoi)
|
|
||||||
#undef PORT_ATTRIBUTE
|
|
||||||
if (ret->size >= ret->alloc) {
|
|
||||||
SiteCommand *newcontent;
|
|
||||||
ret->alloc *= 2;
|
|
||||||
newcontent = realloc(ret->content, ret->alloc *
|
|
||||||
sizeof *newcontent);
|
|
||||||
if (newcontent == NULL)
|
|
||||||
goto error;
|
|
||||||
ret->content = newcontent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (regcomp(&ret->content[ret->size].path, argv[1],
|
|
||||||
cflags))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (strcmp(argv[0], "read") == 0) {
|
|
||||||
if (argc < 3)
|
|
||||||
goto error;
|
|
||||||
ret->content[ret->size].arg = xstrdup(argv[2]);
|
|
||||||
if (ret->content[ret->size].arg == NULL)
|
|
||||||
goto error;
|
|
||||||
ret->content[ret->size].command = READ;
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[0], "throw") == 0) {
|
|
||||||
if (argc < 3)
|
|
||||||
goto error;
|
|
||||||
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 if (strcmp(argv[0], "linked") == 0) {
|
|
||||||
#if DYNAMIC_LINKED_PAGES
|
|
||||||
ret->content[ret->size].command = LINKED;
|
|
||||||
#else
|
|
||||||
fputs(
|
|
||||||
"This version of swebs doesn't have linked page support", stderr);
|
|
||||||
goto error;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "Unknown sitefile command %s", argv[0]);
|
fprintf(stderr, "Unknown sitefile command %s", argv[0]);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
newsitespec:
|
||||||
freecommand(argc, argv);
|
freecommand(argc, argv);
|
||||||
ret->content[ret->size].respondto = respondto;
|
ret->content[ret->size].respondto = vars.respondto;
|
||||||
if (host == NULL)
|
regcomp(&ret->content[ret->size].host, vars.host, CFLAGS);
|
||||||
regcomp(&ret->content[ret->size].host, ".*", cflags);
|
|
||||||
else
|
|
||||||
regcomp(&ret->content[ret->size].host, host, cflags);
|
|
||||||
|
|
||||||
ret->content[ret->size].ports = xmalloc(portcount *
|
ret->content[ret->size].ports = xmalloc(vars.portcount *
|
||||||
sizeof *ret->content[ret->size].ports);
|
sizeof *ret->content[ret->size].ports);
|
||||||
memcpy(ret->content[ret->size].ports, ports, portcount * sizeof *ports);
|
memcpy(ret->content[ret->size].ports, vars.ports,
|
||||||
ret->content[ret->size].portcount = portcount;
|
vars.portcount * sizeof *vars.ports);
|
||||||
|
ret->content[ret->size].portcount = vars.portcount;
|
||||||
|
|
||||||
ret->content[ret->size].contenttype = xstrdup(contenttype);
|
ret->content[ret->size].contenttype = xstrdup(vars.contenttype);
|
||||||
|
|
||||||
ret->size++;
|
++ret->size;
|
||||||
}
|
}
|
||||||
error:
|
error:
|
||||||
freecommand(argc, argv);
|
freecommand(argc, argv);
|
||||||
nterror:
|
nterror:
|
||||||
|
free(vars.ports);
|
||||||
|
free(vars.contenttype);
|
||||||
|
free(vars.host);
|
||||||
freeSitefile(ret);
|
freeSitefile(ret);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
int initLogging(char *path);
|
int initLogging(char *path);
|
||||||
|
|
||||||
|
#define LEN(arr) (sizeof (arr) / sizeof (*arr))
|
||||||
|
|
||||||
int smalloc(size_t size);
|
int smalloc(size_t size);
|
||||||
/* returns an id passed to saddr, or -1 on error */
|
/* returns an id passed to saddr, or -1 on error */
|
||||||
void *saddr(int id);
|
void *saddr(int id);
|
||||||
|
|||||||
Reference in New Issue
Block a user