#include #include #include #include "tinyparser.h" #include "streecmp/streecmp.h" extern char *headers; enum errs err = err_init; enum states state = state_init; enum methods method = method_init; char *uri = NULL; char *ver = NULL; int uri_len = 0; int ver_len = 0; struct nod *header_tree = NULL; char **header_table = NULL; int read_line(char **buffer, char **buffer_limit) { int diff = 0; if ((*buffer) >= (*buffer_limit)) { return diff; } int ret = 0; char *match = strstr(*buffer, "\r\n"); if (match) { ret = match-(*buffer); *buffer += 2; } else { ret = (*buffer_limit)-(*buffer); } *buffer += ret; return ret; } int cmp_orig(char *ch, char *orig, char *limit) { int diff = 0; for (; *orig != '\0' && *ch != '\0' && ch < limit; orig++, ch++, diff++) if (*orig != *ch) return -1; return diff; } int cmp_ascii(char *ch, char *limit) { int diff = 0; for (; *ch != '\0' && *ch != ' ' && ch < limit; ch++, diff++) { if (*ch >= '0' && *ch <= '9') continue; if (*ch >= 'A' && *ch <= 'Z') continue; if (*ch >= 'a' && *ch <= 'z') continue; if (*ch >= '#' && *ch <= '/') continue; if (*ch == '!') continue; if (*ch == ':') continue; if (*ch == ';') continue; if (*ch == '=') continue; if (*ch == '?') continue; if (*ch == '@') continue; if (*ch == '[') continue; if (*ch == ']') continue; if (*ch == '_') continue; if (*ch == '~') continue; return -1; } return diff; } int parse_header(char *offset, int len) { int cursor = 0; int ret = 0; char *header_limit = offset+len; char *sep = strchr(offset, ':'); if (!sep) { return -1; } if (sep > header_limit) { return -1; } int htitle_len = sep-offset; ret = streencmp(header_tree, offset, htitle_len); if (ret == 0) { return -1; } char *hvalue = sep+1; header_table[ret] = hvalue; return 0; } int parse_title(char *offset, int len) { int cursor = 0; while (state != state_title_ok && state != state_title_err) { if (cursor >= len) { state = state_title_err; err = err_parse_title; } int ret = 0; char *ch = offset+cursor; char *lim = offset+len-1; switch (state) { case state_init: state = state_title_method; break; case state_title_method: if ((ret = cmp_orig(ch, "GET", lim))) { cursor += ret; state = state_title_after_method; method = method_get; break; } if ((ret = cmp_orig(ch, "POST", lim))) { cursor += ret; state = state_title_after_method; method = method_post; break; } if ((ret = cmp_orig(ch, "HEAD", lim))) { cursor += ret; state = state_title_after_method; method = method_head; break; } state = state_title_err; err = err_parse_title_method; break; case state_title_after_method: cursor++; state = state_title_uri; break; case state_title_uri: if ((ret = cmp_ascii(ch, lim)) <= 0) { state = state_title_err; err = err_parse_title_uri; break; } if (!(uri = strndup(ch, ret))) { state = state_title_err; err = err_memory; break; } uri_len = ret; cursor += ret; state = state_title_after_uri; break; case state_title_after_uri: cursor++; state = state_title_version; break; case state_title_version: if ((ret = cmp_ascii(ch, lim)) <= 0) { state = state_title_err; err = err_parse_title_version; break; } if (!(ver = strndup(ch, ret))) { state = state_title_err; err = err_memory; break; } ver_len = ret; cursor += ret; state = state_title_ok; break; case state_title_ok: for (;ch < lim;ch++) { if (*ch == ' ') continue; if (*ch == '\t') continue; if (*ch == '\0') continue; if (*ch == '\r') continue; state = state_title_err; err = err_parse_title; break; } break; case state_title_err: fprintf(stderr, "failed\n"); return -1; break; default: break; } } return 0; } int parse_request(char *buffer) { int ret; char *buffer_limit = buffer+strlen(buffer); char *title_offset = buffer; int title_len = read_line(&buffer, &buffer_limit); if ((ret = parse_title(title_offset, title_len)) < 0) { fprintf(stderr, "Failed parsing title\n"); return -1; } for (int bound = 0; bound < MAX_BOUND; bound++) { char *header_offset = buffer; int header_len = read_line(&buffer, &buffer_limit); char *header_limit = header_offset+header_len; // IF END OF MESSAGE if (!header_len) { state = state_fin; break; } if ((ret = parse_header(header_offset, header_len)) < 0) { fprintf(stderr, "Failed parsing header\n"); return -1; } } free(uri); free(ver); return 0; } int main(void) { int ret; char *str = strdup(TEST_ONE); header_table = (char **) calloc(header_count, sizeof(char *)); if (!header_table) { fprintf(stderr, "Not enough dynamic memory\n"); return -1; } header_tree = allocnod(); if (!header_tree) { fprintf(stderr, "Not enough dynamic memory\n"); return -1; } ret = gentree(header_tree, headers, NULL); if (gentree < 0) { fprintf(stderr, "Failed generating the header comparison tree\n"); return -1; } ret = parse_request(str); if (ret < 0) { fprintf(stderr, "Failed parsing request\n"); return -1; } fprintf(stderr, "Finished parsing request\n"); frenod(header_tree); free(header_table); free(str); return 0; }