var socket = use('socket') var c_http = use('net/http') def CRLF = "\r\n" def status_texts = { "200": "OK", "201": "Created", "204": "No Content", "400": "Bad Request", "401": "Unauthorized", "403": "Forbidden", "404": "Not Found", "405": "Method Not Allowed", "500": "Internal Server Error" } function serve(port) { var fd = socket.socket("AF_INET", "SOCK_STREAM") socket.setsockopt(fd, "SOL_SOCKET", "SO_REUSEADDR", true) socket.bind(fd, {address: "127.0.0.1", port: port}) socket.listen(fd, 16) return fd } function parse_request(conn_fd) { var data = socket.recv(conn_fd, 65536) var raw = text(data) var hdr_end = search(raw, CRLF + CRLF) if (hdr_end == null) disrupt var header_text = text(raw, 0, hdr_end) var body_text = text(raw, hdr_end + 4) var lines = array(header_text, CRLF) var parts = array(lines[0], " ") var method = parts[0] var url = parts[1] var qpos = search(url, "?") var path = qpos != null ? text(url, 0, qpos) : url var headers = {} var i = 1 var colon = null var key = null var val = null while (i < length(lines)) { colon = search(lines[i], ": ") if (colon != null) { key = lower(text(lines[i], 0, colon)) val = text(lines[i], colon + 2) headers[key] = val } i = i + 1 } var cl = headers["content-length"] var content_length = null var remaining = null var more = null if (cl != null) content_length = number(cl) if (content_length != null && length(body_text) < content_length) { remaining = content_length - length(body_text) more = socket.recv(conn_fd, remaining) body_text = body_text + text(more) } if (content_length == null || content_length == 0) body_text = null return { method: method, path: path, url: url, headers: headers, body: body_text, _conn: conn_fd } } function accept(server_fd) { var conn = socket.accept(server_fd) return parse_request(conn.socket) } function on_request(server_fd, handler) { var _accept = function() { var conn = socket.accept(server_fd) var req = null var _parse = function() { req = parse_request(conn.socket) } disruption { req = null } _parse() if (req != null) handler(req) socket.on_readable(server_fd, _accept) } socket.on_readable(server_fd, _accept) } function respond(conn, status, headers, body) { var st = status_texts[text(status)] if (st == null) st = "Unknown" var out = "HTTP/1.1 " + text(status) + " " + st + CRLF out = out + "Connection: close" + CRLF var body_str = "" var keys = null var i = 0 if (body != null) { if (is_text(body)) body_str = body else body_str = text(body) } if (headers != null) { keys = array(headers) i = 0 while (i < length(keys)) { out = out + keys[i] + ": " + headers[keys[i]] + CRLF i = i + 1 } } out = out + "Content-Length: " + text(length(body_str)) + CRLF out = out + CRLF + body_str socket.send(conn, out) socket.close(conn) } function sse_open(conn, headers) { var out = "HTTP/1.1 200 OK" + CRLF out = out + "Content-Type: text/event-stream" + CRLF out = out + "Cache-Control: no-cache" + CRLF out = out + "Connection: keep-alive" + CRLF var keys = null var i = 0 if (headers != null) { keys = array(headers) i = 0 while (i < length(keys)) { out = out + keys[i] + ": " + headers[keys[i]] + CRLF i = i + 1 } } out = out + CRLF socket.send(conn, out) } function sse_event(conn, event, data) { var frame = "event: " + event + "\ndata: " + data + "\n\n" var ok = true var _send = function() { socket.send(conn, frame) } disruption { ok = false } _send() return ok } function sse_close(conn) { socket.close(conn) } function close(fd) { socket.close(fd) } return { serve: serve, accept: accept, on_request: on_request, respond: respond, sse_open: sse_open, sse_event: sse_event, sse_close: sse_close, close: close, fetch: c_http.fetch }