#import "Basic"; #import "Hash_Table"; #import "Socket"; String :: #import "String"; #load "server.jai"; consoom :: (input: *string, delimiter: string) -> string { if input.count < 1 then return "INVALID READ"; found, left, right := String.split_from_left(input.*, delimiter); input.* = right; return left; } Request :: struct { route : string; method : string; protocol : string; headers : Table(string, string); body : string; } Response :: struct { protocol : string = "HTTP/1.1"; status : int = 200; headers : Table(string, string); body : string; } parse_request :: (data: *string) -> Request { req := New(Request); req.method = consoom(data, " "); req.route = consoom(data, " "); req.protocol = consoom(data, "\n"); headers_string := consoom(data, "\r\n\r\n"); while headers_string.count > 0 { key := consoom(*headers_string, ": "); value := consoom(*headers_string, "\n"); table_add(*req.headers, key, value); } req.body = data.*; return req; } set_header :: (res: *Response, key: string, value: string) { table_add(*res.headers, key, value); } serialize_response :: (res: *Response) -> string { builder : String_Builder; print_to_builder(*builder, "% % OK", res.protocol, res.status); for v, k : res.headers { print("%: %\n", k,v); print_to_builder(*builder, "\n%: %", k, v); } print_to_builder(*builder, "\r\n\r\n"); print_to_builder(*builder, "%", res.body); return builder_to_string(*builder); } sigaction_t :: struct { sa_sigaction: (sig: s32, info: *siginfo_t, p: *void) #c_call; sa_mask: sigset_t; // Signal mask to apply. sa_flags: s32; // See signal options below. #if OS == .LINUX then sa_restorer: () #c_call; } libc :: #library,system "libc"; sigaction :: (signum: s32, act: *sigaction_t, oldact: *void) -> s32 #foreign libc; main_socket : Socket; sigset_t :: struct { __val: [16] u64; } siginfo_t :: struct { // This is not the correct size, but we don't instantiate it, so it's fine. si_signo: s32; si_errno: s32; si_code: s32; __pad0: s32; si_addr: *void; } handle_signal :: (sig: s32, info: *siginfo_t, secret: *void) #c_call { c : #Context; push_context(c) { print("Graceful exit!!!\n"); close_and_reset(*main_socket); } } main :: () { socket_init(); main_socket = socket(AF_INET, .SOCK_STREAM, .TCP); reuse : s32 = 1; setsockopt(main_socket, SOL_SOCKET, SO_REUSEADDR, *reuse, size_of(s32)); err := bind(main_socket, "127.0.0.1", 8080); if err != 0 { print("Error in binding socket: %\n", err); return; } err = listen(main_socket, 1); if err != 0 { print("Error in listening: %\n", err); return; } sa: sigaction_t; sa.sa_sigaction = handle_signal; sigaction(2, *sa, null); while true { rbuf : [2048 * 1000]u8; addr : sockaddr; addr_len : socklen_t; reqs := accept(main_socket, *addr, *addr_len); bytesRead := recv(reqs, rbuf.data, rbuf.count, 0); datastring : string; datastring.count = bytesRead; datastring.data = rbuf.data; req := parse_request(*datastring); res : Response; handler(req, *res); res_string := serialize_response(*res); send(reqs, res_string.data, xx res_string.count, 0); close_and_reset(*reqs); } }