Skip to content

cebem1nt/httpp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

httpp

Tiny, fast, simple, yet useful header only HTTP/1.1 requests parser for C. httpp has very small codebase and is fully available to your modifications. Want to replace fixed size headers array with a hash table? all yours.

API

#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_header_t headers[HTTPP_DEFAULT_HEADERS_ARR_CAP]; // Array for parsed headers
    httpp_init_req(&parsed, headers, HTTPP_DEFAULT_HEADERS_ARR_CAP); // Initialize the request on stack

    httpp_parse_request(req, strlen(req), &parsed); // Parse the request!

    printf("%s\n", parsed.body.ptr); // Pointer to the beginning of the 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"); 
    // Httpp stores pointers to the conentent in your buffer.
    // Each string is storred as "span" or a string view. 
    // to convert it to a null terminated string (malloc'd), use this:
    char* name = httpp_span_to_str(&host->name);
    printf("%s\n", name);

    free(name); // Dont forget to free it when you're done

    httpp_res_t response;
    httpp_header_t response_headers[2]; 
    httpp_init_res(&response, response_headers, 2);

    response.code = Ok; // or 200
    httpp_res_add_header(&response, "Host", "somehost.some.where");
    httpp_header_t* status = httpp_res_add_header(&response, "Status", "ok");
    // If you try to add more headers than the capacity is, httpp_add_header will return NULL

    char* body = "Some body";
    httpp_res_set_body(&response, body, strlen(body)); // httpp_res_set_body sets the pointer to body, it doesn't copy it 

    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
    printf("Body length = %lu\n", response.body.length);

    free(raw);

    // When using httpp_res_add_header, it strdups given name and value, so make sure to free it  
    httpp_res_free_added(&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 in benchmarks directory. Same benchmark was adapted for http-parser. Results of each one is the average of 5 runs.

Benchmarked with the following request (adapted for each one from picohttp)

#define REQ                                                                                                             \
    "GET /wp-content/uploads/2010/03/hello-kitty-darth-vader-pink.jpg HTTP/1.1\r\n"                                     \
    "Host: www.kittyhell.com\r\n"                                                                                       \
    "User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; ja-JP-mac; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 "  \
    "Pathtraq/0.9\r\n"                                                                                                  \
    "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"                                       \
    "Accept-Language: ja,en-us;q=0.7,en;q=0.3\r\n"                                                                      \
    "Accept-Encoding: gzip,deflate\r\n"                                                                                 \
    "Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n"                                                                 \
    "Keep-Alive: 115\r\n"                                                                                               \
    "Connection: keep-alive\r\n"                                                                                        \
    "Cookie: wp_ozh_wsa_visits=2; wp_ozh_wsa_visit_lasttime=xxxxxxxxxx; "                                               \
    "__utma=xxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.xxxxxxxxxx.x; "                                                  \
    "__utmz=xxxxxxxxx.xxxxxxxxxx.x.x.utmccn=(referral)|utmcsr=reader.livedoor.com|utmcct=/reader/|utmcmd=referral\r\n"  \
    "\r\n"

Elapsed time

httppv1 http-parser httppv2 picohttpparser
2.788205s 9.055873s 0.964826s 2.035271s

Requests per second

httppv1 http-parser httppv2 picohttpparser
3586537.12 1104255.77 10364561.00 4913351.09

About

Tiny, fast, simple, yet useful header only HTTP/1.1 requests parser for C.

Resources

License

Stars

Watchers

Forks