#include #include #include #include "libuv/uv.h" #include "http-parser/http_parser.h" #define CHECK(r, msg) check_result(r, msg) #define UVERR(err, msg) fprintf(stderr, "%s: %s\n", msg, uv_strerror(err)) // #define LOG(msg) puts(msg); #define LOG(msg) #define LOG_ERROR(msg) puts(msg); void check_result(int r, char* msg) { if (r) { uv_err_t err = uv_last_error(); fprintf(stderr, "%s: %s\n", msg, uv_strerror(err)); exit(1); } } #define RESPONSE \ "HTTP/1.1 200 OK\r\n" \ "Content-Type: text/plain\r\n" \ "Content-Length: 12\r\n" \ "\r\n" \ "hello world\n" static uv_tcp_t server; static http_parser_settings parser_settings; static uv_buf_t resbuf; typedef struct { uv_tcp_t handle; http_parser parser; uv_req_t write_req; } client_t; void on_close(uv_handle_t* handle) { LOG("connection closed"); } uv_buf_t on_alloc(uv_tcp_t* client, size_t suggested_size) { uv_buf_t buf; buf.base = malloc(suggested_size); buf.len = suggested_size; return buf; } void on_read(uv_tcp_t* tcp, ssize_t nread, uv_buf_t buf) { size_t parsed; client_t* client = (client_t*) tcp->data; if (nread >= 0) { parsed = http_parser_execute( &client->parser, &parser_settings, buf.base, nread); if (parsed < nread) { LOG_ERROR("parse error"); uv_close((uv_handle_t*) &client->handle, on_close); } } else { uv_err_t err = uv_last_error(); if (err.code == UV_EOF) { uv_close((uv_handle_t*) tcp, on_close); } else { UVERR(err, "read"); } } free(buf.base); } void on_connect(uv_tcp_t* server_handle, int status) { int r; assert(server_handle == &server); LOG("new connection"); client_t* client = malloc(sizeof(client_t)); uv_tcp_init(&client->handle); http_parser_init(&client->parser, HTTP_REQUEST); client->parser.data = client; client->handle.data = client; r = uv_accept(server_handle, &client->handle); CHECK(r, "accept"); uv_read_start(&client->handle, on_alloc, on_read); } void after_write(uv_req_t* req, int status) { uv_close(req->handle, on_close); } int on_headers_complete(http_parser* parser) { client_t* client = (client_t*) parser->data; LOG("http message!"); uv_req_init( &client->write_req, (uv_handle_t*) &client->handle, after_write); uv_write(&client->write_req, &resbuf, 1); return 1; } int main() { int r; parser_settings.on_headers_complete = on_headers_complete; resbuf.base = RESPONSE; resbuf.len = sizeof(RESPONSE); LOG("init"); uv_init(); r = uv_tcp_init(&server); CHECK(r, "bind"); struct sockaddr_in address = uv_ip4_addr("0.0.0.0", 8000); r = uv_bind(&server, address); CHECK(r, "bind"); uv_listen(&server, 128, on_connect); LOG("listening on port 8000"); uv_run(); }