httpp-benchmark

httpp-benchmark.git
git clone git://git.lenczewski.org/httpp-benchmark.git
Log | Files | Refs | README | LICENSE

commit 46146f58b1af7185f32f03cf1afa97eb17594e2b
parent 0d29f86ea7bc1ad7ac6e4717527bca0d69e2dff1
Author: cebem1nt <mineewarik@gmail.com>
Date:   Sat, 29 Nov 2025 00:42:35 -0300

Final touches

Diffstat:
Mhttpp.h | 82+++++++++++++++++++++++++++++++++----------------------------------------------
Mtest.c | 17+++++++++--------
2 files changed, 43 insertions(+), 56 deletions(-)

diff --git a/httpp.h b/httpp.h @@ -14,7 +14,6 @@ #include <stdlib.h> #include <string.h> -#define HTTPP_LINE_BUFSIZE 4096 /* A buffer for "name: value" header parsing */ #define HTTPP_INITIAL_HEADERS_ARR_CAP 20 #define HTTPP_HEADERS_ARR_LIMIT -1 @@ -109,36 +108,25 @@ httpp_header_t* httpp_headers_append(httpp_headers_arr_t* hs, httpp_header_t hea httpp_header_t* httpp_headers_add(httpp_headers_arr_t* hs, char* name, char* value); // stdrup and httpp_headers_append httpp_res_t* httpp_res_new(); -int httpp_res_set_body(httpp_res_t* res, char* body); // strdup and res->body = dupped void httpp_res_free(httpp_res_t* res); char* httpp_res_to_raw(httpp_res_t* res); -#define HTTPP_IMPLEMENTATION #ifdef HTTPP_IMPLEMENTATION #define ltrim(str) do { \ - while (*(str) && *(str) == ' ' || *(str) == '\r' || *(str) == '\n') { \ + while ((*(str) && *(str) == ' ') || (*(str) == '\r') || (*(str) == '\n')) { \ (str)++; \ } \ } while (0) #define ltrim_buf(str, len) do { \ - while (*(str) && *(str) == ' ' || *(str) == '\r' || *(str) == '\n') { \ + while ((*(str) && *(str) == ' ') || (*(str) == '\r') || (*(str) == '\n')) { \ (str)++; \ (len)--; \ } \ } while (0) -#define rtrim(str, len) do { \ - char* __str = (str); \ - char* end = __str + len; \ - while (end >= __str && *end == ' ' || *end == '\r' || *end == '\n') { \ - *end-- = '\0'; \ - len--; \ - } \ -} while (0) - static int chop_until(char c, char** src, char* dest, size_t n) { char* pos = strchr(*src, c); @@ -256,21 +244,24 @@ httpp_req_t* httpp_req_new() void httpp_headers_arr_free(httpp_headers_arr_t* hs) { - if (!hs) return; + if (!hs) + return; for (size_t i = 0; i < hs->length; i++) { free(hs->arr[i].name); free(hs->arr[i].value); } + + free(hs->arr); + free(hs); } void httpp_req_free(httpp_req_t* req) { - if (!req) return; - httpp_headers_arr_free(req->headers); + if (!req) + return; - free(req->headers->arr); - free(req->headers); + httpp_headers_arr_free(req->headers); free(req->route); free(req->body); free(req); @@ -280,12 +271,17 @@ httpp_header_t* httpp_headers_append(httpp_headers_arr_t* hs, httpp_header_t hea { if (hs->length >= hs->capacity) { size_t new_cap = hs->capacity * 2; - if (new_cap <= hs->capacity) // Doesn't free on failure. Make a note about it + + if (new_cap <= hs->capacity) { + free(hs->arr); return NULL; + } hs->arr = (httpp_header_t*) realloc(hs->arr, new_cap * sizeof(httpp_header_t)); - if (!hs->arr) + if (!hs->arr) { + free(hs->arr); return NULL; + } hs->capacity = new_cap; } @@ -294,7 +290,7 @@ httpp_header_t* httpp_headers_append(httpp_headers_arr_t* hs, httpp_header_t hea return NULL; hs->arr[hs->length++] = header; - return &hs->arr[hs->length]; + return &hs->arr[hs->length - 1]; } httpp_header_t* httpp_headers_add(httpp_headers_arr_t* hs, char* name, char* value) @@ -307,12 +303,19 @@ httpp_header_t* httpp_headers_add(httpp_headers_arr_t* hs, char* name, char* val strdup(value) }; - return httpp_headers_append(hs, h); + httpp_header_t* out = httpp_headers_append(hs, h); + + if (out == NULL) { + free(h.name); + free(h.value); + } + + return out; } httpp_header_t* httpp_parse_header(httpp_headers_arr_t* hs, char* line, size_t content_len) { - // RFC says that header starting with whitespace should be rejected. + // RFC says that header starting with whitespace or any other non printable ascii should be rejected. if (*line == ' ' || *line == '\r' || *line == '\n') return NULL; @@ -322,7 +325,7 @@ httpp_header_t* httpp_parse_header(httpp_headers_arr_t* hs, char* line, size_t c size_t name_len = colon - line; - char* name = (char*) malloc(name_len); + char* name = (char*) malloc(name_len + 1); if (!name) return NULL; @@ -330,11 +333,11 @@ httpp_header_t* httpp_parse_header(httpp_headers_arr_t* hs, char* line, size_t c name[name_len] = '\0'; char* value_start = colon + 1; - size_t value_len = content_len - name_len-1; + size_t value_len = content_len - name_len - 1; ltrim_buf(value_start, value_len); - char* value = (char*) malloc(value_len); + char* value = (char*) malloc(value_len + 1); if (!value) { free(name); return NULL; @@ -348,19 +351,16 @@ httpp_header_t* httpp_parse_header(httpp_headers_arr_t* hs, char* line, size_t c static int parse_start_line(char** itr, httpp_req_t* dest) { - char method_buf[HTTPP_MAX_METHOD_LENGTH]; - char version_buf[HTTPP_VERSION_BUFSIZE]; + char method_buf[HTTPP_MAX_METHOD_LENGTH]; + char version_buf[HTTPP_VERSION_BUFSIZE]; char* route; - ltrim(*itr); if (chop_until(' ', itr, method_buf, HTTPP_MAX_METHOD_LENGTH) != 0) return 1; - ltrim(*itr); // Route might have extra spaces at the bginning, for our implementation thats fine if ((route = dchop_until(' ', itr)) == NULL) return 1; - ltrim(*itr); if (chop_until('\r', itr, version_buf, HTTPP_VERSION_BUFSIZE) != 0) { free(route); return 1; @@ -371,9 +371,10 @@ static int parse_start_line(char** itr, httpp_req_t* dest) return 1; } - ltrim(*itr); // remove \n left after version dest->method = (httpp_method_t) httpp_string_to_method(method_buf); dest->route = route; + + ltrim(*itr); return 0; } @@ -400,11 +401,6 @@ httpp_req_t* httpp_parse_request(char* raw) break; } - if (line_size >= HTTPP_LINE_BUFSIZE) { - httpp_req_free(out); - return NULL; - } - if (httpp_parse_header(out->headers, itr, line_size) == NULL) { httpp_req_free(out); return NULL; @@ -448,16 +444,6 @@ void httpp_res_free(httpp_res_t* res) return; httpp_headers_arr_free(res->headers); - free(res->body); -} - -int httpp_res_set_body(httpp_res_t* res, char* body) -{ - res->body = strdup(body); - if (!res->body) - return 1; - - return 0; } char* httpp_res_to_raw(httpp_res_t* res) diff --git a/test.c b/test.c @@ -28,7 +28,7 @@ void print(httpp_req_t* parsed) int main() { char* req1 = - "POST /api/items HTTP/1.1 \r\n" + "POST /api/items HTTP/1.1\r\n" "Host: api.example.com\r\n" "User-Agent: MyClient/1.0\r\n" "Content-Type: application/json\r\n" @@ -57,12 +57,12 @@ int main() char* req3 = "POST /api/items HTTP/1.1\r\n" - " Host: api.example.com\r\n" - " User-Agent : MyClient/1.0\r\n" - " Content-Type: application/json; charset=utf-8\r\n" - " Content-Length: 106\r\n" - " X-Trace-ID: ;;--TRACE--;;\r\n" - " X-Feature-Flags: ,enable-new, ,\r\n" + "Host: api.example.com\r\n" + "User-Agent: MyClient/1.0\r\n" + "Content-Type: application/json; charset=utf-8\r\n" + "Content-Length: 106\r\n" + "X-Trace-ID: ;;--TRACE--;;\r\n" + "X-Feature-Flags: ,enable-new, ,\r\n" "\r\n"; printf("--- req3 ---\n"); @@ -76,7 +76,8 @@ int main() httpp_headers_add(res->headers, "Host", "idk.me.com"); httpp_headers_add(res->headers, "Home", "pkeofkwekgfwktokwt9wt293430592304"); httpp_headers_add(res->headers, "SOmethin", "afkofkeokfoekfo"); - httpp_res_set_body(res, "{\"hello\": 123}\n"); + char* body = "{\"hello\": 123}\n"; + res->body = body; char* raw = httpp_res_to_raw(res); printf("-----------\n");