boihttp/server.go
Nadeen Udantha 4a3d59dea9 boi
2022-06-24 09:35:10 +05:30

98 lines
1.9 KiB
Go

// Copyright (c) 2022 Nadeen Udantha <me@nadeen.lk>. 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
}