#include #include #include #include "tinyparser.h" 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; int read_line(char **cursor, int cursor_size) { int diff = 0; char *match = strchr(*cursor, '\n'); if (!match) match = (*cursor)+cursor_size-1; diff = match - (*cursor); *cursor += diff + 1; return diff; } 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_title(char *title_offset, int title_len) { int title_cursor = 0; while (state != state_title_ok && state != state_title_err) { if (title_cursor >= title_len) { state = state_title_err; err = err_parse_title; } int ret = 0; char *ch = title_offset+title_cursor; char *lim = title_offset+title_len-1; switch (state) { case state_init: state = state_title_method; break; case state_title_method: if ((ret = cmp_orig(ch, "GET", lim))) { title_cursor += ret; state = state_title_after_method; method = method_get; break; } if ((ret = cmp_orig(ch, "POST", lim))) { title_cursor += ret; state = state_title_after_method; method = method_post; break; } if ((ret = cmp_orig(ch, "HEAD", lim))) { title_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: title_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; title_cursor += ret; state = state_title_after_uri; break; case state_title_after_uri: title_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; title_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; 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; int buffer_size = strlen(buffer); char *title_offset = buffer; int title_len = read_line(&buffer, buffer_size); if ((ret = parse_title(title_offset, title_len)) < 0) { fprintf(stderr, "Failed parsing title\n"); return -1; } return 0; } int main(void) { int ret; char *str = strdup(TEST_ONE); ret = parse_request(str); if (ret < 0) { fprintf(stderr, "Failed parsing request\n"); return -1; } fprintf(stderr, "Finished parsing request\n"); free(str); return 0; }