Skip to content

Instantly share code, notes, and snippets.

@KunYi
Last active March 28, 2025 20:19
Show Gist options
  • Save KunYi/08b4741e76fccbc2d2ebc1142e8f86c0 to your computer and use it in GitHub Desktop.
Save KunYi/08b4741e76fccbc2d2ebc1142e8f86c0 to your computer and use it in GitHub Desktop.
a example for libuv + llhttp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* include libuv & llhttp */
#include <llhttp.h>
#include <uv.h>
#define DEFAULT_PORT 8080
uv_loop_t *loop;
// HTTP parser settings
llhttp_settings_t settings;
// HTTP request structure
typedef struct {
uv_tcp_t handle;
llhttp_t parser;
} client_t;
// Buffer to store received data
char buffer[4096];
static void on_alloc(uv_handle_t *handle, size_t suggested_size,
uv_buf_t *buf) {
*buf = uv_buf_init((char *)malloc(suggested_size), suggested_size);
//buf->base = (char *)malloc(suggested_size);
//buf->len = suggested_size;
}
static void on_close(uv_handle_t* handle) {
free(handle);
}
static void on_write(struct uv_write_s *req, int status) {
}
// Callback to handle HTTP request data
void on_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
client_t *client = (client_t *)stream;
if (nread > 0) {
// Parse the received data
enum llhttp_errno err = llhttp_execute(&client->parser, buf->base, nread);
if (err == HPE_OK) {
llhttp_t *parser = &client->parser;
// parsed successfully
fprintf(stdout, "Parse pass, type:%d, method:%d, status_code=%d\n",
parser->type, parser->method, parser->status_code);
if (parser->type == HTTP_REQUEST && parser->method == HTTP_GET &&
parser->status_code == 0) {
// 構建 HTTP 響應
const char *response = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 12\r\n"
"\r\n"
"Hello World!";
uv_buf_t resbuf = uv_buf_init((char *)response, strlen(response));
// 發送 HTTP 響應
uv_write_t write_req;
uv_write(&write_req, stream, &resbuf, 1, on_write);
}
} else {
fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err),
client->parser.reason);
uv_close((uv_handle_t *)&client->handle, on_close);
}
} else if (nread < 0) {
// Error or EOF
if (nread != UV_EOF) {
fprintf(stderr, "Read error %s\n", uv_strerror(nread));
}
fprintf(stdout, "UV_EOF, close the connection\n\n");
uv_close((uv_handle_t *)&client->handle, on_close);
}
free(buf->base);
}
// Callback to handle HTTP method
int on_message_begin(llhttp_t *parser) {
printf("on_message_begin HTTP method: %ul\n", parser->method);
return 0;
}
// Callback to handle URL
int on_url(llhttp_t *parser, const char *at, size_t length) {
printf("URL: %.*s\n", (int)length, at);
return 0;
}
// Callback to handle HTTP version
int on_status(llhttp_t *parser, const char *at, size_t length) {
printf("HTTP version: %.*s\n", (int)length, at);
return 0;
}
// Callback to handle header field
int on_header_field(llhttp_t *parser, const char *at, size_t length) {
printf("Header field: %.*s\n", (int)length, at);
return 0;
}
// Callback to handle header value
int on_header_value(llhttp_t *parser, const char *at, size_t length) {
printf("Header value: %.*s\n", (int)length, at);
return 0;
}
// Main callback to handle request complete
int on_message_complete(llhttp_t *parser) {
printf("Request complete\n");
return 0;
}
// Callback for new client connections
void on_new_connection(uv_stream_t *server, int status) {
if (status < 0) {
fprintf(stderr, "New connection error %s\n", uv_strerror(status));
return;
}
client_t *client = (client_t *)malloc(sizeof(client_t));
uv_tcp_init(loop, &client->handle);
if (uv_accept(server, (uv_stream_t *)client) == 0) {
llhttp_init(&client->parser, HTTP_REQUEST, &settings);
client->handle.data = client;
uv_read_start((uv_stream_t *)client, on_alloc, on_read);
} else {
uv_close((uv_handle_t *)client, on_close);
fprintf(stderr, "New connection error %s\n", uv_strerror(status));
}
}
int main() {
loop = uv_default_loop();
// Initialize HTTP parser settings
llhttp_settings_init(&settings);
settings.on_message_begin = on_message_begin;
settings.on_url = on_url;
settings.on_status = on_status;
settings.on_header_field = on_header_field;
settings.on_header_value = on_header_value;
settings.on_message_complete = on_message_complete;
// Initialize TCP server
uv_tcp_t server;
uv_tcp_init(loop, &server);
struct sockaddr_in bind_addr;
uv_ip4_addr("127.0.0.1", DEFAULT_PORT, &bind_addr);
uv_tcp_bind(&server, (const struct sockaddr *)&bind_addr, 0);
int r = uv_listen((uv_stream_t *)&server, SOMAXCONN, on_new_connection);
if (r) {
fprintf(stderr, "Listen error %s\n", uv_strerror(r));
return 1;
}
printf("Server listening on port %d...\n", DEFAULT_PORT);
return uv_run(loop, UV_RUN_DEFAULT);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment