Lindenii Project Forge
Login

hare-ev

Temporary fork of hare-ev for... reasons

Warning: Due to various recent migrations, viewing non-HEAD refs may be broken.

/cmd/httpserv/main.ha (raw)

use errors;
use ev;
use ev::server;
use fmt;
use io;
use log;
use memio;
use net::http;
use net::ip;
use net::tcp;
use net;
use os;
use unix::signal;

type state = struct {
	loop: *ev::loop,
	exit: int,
};

export fn main() void = {
	const loop = ev::newloop()!;
	defer ev::finish(&loop);

	const sock = match (ev::listen_tcp(&loop, ip::LOCAL_V4, 8080, tcp::reuseaddr)) {
	case let err: net::error =>
		log::fatalf("Error: listen: {}", net::strerror(err));
	case let err: errors::error =>
		log::fatalf("Error: listen: {}", errors::strerror(err));
	case let sock: *ev::file =>
		yield sock;
	};
	defer ev::close(sock);

	let state = state {
		loop = &loop,
		...
	};
	const server = server::http_serve(sock, &http_serve, &state)!;
	defer server::server_finish(server);

	const sig = ev::signal(&loop, &signal, signal::sig::INT, signal::sig::TERM)!;
	defer ev::close(sig);
	ev::setuser(sig, &state);

	log::println("Listening on 127.0.0.1:8080");
	for (ev::dispatch(&loop, -1)!) void;
	os::exit(state.exit);
};

fn signal(file: *ev::file, sig: signal::sig) (void | nomem) = {
	log::printfln("Exiting due to {}", signal::signame(sig));
	const state = ev::getuser(file): *state;
	ev::stop(state.loop);
};

fn http_serve(
	user: nullable *opaque,
	req: http::request,
	rw: http::response_writer
) void = {
	const state = user: *state;

	const (ip, port) = http::peeraddr(&rw);
	log::printfln("Serving from {}:{}", ip::string(ip), port);

	const buf = memio::dynamic();
	defer io::close(&buf)!;

	fmt::fprintfln(&buf, "Method: {}", req.method)!;
	fmt::fprintfln(&buf, "Path: {}", req.target.path)!;
	fmt::fprintfln(&buf, "Fragment: {}", req.target.fragment)!;
	fmt::fprintfln(&buf, "Query: {}", req.target.query)!;
	fmt::fprintfln(&buf, "Headers:")!;
	http::write_header(&buf, &req.header)!;
	fmt::fprintln(&buf)!;
	io::copy(&buf, req.body)!;

	io::seek(&buf, 0, io::whence::SET)!;

	http::response_add_header(&rw, "Content-Type", "text/plain")!;
	http::response_set_body(&rw, &buf);
	http::response_write(&rw)!;
};