98 lines
1.9 KiB
Go
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
|
|
}
|