This repository has been archived on 2020-11-24. You can view files and clone it, but cannot push or open issues or pull requests.
gemini-scgi/server.go

70 lines
1.8 KiB
Go
Raw Normal View History

2020-11-23 12:46:48 +00:00
// package scgi contains a minimal gemini SCGI framework
package scgi
import (
"net"
"bufio"
"strings"
"strconv"
2020-11-24 08:45:27 +00:00
"log"
2020-11-23 12:46:48 +00:00
)
// SCGIHeaders is a map representing the headers of an SCGI request.
type SCGIHeaders map[string]string
// HandlerFunc is the type for a function that will handle an SCGI request
type HandlerFunc func(net.Conn, SCGIHeaders) error
// handle gets an SCGI request, parses it, and then lets fn handle the response
func handle(c net.Conn, fn HandlerFunc) {
defer c.Close() // Connection has to be closed for gemini
reader := bufio.NewReader(c)
hl, err := reader.ReadString(':') // SCGI Spec: First bytes until a ':' represent the header length
if err != nil {
c.Write([]byte("42" + err.Error()))
2020-11-24 08:45:27 +00:00
log.Print(err.Error())
2020-11-23 12:46:48 +00:00
return
}
l, err := strconv.Atoi(hl[:len(hl)-1]) // Strip the trailing :
if err != nil {
c.Write([]byte("42" + err.Error()))
2020-11-24 08:45:27 +00:00
log.Print(err.Error())
2020-11-23 12:46:48 +00:00
return
}
buf := make([]byte, l)
_, err = reader.Read(buf)
if err != nil {
c.Write([]byte("42" + err.Error()))
2020-11-24 08:45:27 +00:00
log.Print(err.Error())
2020-11-23 12:46:48 +00:00
return
}
headerString := string(buf[:l])
headerData := strings.Split(headerString, "\x00") // split on NULLs
header := make(SCGIHeaders)
// convert header data (a slice) to a map
for i := 0; i < len(headerData); i +=2 {
if headerData[i] != "" {
header[headerData[i]] = headerData[i+1]
}
}
err = fn(c, header)
if err != nil {
2020-11-24 08:45:27 +00:00
log.Print(err.Error())
2020-11-23 12:46:48 +00:00
return
}
}
// Serve runs a simple SCGI server on listener, handling requests with fn
func Serve(listener net.Listener, fn HandlerFunc) error {
for {
conn, err := listener.Accept()
if err != nil {
2020-11-24 08:45:27 +00:00
log.Print(err)
2020-11-23 12:46:48 +00:00
}
go handle(conn, fn)
}
}