// Copyright (c) 2022 Nadeen Udantha . All rights reserved. package boihttp import ( "bufio" "context" "errors" "fmt" "io" "net" "os" ) type Handler func(req *Message, reqbody io.Reader, res *Message) (resbody io.Reader) func Listen(addr string, ctx context.Context, handler Handler) (err error) { var lc net.ListenConfig l, err := lc.Listen(ctx, "tcp", addr) if err != nil { return } return Serve(l, handler) } func Serve(l net.Listener, handler Handler) (err error) { for { c, err := l.Accept() if err != nil { return err } go handler2(c, handler) } } func handler2(c net.Conn, handler Handler) { defer c.Close() err := Handle(bufio.NewReadWriter(bufio.NewReader(c), bufio.NewWriter(c)), handler) if err != nil { if errors.Is(err, io.EOF) { return } if _, z := err.(net.Error); z { return } fmt.Fprintf(os.Stderr, "boihttp error: %s\n", err) } } func Handle(c *bufio.ReadWriter, handler Handler) (err error) { for { more, err := handle(c, handler) if err != nil { return err } if !more { break } } return } func handle(c *bufio.ReadWriter, handler Handler) (more bool, err error) { req := new(Message) err = req.ReadRequest(c.Reader) if err != nil { return } reqbody := req.body(c.Reader) res := new(Message) res.Headers = make(Headers) res.SetKeepAlive(req.KeepAlive() || (req.Version == VersionHTTP1_1 && !req.Has("Connection"))) res.Version = req.Version resbody := handler(req, reqbody, res) _, err = io.Copy(io.Discard, reqbody) if err != nil { return } more = res.KeepAlive() err = res.WriteResponse(c.Writer) if err != nil { return } err = c.Writer.Flush() if err != nil { return } _, err = c.Writer.ReadFrom(resbody) if err != nil { return } err = c.Writer.Flush() if err != nil { return } return }