diff --git a/.gitignore b/.gitignore index 4fc5420..56c6303 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ *.o compile_commands.json -tinyparser +test diff --git a/Makefile b/Makefile index 15b11b0..da7a49b 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,23 @@ CC=gcc CFLAGS=-g3 CFILES=parslib.c strings.c -CFILES_STREECMP=streecmp/streecmp.c -OUTPUT=parslib +TEST_FILES=test.c +OUTPUT=parslib.o +TOUTPUT=test -all: - $(CC) $(CFLAGS) $(CFILES) $(CFILES_STREECMP) -o $(OUTPUT) +all: $(FILES) + $(CC) -c $(CFLAGS) -o parslib.o parslib.c + $(CC) -c $(CFLAGS) -o strings.o strings.c + $(CC) -c $(CFLAGS) -o streecmp/streecmp.o streecmp/streecmp.c + +test: all + $(CC) $(CFLAGS) $(TEST_FILES) parslib.o strings.o streecmp/streecmp.o -o $(TOUTPUT) + +run_test: + ./$(TOUTPUT) run: ./$(OUTPUT) clean: - rm -rf $(OUTPUT) + rm -rf *.o $(TOUTPUT) diff --git a/README b/README index 68c0f4e..d0b9e81 100644 --- a/README +++ b/README @@ -27,14 +27,10 @@ TECHNICALS LEAKS - LEAKS file contains the most recent valgrind memory leaks - dump ran on main.c - - LEAKS.TEST.[id] files respectively contain the most recent - valgrind memory leaks dump ran on a test with an id=[id] + LEAKS file contains the most recent valgrind + memory leaks dump ran on a test program. TODO - * implement tests * integrations with tinyproxy..? diff --git a/parslib.c b/parslib.c index e7e64b3..a714406 100644 --- a/parslib.c +++ b/parslib.c @@ -13,16 +13,16 @@ static struct nod *header_tree = NULL; static int stoin(char *str, int len, int *out) { int ret = 0; int place = 1; - for (char *chr = str+len; chr >= str; chr--) { + for (char *chr = str+len-1; chr >= str; chr--) { if (chr == str) { - if (*ch == '+') { + if (*chr == '+') { goto _proceed; } - if (*ch == '-') { + if (*chr == '-') { goto _proceed; } } - if (*chr >= '0' && *ch <= '9') { + if (*chr >= '0' && *chr <= '9') { goto _proceed; } @@ -44,21 +44,43 @@ _proceed: } *out = ret; + return 0; } -void printfpars(struct httpars *pars) { +void printfpareq(struct httpareq *req) { fprintf(stderr, "\tstats:\n" "\t\tmethod\t: %d\n" "\t\turi\t: %.*s\n" "\t\tver\t: %.*s\n", - pars->titl.method, - pars->titl.uri.len, pars->titl.uri.er, - pars->titl.ver.len, pars->titl.ver.er + 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 = &pars->hentries[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; } @@ -94,8 +116,8 @@ int initres(void) { } void fretres(void) { - free(method_tree); - free(header_tree); + frenod(method_tree); + frenod(header_tree); } int readlin(char **buff, char **buff_lim) { @@ -136,7 +158,7 @@ int parshfield(char *offset, int len, struct point *hentries) { diff = htitle_lim-cursor; ret = streencmp(header_tree, cursor, diff); if (!ret) { - return -1; + return 0; // skip it } key = ret; @@ -165,6 +187,75 @@ _loop: return 0; } +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); + 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; + titl->uri.er = cursor; + 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; + titl->ver.er = cursor; + titl->ver.len = diff; + + cursor += diff; + + return 0; +} + int parestitl(char *offset, int len, struct httitleres *titl) { int ret = 0; int diff = 0; @@ -235,82 +326,13 @@ _loop2: return 0; } -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); - 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; - titl->uri.er = cursor; - 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; - titl->ver.er = cursor; - titl->ver.len = diff; - - cursor += diff; - - return 0; -} - -int parsme(char *buff, struct httpars *pars) { +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 = parstitle(title_offset, title_len, &pars->titl)) < 0) { + if ((ret = pareqtitl(title_offset, title_len, &req->titl)) < 0) { fprintf(stderr, "Failed parsing title\n"); return -1; } @@ -327,7 +349,7 @@ int parsme(char *buff, struct httpars *pars) { if ((ret = parshfield(header_offset, header_len, - pars->hentries)) < 0) { + req->hentries)) < 0) { fprintf(stderr, "Failed parsing header\n"); return -1; } @@ -336,3 +358,34 @@ int parsme(char *buff, struct httpars *pars) { 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; +} diff --git a/parslib.h b/parslib.h index c2ef075..77bca95 100644 --- a/parslib.h +++ b/parslib.h @@ -163,14 +163,20 @@ struct httpareq { struct httpares { struct httitleres titl; struct point hentries[header_count]; -} +}; int initres(void); void fretres(void); int readlin(char **buff, char **buff_lim); int parshfield(char *offset, int len, /* out */ struct point *hentries); -int parstitle(char *offset, int len, /* out */ struct httitle *titl); -int parsme(char *buff, /* out */ struct httpars *pars); -void printfpars(struct httpars *pars); + +int pareqtitl(char *offset, int len, struct httitlereq *titl); +int parestitl(char *offset, int len, struct httitleres *titl); + +int pareq(char *buff, /* out */ struct httpareq *req); +int pares(char *buff, /* out */ struct httpares *res); + +void printfpareq(struct httpareq *req); +void printfpares(struct httpares *res); #endif diff --git a/test.c b/test.c new file mode 100644 index 0000000..254c21a --- /dev/null +++ b/test.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include "parslib.h" + +char *req_test_data = { + "GET / HTTP/1.1\r\n" + "Host: archive.0xdeadbeer.xyz\r\n" + "User-Agent: curl/8.9.1\r\n" + "Accept: */*\r\n" + "\r\n" + "{\"key\": \"kefjoiawejfojgorgjbosejrgo\"}|" + "GET / HTTP/1.1\r\n" + "Host: google.com\r\n" + "User-Agent: curl/8.9.1\r\n" + "Accept: */*\r\n|" +}; +char *res_test_data = { + "HTTP/1.1 301 Moved Permanently\r\n" + "Location: http://www.google.com/\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Content-Security-Policy-Report-Only: object-src 'none';base-uri 'self';script-src 'nonce-7hRaJZVpUAa6E54ys6qpuA' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp\r\n" + "Date: Wed, 04 Sep 2024 17:52:02 GMT\r\n" + "Expires: Fri, 04 Oct 2024 17:52:02 GMT\r\n" + "Cache-Control: public, max-age=2592000\r\n" + "Server: gws\r\n" + "Content-Length: 219\r\n" + "X-XSS-Protection: 0\r\n" + "X-Frame-Options: SAMEORIGIN\r\n|" +}; + +int main(void) { + int ret = 0; + char *reqs = strdup(req_test_data); + if (!reqs) { + fprintf(stderr, "Not enough dynamic memory\n"); + return -1; + } + + char *reses = strdup(res_test_data); + if (!reses) { + fprintf(stderr, "Not enough dynamic memory\n"); + return -1; + } + + struct httpareq *req = (struct httpareq *) calloc(1, sizeof(struct httpareq)); + if (!req) { + fprintf(stderr, "Not enough dynamic memory\n"); + return -1; + } + + struct httpares *res = (struct httpares *) calloc(1, sizeof(struct httpares)); + if (!res) { + fprintf(stderr, "Not enough dynamic memory\n"); + return -1; + } + + ret = initres(); + if (ret < 0) { + fprintf(stderr, "Failed initializing parser\n"); + return -1; + } + + fprintf(stdout, "xxxREQxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + for (char *ch = strtok(reqs, "|"); ch != NULL; ch = strtok(NULL, "|")) { + ret = pareq(ch, req); + fprintf(stdout, "-------------------------------------\n"); + printfpareq(req); + fprintf(stdout, "-------------------------------------\n"); + } + fprintf(stdout, "xxxRESxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + for (char *ch = strtok(reses, "|"); ch != NULL; ch = strtok(NULL, "|")) { + ret = pares(ch, res); + fprintf(stdout, "-------------------------------------\n"); + printfpares(res); + fprintf(stdout, "-------------------------------------\n"); + } + fprintf(stdout, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + + fretres(); + free(res); + free(req); + free(reses); + free(reqs); + + return 0; +}