diff options
Diffstat (limited to 'gopher/serve.go')
-rw-r--r-- | gopher/serve.go | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/gopher/serve.go b/gopher/serve.go new file mode 100644 index 0000000..84745d7 --- /dev/null +++ b/gopher/serve.go @@ -0,0 +1,72 @@ +package gopher + +import ( + "context" + "errors" + "fmt" + "io" + "net" + "strings" + + "tildegit.org/tjp/gus" + "tildegit.org/tjp/gus/internal" + "tildegit.org/tjp/gus/logging" +) + +type gopherServer struct { + internal.Server + handler gus.Handler +} + +func (gs gopherServer) Protocol() string { return "GOPHER" } + +// NewServer builds a gopher server. +func NewServer( + ctx context.Context, + hostname string, + network string, + address string, + handler gus.Handler, + errLog logging.Logger, +) (gus.Server, error) { + gs := &gopherServer{handler: handler} + + if strings.IndexByte(hostname, ':') < 0 { + hostname = net.JoinHostPort(hostname, "70") + } + + var err error + gs.Server, err = internal.NewServer(ctx, hostname, network, address, errLog, gs.handleConn) + if err != nil { + return nil, err + } + + return gs, nil +} + +func (gs *gopherServer) handleConn(conn net.Conn) { + var response *gus.Response + request, err := ParseRequest(conn) + if err != nil { + response = Error(errors.New("Malformed request.")).Response() + } else { + request.Server = gs + request.RemoteAddr = conn.RemoteAddr() + + defer func() { + if r := recover(); r != nil { + err := fmt.Errorf("%s", r) + _ = gs.LogError("msg", "panic in handler", "err", err) + rdr := NewResponseReader(Error(errors.New("Server error.")).Response()) + _, _ = io.Copy(conn, rdr) + } + }() + response = gs.handler(gs.Ctx, request) + if response == nil { + response = Error(errors.New("Resource does not exist.")).Response() + } + } + + defer response.Close() + _, _ = io.Copy(conn, NewResponseReader(response)) +} |