bunkum

an old and silly c99 web server with some fun features
Log | Files | Refs | README

commit 3f66d6c58d16dd0065b63e0f9f03d947048be793
parent 11a6e4ad93d37e2479f40dddb54237b6c016d89c
Author: quantumish <freifeld.david@gmail.com>
Date:   Sun,  9 Apr 2023 16:32:05 -0700

Request parsing, minor cleanups

Diffstat:
Mhttp.c | 14++++++++++++--
Ahttp/request.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahttp/request.h | 38++++++++++++++++++++++++++++++++++++++
Mutils/log.h | 2++
Mutils/shitvec.c | 3++-
5 files changed, 108 insertions(+), 3 deletions(-)

diff --git a/http.c b/http.c @@ -20,6 +20,7 @@ #include "utils/time.h" #include "utils/shitvec.h" #include "http/response.h" +#include "http/request.h" void scuffed_htmlescape(char* dst, char* src, size_t sz) { strcpy(dst, "<pre>\n"); @@ -50,13 +51,22 @@ void scuffed_htmlescape(char* dst, char* src, size_t sz) { void* handle_conn(void* ctxt) { int ns = *(int*)ctxt; char pathbuf[MAX_PATH_SZ]; - char msgbuf[512] = {0}; + char msgbuf[1024] = {0}; while(true) { - if (recv(ns, msgbuf, 512, 0) == 0) { + if (recv(ns, msgbuf, 1024, 0) == 0) { log_info("Closing connection."); return 0x0; } if (strlen(msgbuf) > 0) { + request_t req = req_new(msgbuf, 1024); + int err = req_parse(&req); + if (err < 0) log_error("Failed to parse incoming request."); + log_debug("Req: %s, %s, %f", method_name(req.method), req.path, req.ver); + for (size_t i = 0; i < req.headers.vec_sz; i++) { + header_line_t hdr = *(header_line_t*)shitvec_get(&req.headers, i); + log_debug("Header '%s: %s'", hdr.name, hdr.value); + } + sscanf(msgbuf, "GET %s HTTP/1.1", (char*)&pathbuf); log_info("Got request for %s", pathbuf); diff --git a/http/request.c b/http/request.c @@ -0,0 +1,54 @@ +#include <stdio.h> +#include <string.h> +#include <stdint.h> + +#include "../utils/shitvec.h" +#include "request.h" + +const char* method_names[] = {"GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE"}; + +const char* method_name(enum http_method m) { + return method_names[m]; +} + +const enum http_method method_codes[] = {DELETE, CONNECT, PUT, POST, TRACE, HEAD, OPTIONS, GET}; +enum http_method method_enum(char* p) { + return method_codes[((*(uint64_t*)p*0x1b8b6e6d) % 0x100000000) >> 28]; +} + +header_line_t header_line_new() { + header_line_t hl; + memset(hl.name, 0, MAX_HEADER_NAME); + memset(hl.value, 0, MAX_HEADER_VALUE); + return hl; +} + +request_t req_new(char* reqbuf, size_t bufsize) { + request_t req; + req.buf = reqbuf; + req.bufsize = bufsize; + return req; +} + +int req_parse(request_t* req) { + char method[8] = {0}; + int matched = sscanf(req->buf, "%s %s HTTP/%f\r\n", (char*)method, (char*)req->path, &req->ver); + if (matched < 3 || matched == EOF) return -1; + req->method = method_enum((char*)method); + + req->headers = shitvec_new(sizeof(header_line_t)); + char* start = memchr(req->buf, '\n', MAX_HEADER_NAME+MAX_HEADER_VALUE)+1; + while (start+MAX_HEADER_NAME+MAX_HEADER_VALUE < req->buf+req->bufsize) { + header_line_t hdr; + int matched = sscanf(start, "%32[^:]: %s", hdr.name, hdr.value); + if (matched == 0) return 0; // No more headers; + else if (matched == 1) { + if (hdr.name[0] == '\r') return 0; // TODO sketch + return -1; // Uhh... half a header. + } + shitvec_push(&req->headers, &hdr); + start = memchr(start, '\n', MAX_HEADER_NAME+MAX_HEADER_VALUE)+1; + } + + return 0; +} diff --git a/http/request.h b/http/request.h @@ -0,0 +1,38 @@ +#ifndef REQUEST_H +#define REQUEST_H + +#include "../utils/shitvec.h" + +enum http_method { + GET, + HEAD, + POST, + PUT, + DELETE, + CONNECT, + OPTIONS, + TRACE, +}; +const char* method_name(enum http_method m); + +#define MAX_HEADER_NAME 32 +#define MAX_HEADER_VALUE 128 + +typedef struct header_line { + char name[MAX_HEADER_NAME]; + char value[MAX_HEADER_VALUE]; +} header_line_t; + +typedef struct request { + char* buf; + size_t bufsize; + enum http_method method; + char path[64]; + float ver; + shitvec_t headers; +} request_t; + +request_t req_new(char* reqbuf, size_t bufsize); +int req_parse(request_t* req); + +#endif diff --git a/utils/log.h b/utils/log.h @@ -18,5 +18,7 @@ void log_msg(enum log_level lvl, char* lvl_name, char* fmt, ...); #define log_warn(fmt, ...) log_msg(LOG_WARN, "WARN", fmt, ##__VA_ARGS__) #define log_error(fmt, ...) log_msg(LOG_ERROR, "ERROR", fmt, ##__VA_ARGS__) #define log_fatal(fmt, ...) log_msg(LOG_FATAL, "FATAL", fmt, ##__VA_ARGS__) +void log_set_min_lvl(enum log_level lvl); +void die(char* p); #endif diff --git a/utils/shitvec.c b/utils/shitvec.c @@ -20,7 +20,8 @@ void* shitvec_get(shitvec_t* sv, size_t index) { } void shitvec_push(shitvec_t* sv, void* item) { - if ((sv->arr+(sv->e_sz * sv->vec_sz)) > sv->arr+sv->alloc_sz) { + // FIXME sketchy af + if ((sv->arr+(2 * sv->e_sz * sv->vec_sz)) > sv->arr+sv->alloc_sz) { sv->arr = realloc(sv->arr, sv->alloc_sz * 2); } memcpy(sv->arr+(sv->vec_sz * sv->e_sz), item, sv->e_sz);