Skip to content

Instantly share code, notes, and snippets.

@gkhighelf
Forked from utaal/Makefile
Created July 19, 2016 09:46
Show Gist options
  • Select an option

  • Save gkhighelf/8fe74e0964d243de711b4f6f87139c89 to your computer and use it in GitHub Desktop.

Select an option

Save gkhighelf/8fe74e0964d243de711b4f6f87139c89 to your computer and use it in GitHub Desktop.
webserver using libuv
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#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();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment