#include #include #include #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; }