Current section
Files
Jump to
Current section
Files
src/net/http.gleam
import gleam/list
import gleam/string
import midas_utils
pub external type ListenSocket
pub external type Socket
pub external fn listen(Int) -> Result(ListenSocket, Nil) =
"net_http_native" "listen"
pub external fn accept(ListenSocket) -> Result(Socket, Nil) =
"gen_tcp" "accept"
// TODO real Error
external fn recv(Socket, length: Int, timeout: Int) -> Result(p, Nil) =
"gen_tcp" "recv"
pub external fn send(Socket, String) -> Result(Nil, Nil) =
"net_http_native" "send"
pub type HttpURI {
AbsPath(String)
}
external type AtomOrBinary
external fn atom_or_binary_to_string(AtomOrBinary) -> String =
"net_http_native" "atom_or_binary_to_string"
external type Reserved
type HttpPacket {
// method is a string because erl returns upcase atoms
HttpRequest(AtomOrBinary, HttpURI, tuple(Int, Int))
HttpHeader(Int, AtomOrBinary, Reserved, String)
HttpEoh
}
fn read_packet(socket, timeout) {
recv(socket, 0, timeout)
}
// Decode packet turns some methods/header fields into atoms
fn do_read_headers(socket, timeout, headers) {
case read_packet(socket, timeout) {
Ok(HttpEoh) -> Ok(list.reverse(headers))
Ok(HttpHeader(_, name, _, value)) -> {
let header = tuple(
string.lowercase(atom_or_binary_to_string(name)),
value,
)
let headers = [header, ..headers]
do_read_headers(socket, timeout, headers)
}
_ -> Error(Nil)
}
}
pub fn read_request_head(socket, timeout) {
case read_packet(socket, timeout) {
Ok(HttpRequest(method, http_uri, tuple(1, 1))) -> {
let method = atom_or_binary_to_string(method)
case do_read_headers(socket, timeout, []) {
Ok(headers) -> Ok(tuple(method, http_uri, headers))
_ -> Error(Nil)
}
}
_ -> Error(Nil)
}
}
pub external fn read_body(
socket,
content_length,
timeout,
) -> Result(String, Nil) =
"net_http_native" "read_body"