🎉
【C 言語】【Zig】llhttp で HTTP/1 メッセージを解析する
llhttp は Node.js で採用されている HTTP/1 パーサーである。Github からソースコードを入手してビルドしてみよう
git clone https://github.com/nodejs/llhttp.git
cd
npm ci
make
2025年リリース予定の Debian 13 Trixie では libllhttp-dev
パッケージが用意されている。
build ディレクトリに libllhttp.a
、libllhttp.so
、llhttp.h
が生成される。公式リポジトリに記載されているコードを試してみよう
#include "stdio.h"
#include "string.h"
#include "llhttp.h"
int handle_on_message_complete(llhttp_t* parser) {
fprintf(stdout, "Message completed!\n");
uint8_t method = llhttp_get_method(parser);
printf("%s\n", llhttp_method_name(method));
return 0;
}
int main() {
llhttp_t parser;
llhttp_settings_t settings;
const char* request = "GET / HTTP/1.1\r\n\r\n";
int request_len = strlen(request);
llhttp_settings_init(&settings);
settings.on_message_complete = handle_on_message_complete;
llhttp_init(&parser, HTTP_BOTH, &settings);
enum llhttp_errno err = llhttp_execute(&parser, request, request_len);
if (err == HPE_OK) {
fprintf(stdout, "Successfully parsed!\n");
} else {
fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err), parser.reason);
}
return 0;
}
ビルドして実行してみよう
zig run test.c -lc -l llhttp -L $HOME/llhttp/build -I $HOME/llhttp/build
Successfully parsed!
今度は Zig でコードを書いてみよう。コールバックの書き方は zig translate-c
で生成されたコードを参考にした
const std = @import("std");
const print = std.debug.print;
const llhttp = @cImport({
@cInclude("llhttp.h");
});
fn handle_on_message_complete(parser: [*c]llhttp.llhttp_t) callconv(.C) c_int {
print("{s}\n", .{ "Message completed!" });
const method = llhttp.llhttp_get_method(parser);
print("{s}\n", .{ llhttp.llhttp_method_name(method) });
return 0;
}
pub fn main() !void {
var parser = llhttp.llhttp_t {};
var settings = llhttp.llhttp_settings_t {};
const request = "GET / HTTP/1.1\r\n\r\n";
const request_len = request.len;
llhttp.llhttp_settings_init(&settings);
settings.on_message_complete = handle_on_message_complete;
llhttp.llhttp_init(&parser, llhttp.HTTP_BOTH, &settings);
const err = llhttp.llhttp_execute(&parser, request, request_len);
if (err == llhttp.HPE_OK) {
print("Successfully parsed!\n", .{});
} else {
print("Parse error: {s} {s}\n", .{
llhttp.llhttp_errno_name(err), parser.reason
});
}
}
ビルドと実行は次のとおり
zig run test.zig -l c -l llhttp -L $HOME/llhttp/build -I $HOME/llhttp/build
Discussion