1 # ezhttp/src/step: what the server decides for one connection, kept pure so 2 # a law can state it. server.bend runs the effects and asks this module what 3 # each outcome means; it decides nothing itself. 4 import Base 5 import ./http.bend as Http 6 7 # what a request asks of the server: answer it now, or call the handler 8 type Step is Data: 9 Answer{reply: Http.Reply} 10 Call{req: Http.Request} 11 12 # an effect's outcome on one connection: the value, or the line to log for 13 # a connection that is lost 14 type Got<-A: Type> is Type: 15 Kept{value: A} 16 Lost{line: String} 17 18 # a bad request is answered 400 with its reason and never reaches the 19 # handler; a good one goes to the handler as it was parsed 20 def step.of(req: Http.Request) -> Step: 21 match req: 22 case Http.Bad{why}: 23 Answer{Http.Reply{400, [], why}} 24 case Http.Request{method, target, headers, body}: 25 Call{Http.Request{method, target, headers, body}} 26 27 # the line logged for a failed effect: `ezhttp: : ` 28 def step.line(phase: String, why: String) -> String: 29 "ezhttp: " ++ phase ++ ": " ++ why 30 31 # a failed accept or recv loses the connection instead of ending the server 32 def step.got( 33 -A: Type, 34 phase: String, 35 res: Result<&1, &1, U32 & String, A> 36 ) -> Got: 37 match res: 38 case Fail{(code, why)}: 39 Lost{step.line(phase, why)} 40 case Done{value}: 41 Kept{value} 42 43 # a failed send loses the connection too; the text it did not send is dropped 44 def step.sent(res: Result<&1, &1, (U32 & String) & String, Unit>) -> Got: 45 match res: 46 case Fail{((code, why), left)}: 47 Lost{step.line("write", why)} 48 case Done{value}: 49 Kept{value}