495 lines
9.9 KiB
C
495 lines
9.9 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "parslib.h"
|
|
#include "streecmp/streecmp.h"
|
|
|
|
extern char *methods;
|
|
extern char *headers;
|
|
|
|
static struct nod *method_tree = NULL;
|
|
static struct nod *header_tree = NULL;
|
|
|
|
int stoin(char *str, int len, int *out) {
|
|
int ret = 0;
|
|
int place = 1;
|
|
for (char *chr = str+len-1; chr >= str; chr--) {
|
|
if (chr == str) {
|
|
if (*chr == '+') {
|
|
goto _proceed;
|
|
}
|
|
if (*chr == '-') {
|
|
goto _proceed;
|
|
}
|
|
}
|
|
if (*chr >= '0' && *chr <= '9') {
|
|
goto _proceed;
|
|
}
|
|
|
|
return -1;
|
|
|
|
_proceed:
|
|
|
|
if (*chr == '-') {
|
|
ret = -ret;
|
|
continue;
|
|
}
|
|
if (*chr == '+') {
|
|
continue;
|
|
}
|
|
|
|
int number = *chr-'0';
|
|
ret += number * place;
|
|
place *= 10;
|
|
}
|
|
|
|
*out = ret;
|
|
return 0;
|
|
}
|
|
|
|
void printfpareq(struct httpareq *req) {
|
|
fprintf(stderr, "\tstats:\n"
|
|
"\t\tmethod\t: %d\n"
|
|
"\t\turi\t: %.*s\n"
|
|
"\t\tver\t: %.*s\n",
|
|
req->titl.method,
|
|
req->titl.uri.len, req->titl.uri.er,
|
|
req->titl.ver.len, req->titl.ver.er
|
|
);
|
|
|
|
fprintf(stdout, "\theaders:\n");
|
|
for (int i = 0; i < header_count; i++) {
|
|
struct point *pnt = &req->hentries[i];
|
|
if (!pnt->er) {
|
|
continue;
|
|
}
|
|
|
|
fprintf(stdout, "\t\t%d\t: %.*s\n", i, pnt->len, pnt->er);
|
|
}
|
|
}
|
|
|
|
void printfpares(struct httpares *res) {
|
|
fprintf(stderr, "\tstats:\n"
|
|
"\t\tver\t: %.*s\n"
|
|
"\t\tcode\t: %d\n"
|
|
"\t\tstext\t: %.*s\n",
|
|
res->titl.ver.len, res->titl.ver.er,
|
|
res->titl.code,
|
|
res->titl.stxt.len, res->titl.stxt.er
|
|
);
|
|
|
|
fprintf(stdout, "\theaders:\n");
|
|
for (int i = 0; i < header_count; i++) {
|
|
struct point *pnt = &res->hentries[i];
|
|
if (!pnt->er) {
|
|
continue;
|
|
}
|
|
|
|
fprintf(stdout, "\t\t%d\t: %.*s\n", i, pnt->len, pnt->er);
|
|
}
|
|
}
|
|
|
|
int initres(void) {
|
|
int ret = 0;
|
|
|
|
header_tree = allocnod();
|
|
if (!header_tree) {
|
|
return -1;
|
|
}
|
|
|
|
method_tree = allocnod();
|
|
if (!method_tree) {
|
|
return -1;
|
|
}
|
|
|
|
ret = gentree(header_tree, headers, NULL, LOOSE_CHECK);
|
|
if (ret < 0) {
|
|
return -1;
|
|
}
|
|
|
|
ret = gentree(method_tree, methods, NULL, LOOSE_CHECK);
|
|
if (ret < 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void fretres(void) {
|
|
frenod(method_tree);
|
|
frenod(header_tree);
|
|
}
|
|
|
|
void frepareq(struct httpareq *req) {
|
|
struct httitlereq *titl = &req->titl;
|
|
free(titl->uri.er);
|
|
titl->uri.er = NULL;
|
|
free(titl->ver.er);
|
|
titl->uri.er = NULL;
|
|
|
|
for (int i = 0; i < header_count; i++) {
|
|
struct point *e = &req->hentries[i];
|
|
if (!e->er) {
|
|
continue;
|
|
}
|
|
|
|
free(e->er);
|
|
e->er = NULL;
|
|
}
|
|
}
|
|
|
|
void frepares(struct httpares *res) {
|
|
struct httitleres *titl = &res->titl;
|
|
free(titl->ver.er);
|
|
titl->ver.er = NULL;
|
|
free(titl->stxt.er);
|
|
titl->stxt.er = NULL;
|
|
|
|
for (int i = 0; i < header_count; i++) {
|
|
struct point *e = &res->hentries[i];
|
|
if (!e->er) {
|
|
continue;
|
|
}
|
|
|
|
free(e->er);
|
|
e->er = NULL;
|
|
}
|
|
}
|
|
|
|
int readlin(char **buff, char **buff_lim) {
|
|
int diff = 0;
|
|
if ((*buff) >= (*buff_lim)) {
|
|
return diff;
|
|
}
|
|
|
|
int ret = 0;
|
|
char *match = strstr(*buff, "\r\n");
|
|
if (match) {
|
|
ret = match-(*buff);
|
|
*buff += 2;
|
|
} else {
|
|
ret = (*buff_lim)-(*buff);
|
|
}
|
|
*buff += ret;
|
|
return ret;
|
|
}
|
|
|
|
int parshfield(char *offset, int len, struct point *hentries) {
|
|
int key = 0;
|
|
int ret = 0;
|
|
int diff = 0;
|
|
|
|
char *cursor = offset;
|
|
char *cursor_lim = offset+len;
|
|
|
|
// header title
|
|
char *htitle_lim = strchr(cursor, ':');
|
|
if (!htitle_lim) {
|
|
return -1;
|
|
}
|
|
if (htitle_lim > cursor_lim) {
|
|
return -1;
|
|
}
|
|
|
|
diff = htitle_lim-cursor;
|
|
ret = streencmp(header_tree, cursor, diff, LOOSE_CHECK);
|
|
if (!ret) {
|
|
return 0; // skip it
|
|
}
|
|
|
|
key = ret;
|
|
cursor += diff;
|
|
|
|
// white space and seperators
|
|
_loop:
|
|
if (cursor > cursor_lim) {
|
|
return -1;
|
|
}
|
|
if (*cursor == ':') {
|
|
cursor++;
|
|
goto _loop;
|
|
}
|
|
if (*cursor == ' ') {
|
|
cursor++;
|
|
goto _loop;
|
|
}
|
|
|
|
// header value
|
|
diff = cursor_lim-cursor;
|
|
char *e = strndup(cursor, diff);
|
|
if (!e) {
|
|
return -1;
|
|
}
|
|
|
|
hentries[key].er = e;
|
|
hentries[key].len = diff;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pahostinfo(char *offset, int len, struct hostinfo *info) {
|
|
int diff = 0;
|
|
int usedefault = 0;
|
|
char *delim = strchr(offset, ':');
|
|
if (!delim) {
|
|
delim = offset+len;
|
|
usedefault = 1;
|
|
}
|
|
|
|
diff = delim-offset;
|
|
info->hostname = strndup(offset, diff);
|
|
if (!info->hostname) {
|
|
goto _err;
|
|
}
|
|
info->hostname_len = diff;
|
|
|
|
if (usedefault) {
|
|
diff = strlen(DEFAULT_HTTP);
|
|
info->service = strndup(DEFAULT_HTTP, diff);
|
|
if (!info->service) {
|
|
goto _err_service;
|
|
}
|
|
info->service_len = diff;
|
|
} else {
|
|
char *service_offset = delim+1;
|
|
char *end = offset+len;
|
|
diff = end-service_offset;
|
|
info->service = strndup(service_offset, diff);
|
|
if (!info->service) {
|
|
goto _err_service;
|
|
}
|
|
info->service_len = diff;
|
|
}
|
|
|
|
return 0;
|
|
|
|
_err_service:
|
|
free(info->hostname);
|
|
|
|
_err:
|
|
return -1;
|
|
}
|
|
|
|
int pareqtitl(char *offset, int len, struct httitlereq *titl) {
|
|
int ret = 0;
|
|
int diff = 0;
|
|
char *cursor = offset;
|
|
char *cursor_lim = cursor+len;
|
|
|
|
// method
|
|
char *method_lim = strchr(cursor, ' ');
|
|
if (!method_lim) {
|
|
return -1;
|
|
}
|
|
if (method_lim > cursor_lim) {
|
|
return -1;
|
|
}
|
|
|
|
diff = method_lim-cursor;
|
|
ret = streencmp(method_tree, cursor, diff, LOOSE_CHECK);
|
|
if (ret == 0) {
|
|
return -1;
|
|
}
|
|
|
|
titl->method = ret;
|
|
cursor += diff;
|
|
|
|
// white space
|
|
_loop1:
|
|
if (cursor > cursor_lim) {
|
|
return -1;
|
|
}
|
|
if (*cursor == ' ') {
|
|
cursor++;
|
|
goto _loop1;
|
|
}
|
|
|
|
// uri
|
|
char *uri_lim = strchr(cursor, ' ');
|
|
if (!uri_lim) {
|
|
return -1;
|
|
}
|
|
if (uri_lim > cursor_lim) {
|
|
return -1;
|
|
}
|
|
|
|
diff = uri_lim-cursor;
|
|
char *e = strndup(cursor, diff);
|
|
if (!e) {
|
|
return -1;
|
|
}
|
|
|
|
titl->uri.er = e;
|
|
titl->uri.len = diff;
|
|
|
|
cursor += diff;
|
|
|
|
// white space
|
|
_loop2:
|
|
if (cursor > cursor_lim) {
|
|
return -1;
|
|
}
|
|
if (*cursor == ' ') {
|
|
cursor++;
|
|
goto _loop2;
|
|
}
|
|
|
|
// ver
|
|
diff = cursor_lim-cursor;
|
|
e = strndup(cursor, diff);
|
|
if (!e) {
|
|
return -1;
|
|
}
|
|
|
|
titl->ver.er = e;
|
|
titl->ver.len = diff;
|
|
|
|
cursor += diff;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int parestitl(char *offset, int len, struct httitleres *titl) {
|
|
int ret = 0;
|
|
int diff = 0;
|
|
char *cursor = offset;
|
|
char *cursor_lim = cursor+len;
|
|
|
|
// ver
|
|
char *ver_lim = strchr(cursor, ' ');
|
|
if (!ver_lim) {
|
|
return -1;
|
|
}
|
|
if (ver_lim > cursor_lim) {
|
|
return -1;
|
|
}
|
|
|
|
diff = ver_lim-cursor;
|
|
char *e = strndup(cursor, diff);
|
|
if (!e) {
|
|
return -1;
|
|
}
|
|
|
|
titl->ver.er = e;
|
|
titl->ver.len = diff;
|
|
|
|
cursor += diff;
|
|
|
|
// white space
|
|
_loop1:
|
|
if (cursor > cursor_lim) {
|
|
return -1;
|
|
}
|
|
if (*cursor == ' ') {
|
|
cursor++;
|
|
goto _loop1;
|
|
}
|
|
|
|
// code
|
|
char *code_lim = strchr(cursor, ' ');
|
|
if (!code_lim) {
|
|
return -1;
|
|
}
|
|
if (code_lim > cursor_lim) {
|
|
return -1;
|
|
}
|
|
|
|
diff = code_lim-cursor;
|
|
int code;
|
|
ret = stoin(cursor, diff, &code);
|
|
if (ret < 0) {
|
|
return -1;
|
|
}
|
|
|
|
titl->code = code;
|
|
cursor += diff;
|
|
|
|
// white space
|
|
_loop2:
|
|
if (cursor > cursor_lim) {
|
|
return -1;
|
|
}
|
|
if (*cursor == ' ') {
|
|
cursor++;
|
|
goto _loop2;
|
|
}
|
|
|
|
// status text
|
|
diff = cursor_lim-cursor;
|
|
e = strndup(cursor, diff);
|
|
if (!e) {
|
|
return -1;
|
|
}
|
|
|
|
titl->stxt.er = e;
|
|
titl->stxt.len = diff;
|
|
|
|
cursor += diff;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pareq(char *buff, struct httpareq *req) {
|
|
int ret;
|
|
char *buff_lim = buff+strlen(buff);
|
|
|
|
char *title_offset = buff;
|
|
int title_len = readlin(&buff, &buff_lim);
|
|
if ((ret = pareqtitl(title_offset, title_len, &req->titl)) < 0) {
|
|
fprintf(stderr, "Failed parsing title\n");
|
|
return -1;
|
|
}
|
|
|
|
for (int bound = 0; bound < MAX_BOUND; bound++) {
|
|
char *header_offset = buff;
|
|
int header_len = readlin(&buff, &buff_lim);
|
|
char *header_limit = header_offset+header_len;
|
|
|
|
// IF END OF MESSAGE
|
|
if (!header_len) {
|
|
break;
|
|
}
|
|
|
|
if ((ret = parshfield(header_offset,
|
|
header_len,
|
|
req->hentries)) < 0) {
|
|
fprintf(stderr, "Failed parsing header\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int pares(char *buff, struct httpares *res) {
|
|
int ret;
|
|
char *buff_lim = buff+strlen(buff);
|
|
|
|
char *title_offset = buff;
|
|
int title_len = readlin(&buff, &buff_lim);
|
|
if ((ret = parestitl(title_offset, title_len, &res->titl)) < 0) {
|
|
fprintf(stderr, "Failed parsing title\n");
|
|
return -1;
|
|
}
|
|
|
|
for (int bound = 0; bound < MAX_BOUND; bound++) {
|
|
char *header_offset = buff;
|
|
int header_len = readlin(&buff, &buff_lim);
|
|
char *header_limit = header_offset+header_len;
|
|
|
|
// IF END OF MESSAGE
|
|
if (!header_len) {
|
|
break;
|
|
}
|
|
|
|
if ((ret = parshfield(header_offset,
|
|
header_len,
|
|
res->hentries)) < 0) {
|
|
fprintf(stderr, "Failed parsing header\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|