chibipub

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit a063e39067588c7ec8d75a4528a8ad3a5e6b499b
parent 6832d4043024ccc6d9d796e7e5b1c6bfc3c57b19
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 19 Nov 2020 11:52:46 -0800

header parsing

Diffstat:
Msrc/wolfsocks.c | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 125 insertions(+), 21 deletions(-)

diff --git a/src/wolfsocks.c b/src/wolfsocks.c @@ -8,18 +8,14 @@ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <ctype.h> +#include <assert.h> #include "cursor.h" #define BUF_SIZE 4096 #define ARENA_SIZE 8192 -struct http_req { - char *method; - char *path; - char *ver; -}; - struct parser { struct cursor cur; struct cursor arena; @@ -28,15 +24,24 @@ struct parser { struct http_header { char *name; char *value; + struct http_header *next; }; -static void error(char *msg) +struct http_req { + char *method; + char *path; + char *ver; + struct http_header *headers; +}; + +static void error(char *msg) { perror(msg); exit(1); } -static int parse_segment(struct parser *p, char **seg) + +static int parse_segment_with(struct parser *p, char **seg, char delim) { char c; @@ -46,20 +51,55 @@ static int parse_segment(struct parser *p, char **seg) if (!pull_byte(&p->cur, (unsigned char*)&c)) return 0; - if (c == ' ' || c == '\r' || c == '\n') { + if (c == delim) { if (!push_byte(&p->arena, 0)) return 0; - break; - } else { - if (!push_byte(&p->arena, c)) - return 0; + return 1; } + + if (!push_byte(&p->arena, c)) + return 0; } return 1; } -static int parse_header_segment(struct http_req *req, struct parser *p) +static int consume_char(struct cursor *cur, char match) +{ + char c; + return pull_byte(cur, (unsigned char*)&c) && c == match; +} + +static int parse_segment(struct parser *p, char **seg) +{ + return parse_segment_with(p, seg, ' '); +} + +static int parse_last_segment(struct parser *p, char **seg) +{ + if (!parse_segment_with(p, seg, '\r')) + return 0; + + /* don't consume crlf yet */ + p->cur.p--; + + return 1; +} + +static int parse_header_name(struct parser *p, char **name) +{ + if (!parse_segment_with(p, name, ':')) + return 0; + + return consume_char(&p->cur, ' '); +} + +static int consume_crlf(struct cursor *cur) +{ + return consume_char(cur, '\r') && consume_char(cur, '\n'); +} + +static int parse_request_line(struct http_req *req, struct parser *p) { if (!parse_segment(p, &req->method)) return 0; @@ -67,23 +107,85 @@ static int parse_header_segment(struct http_req *req, struct parser *p) if (!parse_segment(p, &req->path)) return 0; - if (!parse_segment(p, &req->ver)) + if (!parse_last_segment(p, &req->ver)) return 0; - return 1; + return consume_crlf(&p->cur); +} + +static int parse_header(struct http_header **prev, struct parser *p) +{ + struct http_header next; + struct http_header *next_p; + next.next = NULL; + + assert(*prev == NULL || !(*prev)->next); + + printf("parsing header name...\n"); + + if (!parse_header_name(p, &next.name)) + return 0; + + printf("got header name: %s\n", next.name); + + if (!parse_last_segment(p, &next.value)) + return 0; + + printf("got header value: %s\n", next.value); + + next_p = (struct http_header *)p->arena.p; + + if (!push_data(&p->arena, (unsigned char*)&next, sizeof(next))) + return 0; + + if (*prev == NULL) + *prev = next_p; + else + (*prev)->next = next_p; + + printf("consuming crlf: %.*s\n", 2, p->cur.p); + + return consume_crlf(&p->cur); } + static int parse_http_request(struct http_req *req, struct parser *p) { - return parse_header_segment(req, p); + struct http_header **header; + struct cursor back; + + if (!parse_request_line(req, p)) + return 0; + + printf("got request line\n"); + + header = &req->headers; + + while (1) { + copy_cursor(&p->cur, &back); + if (!parse_header(header, p)) { + copy_cursor(&back, &p->cur); + break; + } + header = &(*header)->next; + } + + printf("after headers: %.*s\n", 5, p->cur.p); + + return consume_crlf(&p->cur); } static void print_http_request(struct http_req *req) { + struct http_header *header; printf("%s %s %s\r\n", req->method, req->path, req->ver); + header = req->headers; + for (; header; header = header->next) { + printf("%s: %s\n", header->name, header->value); + } } -void run_http_server() +void run_http_server() { static unsigned char arena[ARENA_SIZE]; static unsigned char buffer[BUF_SIZE]; @@ -98,6 +200,7 @@ void run_http_server() int optval; struct http_req req; + memset(&req, 0, sizeof(req)); struct parser parser; @@ -111,7 +214,7 @@ void run_http_server() } optval = 1; - setsockopt(parent, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, + setsockopt(parent, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(optval)); memset(&server_addr, 0, sizeof(server_addr)); @@ -158,8 +261,9 @@ void run_http_server() if (len == 0) { break; } - + if (parse_http_request(&req, &parser)) { + printf("\nPARSED:\n\n"); print_http_request(&req); } @@ -179,7 +283,7 @@ void run_http_server() } } -int main(int argc, char *argv[]) +int main(int argc, char *argv[]) { run_http_server();