Skip to content

Commit

Permalink
Add support for building with llhttp instead of http-parser
Browse files Browse the repository at this point in the history
As http-parser has been unmaintained for a while [1], let's add
support for its natural replacement, llhttp.

However, as llhttp does not seem to be packaged in distros like
Debian [2], we will keep supporting building with http-parser for
time being, preferring llhttp, if it is present.

[1] nodejs/http-parser#522
[2] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=977716
  • Loading branch information
sergio-correia committed Jan 11, 2024
1 parent 9e4f9a6 commit 3054828
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 22 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/install-dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ debian:*|ubuntu:*)
echo 'max_parallel_downloads=10' >> /etc/dnf/dnf.conf
dnf -y clean all
dnf -y --setopt=deltarpm=0 update
dnf -y install gcc meson pkgconfig libjose-devel jose http-parser-devel \
dnf -y install gcc meson pkgconfig libjose-devel jose llhttp-devel \
systemd gcovr curl socat iproute
;;

Expand Down
17 changes: 13 additions & 4 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,22 @@ add_project_arguments('-DVERSION="'+meson.project_version() + '"', language : 'c
jose = dependency('jose', version: '>=8')
a2x = find_program('a2x', required: false)
compiler = meson.get_compiler('c')
if not compiler.has_header('http_parser.h',args : '-I/usr/local/include')
error('http-parser devel files not found.')

http_lib = []
if compiler.has_header('llhttp.h', args: '-I/usr/local/include')
http_lib = 'llhttp'
add_project_arguments('-DUSE_LLHTTP', language: 'c')
else
if not compiler.has_header('http_parser.h', args: '-I/usr/local/include')
error('neither llhttp nor http-parser devel files found.')
endif
http_lib = 'http_parser'
endif

if host_machine.system() == 'freebsd'
http_parser = compiler.find_library('http_parser',dirs : '/usr/local/lib')
http_parser = compiler.find_library(http_lib, dirs : '/usr/local/lib')
else
http_parser = compiler.find_library('http_parser')
http_parser = compiler.find_library(http_lib)
endif

licenses = ['COPYING']
Expand Down
10 changes: 5 additions & 5 deletions src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ HTTP_METHOD_MAP(XX)
};

static int
on_url(http_parser *parser, const char *at, size_t length)
on_url(http_parser_t *parser, const char *at, size_t length)
{
struct http_state *state = parser->data;

Expand All @@ -51,7 +51,7 @@ on_url(http_parser *parser, const char *at, size_t length)
}

static int
on_body(http_parser *parser, const char *at, size_t length)
on_body(http_parser_t *parser, const char *at, size_t length)
{
struct http_state *state = parser->data;

Expand All @@ -66,7 +66,7 @@ on_body(http_parser *parser, const char *at, size_t length)
}

static int
on_message_complete(http_parser *parser)
on_message_complete(http_parser_t *parser)
{
struct http_state *state = parser->data;
const char *addr = NULL;
Expand Down Expand Up @@ -132,15 +132,15 @@ on_message_complete(http_parser *parser)
return 0;
}

const http_parser_settings http_settings = {
const http_settings_t http_settings = {
.on_url = on_url,
.on_body = on_body,
.on_message_complete = on_message_complete,
};

int
http_reply(const char *file, int line,
enum http_status code, const char *fmt, ...)
http_status_t code, const char *fmt, ...)
{
const char *msg = NULL;
va_list ap;
Expand Down
35 changes: 31 additions & 4 deletions src/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,39 @@

#pragma once

#include <http_parser.h>
#include <sys/types.h>
#include <regex.h>

#ifdef USE_LLHTTP
#include <llhttp.h>

typedef llhttp_method_t http_method_t;
typedef llhttp_status_t http_status_t;
typedef llhttp_settings_t http_settings_t;
typedef llhttp_t http_parser_t;
#define tang_http_parser_init(parser, settings) llhttp_init(parser, HTTP_REQUEST, settings)
#define tang_http_parser_execute(parser, settings, req, rcvd) llhttp_execute(parser, req, rcvd)
#define tang_http_parser_errno(parser) parser.error
#define tang_http_errno_description(parser, errno) llhttp_get_error_reason(parser)

#else
/* Legacy http-parser. */
#include <http_parser.h>

typedef enum http_method http_method_t;
typedef enum http_status http_status_t;
typedef http_parser_settings http_settings_t;
typedef struct http_parser http_parser_t;

#define tang_http_parser_init(parser, settings) http_parser_init(parser, HTTP_REQUEST)
#define tang_http_parser_execute(parser, settings, req, rcvd) http_parser_execute(parser, settings, req, rcvd)
#define tang_http_parser_errno(parser) parser.http_errno
#define tang_http_errno_description(parser, errno) http_errno_description(errno)

#endif /* USE_LLHTTP */

struct http_dispatch {
int (*func)(enum http_method method, const char *path,
int (*func)(http_method_t method, const char *path,
const char *body, regmatch_t matches[], void *misc);
uint64_t methods;
size_t nmatches;
Expand All @@ -43,11 +70,11 @@ struct http_state {
void *misc;
};

extern const http_parser_settings http_settings;
extern const http_settings_t http_settings;

int __attribute__ ((format(printf, 4, 5)))
http_reply(const char *file, int line,
enum http_status code, const char *fmt, ...);
http_status_t code, const char *fmt, ...);

#define http_reply(code, ...) \
http_reply(__FILE__, __LINE__, code, __VA_ARGS__)
16 changes: 8 additions & 8 deletions src/tangd.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ str_cleanup(char **str)
}

static int
adv(enum http_method method, const char *path, const char *body,
adv(http_method_t method, const char *path, const char *body,
regmatch_t matches[], void *misc)
{
__attribute__((cleanup(str_cleanup))) char *adv = NULL;
Expand Down Expand Up @@ -101,7 +101,7 @@ adv(enum http_method method, const char *path, const char *body,
}

static int
rec(enum http_method method, const char *path, const char *body,
rec(http_method_t method, const char *path, const char *body,
regmatch_t matches[], void *misc)
{
__attribute__((cleanup(str_cleanup))) char *enc = NULL;
Expand Down Expand Up @@ -197,13 +197,14 @@ static int
process_request(const char *jwkdir, int in_fileno)
{
struct http_state state = { .dispatch = dispatch, .misc = (char*)jwkdir };
struct http_parser parser = { .data = &state };
http_parser_t parser;
struct stat st = {};
char req[4096] = {};
size_t rcvd = 0;
int r = 0;

http_parser_init(&parser, HTTP_REQUEST);
tang_http_parser_init(&parser, &http_settings);
parser.data = &state;

if (stat(jwkdir, &st) != 0) {
fprintf(stderr, "Error calling stat() on path: %s: %m\n", jwkdir);
Expand All @@ -224,17 +225,16 @@ process_request(const char *jwkdir, int in_fileno)

rcvd += r;

r = http_parser_execute(&parser, &http_settings, req, rcvd);
if (parser.http_errno != 0) {
r = tang_http_parser_execute(&parser, &http_settings, req, rcvd);
if (tang_http_parser_errno(parser) != 0) {
fprintf(stderr, "HTTP Parsing Error: %s\n",
http_errno_description(parser.http_errno));
tang_http_errno_description(&parser, tang_http_parser_errno(parser)));
return EXIT_SUCCESS;
}

memmove(req, &req[r], rcvd - r);
rcvd -= r;
}

return EXIT_SUCCESS;
}

Expand Down

0 comments on commit 3054828

Please sign in to comment.