httpp-benchmark

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

commit cb449cfa2b92fbdd397e35cc39656b33510d19b1
parent 46146f58b1af7185f32f03cf1afa97eb17594e2b
Author: cebem1nt <mineewarik@gmail.com>
Date:   Sat, 29 Nov 2025 13:44:26 -0300

Added README, benchmark graphs, example.c and overall improvements

Diffstat:
M.gitignore | 4++--
MREADME.md | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Abench.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dbenchmark.c | 52----------------------------------------------------
Aelapsed.svg | 2++
Aexample.c | 44++++++++++++++++++++++++++++++++++++++++++++
Mhttpp.h | 51++++++++++++++++++++++++++++++++++++++++-----------
Arequests.svg | 2++
Mtest.c | 10+++++-----
9 files changed, 217 insertions(+), 72 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,2 +1,2 @@ *.out -benchmark -\ No newline at end of file +bench +\ No newline at end of file diff --git a/README.md b/README.md @@ -1,3 +1,65 @@ # httpp +Tiny, simple, yet useful header only dynamic HTTP/1.1 requests parser for C. -WIP -\ No newline at end of file +## API + +```c +#include <stdio.h> +#include <stdlib.h> + +#define HTTPP_IMPLEMENTATION +#include "httpp.h" + +char* req = + "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" + "Content-Length: 48\r\n" + "\r\n" + "{\"name\":\"Widget\",\"quantity\":10,\"price\":9.99}"; + +int main() +{ + httpp_req_t* parsed = httpp_parse_request(req); + printf("%s\n", parsed->body); // parsed, malloc'd body + printf("%i\n", parsed->method); // Method is an enum! + + const char* method = httpp_method_to_string(parsed->method); // Method as string (e.g POST) + printf("%s\n", method); + + httpp_header_t* host = httpp_find_header(parsed, "Host"); + printf("%s\n", host->value); // api.example.com + + httpp_res_t* response = httpp_res_new(); + response->code = Ok; // or 200 + httpp_add_header(response, "Host", "somehost.some.where"); + httpp_add_header(response, "Status", "ok"); + + httpp_res_set_body(response, "Some body"); + char* raw = httpp_res_to_raw(response); // Convert to a malloc'd raw string + + printf("\nComposed response: \n"); + printf("----\n%s\n----\n", raw); // Or write it to a socket + + // Don't forget to free everything + httpp_req_free(parsed); // Free parsed request + httpp_res_free(response); // Free response structure + free(raw); // Free composed raw response +} +``` + +## Benchmark +All benchmarks were compiled with -O3 flag using gcc _15.2.1 20251112_. Benchmarks were running on a Ryzen 7 with 4.79GHz peek frequency. The code can be found [here](./bench.c). Same benchmark was adapted for http-parser. Results of each one is the average of 5 runs + +![Elapsed time](./elapsed.svg) + +| http-parser | httpp | picohttpparser | +| ----------- | ----------- | -------------- | +| `5.344527s` | `3.058964s` | `2.005615s` | + +![Requests per second](./requests.svg) + +| http-parser | httpp | picohttpparser | +| ------------- | ------------- | -------------- | +| `1871702.306` | `3269700.736` | `4986831.824` | +\ No newline at end of file diff --git a/bench.c b/bench.c @@ -0,0 +1,58 @@ +// A benchmark adapted from https://github.com/h2o/picohttpparser + +#include <assert.h> +#include <stdio.h> +#include <time.h> +#include <string.h> + +#define HTTPP_IMPLEMENTATION +#include "httpp.h" + +#define REQ \ +"GET /cookies HTTP/1.1\r\n" \ +"Host: 127.0.0.1:8090\r\n" \ +"Connection: keep-alive\r\n" \ +"Cache-Control: max-age=0\r\n" \ +"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" \ +"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17\r\n" \ +"Accept-Encoding: gzip,deflate,sdch\r\n" \ +"Accept-Language: en-US,en;q=0.8\r\n" \ +"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n" \ +"Cookie: name=wookie\r\n" \ +"\r\n" + +#define ITERATIONS 10000000 + +double now_seconds() +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec + ts.tv_nsec / 1e9; +} + +int main() +{ + char* raw = REQ; + size_t raw_len = strlen(raw); + int i; + + double t0 = now_seconds(); + for (i = 0; i < ITERATIONS; ++i) { + httpp_req_t* req = httpp_parse_request(raw); + if (!req) { + fprintf(stderr, "parse failed at iter %d\n", i); + return 1; + } + + httpp_req_free(req); + } + double t1 = now_seconds(); + + double elapsed = t1 - t0; + double reqs_per_second = (double) ITERATIONS / elapsed; + + printf("Elapsed %f seconds.\n", elapsed); + printf("Requests per second ≈ %.2f \n", reqs_per_second); + + return 0; +} diff --git a/benchmark.c b/benchmark.c @@ -1,52 +0,0 @@ -// A benchmark adapted from https://github.com/fukamachi/fast-http - -#include <assert.h> -#include <stdio.h> -#include <time.h> -#include <string.h> - -#define HTTPP_IMPLEMENTATION -#include "httpp.h" - -#define REQ \ -"GET /cookies HTTP/1.1\r\n" \ -"Host: 127.0.0.1:8090\r\n" \ -"Connection: keep-alive\r\n" \ -"Cache-Control: max-age=0\r\n" \ -"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" \ -"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17\r\n" \ -"Accept-Encoding: gzip,deflate,sdch\r\n" \ -"Accept-Language: en-US,en;q=0.8\r\n" \ -"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n" \ -"Cookie: name=wookie\r\n" \ -"\r\n" - -#define ITERATIONS 10000000 - -double now_seconds(void) -{ - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec + ts.tv_nsec / 1e9; -} - -int main(void) { - char* raw = REQ; - size_t raw_len = strlen(raw); - int i; - - double t0 = now_seconds(); - for (i = 0; i < ITERATIONS; ++i) { - httpp_req_t* req = httpp_parse_request(raw); - if (!req) { - fprintf(stderr, "parse failed at iter %d\n", i); - return 1; - } - - httpp_req_free(req); - } - double t1 = now_seconds(); - - printf("Elapsed %f seconds.\n", t1 - t0); - return 0; -} diff --git a/elapsed.svg b/elapsed.svg @@ -0,0 +1 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink" width="600" height="390" style="overflow: hidden;" aria-label="A chart."><defs id="_ABSTRACT_RENDERER_ID_534"><clipPath id="_ABSTRACT_RENDERER_ID_535"><rect x="115" y="75" width="371" height="241"></rect></clipPath><filter id="_ABSTRACT_RENDERER_ID_536"><feGaussianBlur in="SourceAlpha" stdDeviation="2"></feGaussianBlur><feOffset dx="1" dy="1"></feOffset><feComponentTransfer><feFuncA type="linear" slope="0.1"></feFuncA></feComponentTransfer><feMerge><feMergeNode></feMergeNode><feMergeNode in="SourceGraphic"></feMergeNode></feMerge></filter></defs><rect x="0" y="0" width="600" height="390" stroke="none" stroke-width="0" fill="#ffffff"></rect><g><text text-anchor="start" x="115" y="52.05" font-family="Arial" font-size="13" font-weight="bold" stroke="none" stroke-width="0" fill="#000000">Elapsed time (10 000 000 iterations)</text><rect x="115" y="41" width="371" height="13" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></rect></g><g><rect x="115" y="75" width="371" height="241" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></rect><g clip-path="url(https://www.rapidtables.com/tools/bar-graph.html#_ABSTRACT_RENDERER_ID_535)"><g><rect x="115" y="315" width="371" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="115" y="213" width="371" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="115" y="162" width="371" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="115" y="126" width="371" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="115" y="98" width="371" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="115" y="75" width="371" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="115" y="226" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="201" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="190" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="180" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="171" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="154" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="146" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="139" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="132" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="120" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="114" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="108" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="103" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="93" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="88" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="84" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="79" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect></g><g><rect x="139" y="91" width="76" height="224" stroke="none" stroke-width="0" fill="#3584e4"></rect><rect x="262" y="161" width="77" height="154" stroke="none" stroke-width="0" fill="#3584e4"></rect><rect x="386" y="214" width="76" height="101" stroke="none" stroke-width="0" fill="#3584e4"></rect></g><g><rect x="115" y="315" width="371" height="1" stroke="none" stroke-width="0" fill="#333333"></rect></g></g><g></g><g><g><text text-anchor="middle" x="177.16666666666666" y="335.05" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">http-parser</text></g><g><text text-anchor="middle" x="300.5" y="335.05" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">httpp</text></g><g><text text-anchor="middle" x="423.8333333333333" y="335.05" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">picohttpparser</text></g><g><text text-anchor="end" x="102" y="319.55" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">0</text></g><g><text text-anchor="end" x="102" y="218.23350000000002" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">2</text></g><g><text text-anchor="end" x="102" y="167.2341" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">3</text></g><g><text text-anchor="end" x="102" y="131.0494" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">4</text></g><g><text text-anchor="end" x="102" y="102.9824" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">5</text></g><g><text text-anchor="end" x="102" y="80.05" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">6</text></g></g></g><g><g><text text-anchor="middle" x="300.5" y="368.05" font-family="Arial" font-size="13" font-style="italic" stroke="none" stroke-width="0" fill="#222222">Parsers</text><rect x="115" y="357" width="371" height="13" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></rect></g><g><text text-anchor="middle" x="52.05" y="195.5" font-family="Arial" font-size="13" font-style="italic" transform="rotate(-90 52.05 195.5)" stroke="none" stroke-width="0" fill="#222222">Seconds</text><path d="M40.99999999999999,316L41.00000000000001,75L54.00000000000001,75L53.99999999999999,316Z" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></path></g></g><g></g></svg> +\ No newline at end of file diff --git a/example.c b/example.c @@ -0,0 +1,43 @@ +#include <stdio.h> +#include <stdlib.h> + +#define HTTPP_IMPLEMENTATION +#include "httpp.h" + +char* req = + "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" + "Content-Length: 48\r\n" + "\r\n" + "{\"name\":\"Widget\",\"quantity\":10,\"price\":9.99}"; + +int main() +{ + httpp_req_t* parsed = httpp_parse_request(req); + printf("%s\n", parsed->body); // parsed, malloc'd body + printf("%i\n", parsed->method); // Method is an enum! + + const char* method = httpp_method_to_string(parsed->method); // Method as string (e.g POST) + printf("%s\n", method); + + httpp_header_t* host = httpp_find_header(parsed, "Host"); + printf("%s\n", host->value); // api.example.com + + httpp_res_t* response = httpp_res_new(); + response->code = Ok; // or 200 + httpp_add_header(response, "Host", "somehost.some.where"); + httpp_add_header(response, "Status", "ok"); + + httpp_res_set_body(response, "Some body"); + char* raw = httpp_res_to_raw(response); // Convert to a malloc'd raw string + + printf("\nComposed response: \n"); + printf("----\n%s\n----\n", raw); // Or write it to a socket + + // Don't forget to free everything + httpp_req_free(parsed); // Free parsed request + httpp_res_free(response); // Free response structure + free(raw); // Free composed raw response +} +\ No newline at end of file diff --git a/httpp.h b/httpp.h @@ -4,8 +4,7 @@ * Pipelined requests are not supported because nobody realy cares about them * (https://en.wikipedia.org/wiki/HTTP_pipelining#Implementation_status) * - * Chunked transfer is not really supported - * + * TODO Chunked transfer is not really supported * TODO Folded headers aren't handled. */ @@ -98,18 +97,26 @@ const char* httpp_status_to_string(httpp_status_t s); httpp_req_t* httpp_req_new(); void httpp_req_free(httpp_req_t* req); -httpp_req_t* httpp_parse_request(char* raw); +httpp_req_t* httpp_parse_request(char* raw); httpp_header_t* httpp_parse_header(httpp_headers_arr_t* hs, char* line, size_t content_len); httpp_headers_arr_t* httpp_headers_arr_new(); +httpp_header_t* httpp_headers_arr_append(httpp_headers_arr_t* hs, httpp_header_t header); +httpp_header_t* httpp_headers_arr_add(httpp_headers_arr_t* hs, char* name, char* value); // stdrup and httpp_headers_arr_append +httpp_header_t* httpp_headers_arr_find(httpp_headers_arr_t* hs, char* name); void httpp_headers_arr_free(httpp_headers_arr_t* hs); -httpp_header_t* httpp_headers_append(httpp_headers_arr_t* hs, httpp_header_t header); -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(); -void httpp_res_free(httpp_res_t* res); +int httpp_res_set_body(httpp_res_t* res, char* body); // strdup body and set it char* httpp_res_to_raw(httpp_res_t* res); +void httpp_res_free(httpp_res_t* res); + +#define httpp_add_header(req_or_res, name, value) \ + (httpp_headers_arr_add((req_or_res)->headers, name, value)) + +#define httpp_find_header(req_or_res, name) \ + (httpp_headers_arr_find((req_or_res)->headers, name)) #ifdef HTTPP_IMPLEMENTATION @@ -209,7 +216,6 @@ const char* httpp_status_to_string(httpp_status_t s) } } - httpp_headers_arr_t* httpp_headers_arr_new() { httpp_headers_arr_t* out = (httpp_headers_arr_t*) malloc(sizeof(httpp_headers_arr_t)); @@ -267,7 +273,7 @@ void httpp_req_free(httpp_req_t* req) free(req); } -httpp_header_t* httpp_headers_append(httpp_headers_arr_t* hs, httpp_header_t header) +httpp_header_t* httpp_headers_arr_append(httpp_headers_arr_t* hs, httpp_header_t header) { if (hs->length >= hs->capacity) { size_t new_cap = hs->capacity * 2; @@ -293,7 +299,19 @@ httpp_header_t* httpp_headers_append(httpp_headers_arr_t* hs, httpp_header_t hea return &hs->arr[hs->length - 1]; } -httpp_header_t* httpp_headers_add(httpp_headers_arr_t* hs, char* name, char* value) +httpp_header_t* httpp_headers_arr_find(httpp_headers_arr_t* hs, char* name) +{ + // For the sake of simplicity and minimalism, it's just a for loop. No hash table here. + for (size_t i = 0; i < hs->length; i++) { + if (strcmp(hs->arr[i].name, name) == 0) + return &hs->arr[i]; + } + + return NULL; +} + + +httpp_header_t* httpp_headers_arr_add(httpp_headers_arr_t* hs, char* name, char* value) { if (!name || !value) return NULL; @@ -303,7 +321,7 @@ httpp_header_t* httpp_headers_add(httpp_headers_arr_t* hs, char* name, char* val strdup(value) }; - httpp_header_t* out = httpp_headers_append(hs, h); + httpp_header_t* out = httpp_headers_arr_append(hs, h); if (out == NULL) { free(h.name); @@ -346,7 +364,7 @@ httpp_header_t* httpp_parse_header(httpp_headers_arr_t* hs, char* line, size_t c memcpy(value, value_start, value_len); value[value_len] = '\0'; - return httpp_headers_append(hs, (httpp_header_t){name, value}); + return httpp_headers_arr_append(hs, (httpp_header_t){name, value}); } static int parse_start_line(char** itr, httpp_req_t* dest) @@ -438,12 +456,23 @@ httpp_res_t* httpp_res_new() return out; } +int httpp_res_set_body(httpp_res_t* res, char* body) +{ + char* content = strdup(body); + if (!content) + return 1; + + res->body = content; + return 0; +} + void httpp_res_free(httpp_res_t* res) { if (!res) return; httpp_headers_arr_free(res->headers); + free(res->body); } char* httpp_res_to_raw(httpp_res_t* res) diff --git a/requests.svg b/requests.svg @@ -0,0 +1 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink" width="600" height="390" style="overflow: hidden;" aria-label="A chart."><defs id="_ABSTRACT_RENDERER_ID_974"><clipPath id="_ABSTRACT_RENDERER_ID_975"><rect x="115" y="75" width="371" height="241"></rect></clipPath><filter id="_ABSTRACT_RENDERER_ID_976"><feGaussianBlur in="SourceAlpha" stdDeviation="2"></feGaussianBlur><feOffset dx="1" dy="1"></feOffset><feComponentTransfer><feFuncA type="linear" slope="0.1"></feFuncA></feComponentTransfer><feMerge><feMergeNode></feMergeNode><feMergeNode in="SourceGraphic"></feMergeNode></feMerge></filter></defs><rect x="0" y="0" width="600" height="390" stroke="none" stroke-width="0" fill="#ffffff"></rect><g><text text-anchor="start" x="115" y="52.05" font-family="Arial" font-size="13" font-weight="bold" stroke="none" stroke-width="0" fill="#000000">Parsed requests per second</text><rect x="115" y="41" width="371" height="13" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></rect></g><g><rect x="115" y="75" width="371" height="241" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></rect><g clip-path="url(https://www.rapidtables.com/tools/bar-graph.html#_ABSTRACT_RENDERER_ID_975)"><g><rect x="115" y="315" width="371" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="115" y="198" width="371" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="115" y="143" width="371" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="115" y="105" width="371" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="115" y="75" width="371" height="1" stroke="none" stroke-width="0" fill="#cccccc"></rect><rect x="115" y="219" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="212" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="204" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="191" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="185" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="179" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="173" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="168" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="162" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="157" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="153" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="148" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="139" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="135" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="131" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="127" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="123" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="119" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="115" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="112" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="108" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="102" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="98" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="95" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="92" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="89" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="86" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="83" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="80" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect><rect x="115" y="78" width="371" height="1" stroke="none" stroke-width="0" fill="#ebebeb"></rect></g><g><rect x="139" y="207" width="76" height="108" stroke="none" stroke-width="0" fill="#3584e4"></rect><rect x="262" y="133" width="77" height="182" stroke="none" stroke-width="0" fill="#3584e4"></rect><rect x="386" y="76" width="76" height="239" stroke="none" stroke-width="0" fill="#3584e4"></rect></g><g><rect x="115" y="315" width="371" height="1" stroke="none" stroke-width="0" fill="#333333"></rect></g></g><g></g><g><g><text text-anchor="middle" x="177.16666666666666" y="335.05" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">http-parser</text></g><g><text text-anchor="middle" x="300.5" y="335.05" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">httpp</text></g><g><text text-anchor="middle" x="423.8333333333333" y="335.05" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#222222">picohttpparser</text></g><g><text text-anchor="end" x="102" y="319.55" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">0</text></g><g><text text-anchor="end" x="102" y="202.5873" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">2,000,000</text></g><g><text text-anchor="end" x="102" y="148.36370000000002" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">3,000,000</text></g><g><text text-anchor="end" x="102" y="109.89139999999999" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">4,000,000</text></g><g><text text-anchor="end" x="102" y="80.05" font-family="Arial" font-size="13" stroke="none" stroke-width="0" fill="#444444">5,000,000</text></g></g></g><g><g><text text-anchor="middle" x="300.5" y="368.05" font-family="Arial" font-size="13" font-style="italic" stroke="none" stroke-width="0" fill="#222222">Parsers</text><rect x="115" y="357" width="371" height="13" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></rect></g><g><text text-anchor="middle" x="26.55" y="195.5" font-family="Arial" font-size="13" font-style="italic" transform="rotate(-90 26.55 195.5)" stroke="none" stroke-width="0" fill="#222222">Requests</text><path d="M15.499999999999991,316L15.500000000000005,75L28.500000000000007,75L28.499999999999993,316Z" stroke="none" stroke-width="0" fill-opacity="0" fill="#ffffff"></path></g></g><g></g></svg> +\ No newline at end of file diff --git a/test.c b/test.c @@ -73,11 +73,11 @@ int main() httpp_res_t* res = httpp_res_new(); res->code = 200; - httpp_headers_add(res->headers, "Host", "idk.me.com"); - httpp_headers_add(res->headers, "Home", "pkeofkwekgfwktokwt9wt293430592304"); - httpp_headers_add(res->headers, "SOmethin", "afkofkeokfoekfo"); - char* body = "{\"hello\": 123}\n"; - res->body = body; + httpp_headers_arr_add(res->headers, "Host", "idk.me.com"); + httpp_headers_arr_add(res->headers, "Home", "pkeofkwekgfwktokwt9wt293430592304"); + httpp_headers_arr_add(res->headers, "SOmethin", "afkofkeokfoekfo"); + + httpp_res_set_body(res, "{\"hello\": 123}\n"); char* raw = httpp_res_to_raw(res); printf("-----------\n");