~/bend-docscommunity

server.bend fails

raw source on the hub · import 0x5e4e2a9db839a0214ace6923b04b685b/server.bend as Server

ezhttp/server: listen, accept, parse one request, write one response. Uses Base TCP (no TLS in v0). One exchange per connection with Connection: close. Handler is a pure Request -> Reply function.

3 imports
import Base
import ./http.bend as Http
import ./cors.bend as Cors

Definitions

def server.max source · line 9 · raw

U32

default recv budget for one request message

def server.listen source · line 13 · raw

@port:U32 -> IO(Listener)

listen on a port (RFC 9112 connection establishment stays at the socket)

def server.accept.of source · line 17 · raw

@lst:Listener -> @res:Result<&1, &1, Pair(U32, String), Socket> -> IO(Pair(Listener, Socket))

unpack accept: listener stays, socket from the Result

def server.accept.un source · line 25 · raw

@pair:Pair(Listener, Result<&1, &1, Pair(U32, String), Socket>) -> IO(Pair(Listener, Socket))

def server.accept source · line 30 · raw

@listener:Listener -> IO(Pair(Listener, Socket))

def server.read.why source · line 38 · raw

String

the short-body refusal, so a partial recv can continue

def server.read.short source · line 42 · raw

@why:String -> Bool

whether this refusal is a body that has not arrived yet

def server.read.need source · line 46 · raw

@req:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> Bool

a parsed request still wants more bytes

def server.read.fuel source · line 54 · raw

Nat

how many extra recvs to chase a Content-Length

def server.read.done source · line 58 · raw

@sock:Socket -> @got:String -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))

parse what has arrived

def server.read.next source · line 62 · raw

@sock:Socket -> @got:String -> @req:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> @rest:(@_:Socket -> @_:String -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))) -> @more:Bool -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))

stop on a finished message, or ask for another recv

def server.read.grew source · line 76 · raw

@sock:Socket -> @+got:String -> @rest:(@_:Socket -> @_:String -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))) -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))

append a chunk and decide whether it completes the request

def server.read.empty source · line 85 · raw

@sock:Socket -> @got:String -> @chunk:String -> @rest:(@_:Socket -> @_:String -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))) -> @closed:Bool -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))

peer closed, or the chunk extends the buffer

def server.read.use source · line 99 · raw

@sock:Socket -> @got:String -> @+chunk:String -> @rest:(@_:Socket -> @_:String -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))) -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))

one chunk of the request message

def server.read.pass source · line 108 · raw

@sock:Socket -> @got:String -> @rest:(@_:Socket -> @_:String -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))) -> @r:Result<&1, &1, Pair(U32, String), String> -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))

the bytes from one recv

def server.read.un source · line 118 · raw

@got:String -> @rest:(@_:Socket -> @_:String -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))) -> @pair:Pair(Socket, Result<&1, &1, Pair(U32, String), String>) -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))

unpack recv's socket and result

def server.read.go source · line 128 · raw

@fuel:Nat -> @sock:Socket -> @got:String -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))

recv until Content-Length is met, the peer closes, or fuel runs out. fuel is first so the recursive call is a decreasing self-call.

def server.read source · line 140 · raw

@sock:Socket -> IO(Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request))

recv then parse an HTTP request (RFC 9112 §3)

def server.write.res source · line 144 · raw

@sock:Socket -> @r:Result<&1, &1, Pair(U32, String), Unit> -> IO(Socket)

write a structured response and keep the socket

def server.write.un source · line 148 · raw

@pair:Pair(Socket, Result<&1, &1, Pair(U32, String), Unit>) -> IO(Socket)

def server.write source · line 153 · raw

@sock:Socket -> @reply:0x5e4e2a9db839a0214ace6923b04b685b/http.Reply -> IO(Socket)

Templates

template server.dispatch source · line 161 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @req:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply

turn a bad request into 400; otherwise call the handler

template server.reply.built source · line 170 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @method:String -> @req:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply

apply HEAD body stripping once the method token is known

template server.reply source · line 175 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @req:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply

HEAD responses are written with an empty body (RFC 9110 §9.3.2)

template server.cors_reply source · line 185 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @cfg:0x5e4e2a9db839a0214ace6923b04b685b/cors.Cfg -> @+req:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply

CORS preflight or simple headers, after HEAD bodies are dropped

template server.exchange.go source · line 193 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @sock:Socket -> @req:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> IO(Unit)

after read: write the handler's reply and close

template server.exchange.un source · line 201 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @pair:Pair(Socket, 0x5e4e2a9db839a0214ace6923b04b685b/http.Request) -> IO(Unit)

template server.exchange source · line 209 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @sock:Socket -> IO(Unit)

one connection: read, handle, write, close

template server.loop.cont source · line 216 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @again:(@_:Listener -> IO(Unit)) -> @pair:Pair(Listener, Socket) -> IO(Unit)

continue after accept: exchange, then call again with the listener. again is a runtime closure so it can carry the fuel still left.

template server.loop.go source · line 226 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @fuel:Nat -> @listener:Listener -> IO(Unit)

fuel-bounded accept loop (self-recursive)

template server.loop source · line 240 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @listener:Listener -> @limit:U32 -> IO(Unit)

listen and serve up to limit connections (fuel from the limit)

template server.serve source · line 248 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @port:U32 -> @limit:U32 -> IO(Unit)

listen and serve up to limit connections

template server.once.cont source · line 257 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @pair:Pair(Listener, Socket) -> IO(Unit)

serve exactly one connection then stop

template server.once source · line 265 · raw

@-handle:(@_:0x5e4e2a9db839a0214ace6923b04b685b/http.Request -> 0x5e4e2a9db839a0214ace6923b04b685b/http.Reply) -> @port:U32 -> IO(Unit)