From ff05d62013906f3086b452bfeda3e0d5b9b7a541 Mon Sep 17 00:00:00 2001 From: tjpcc Date: Mon, 9 Jan 2023 16:40:24 -0700 Subject: Initial commit. some basics: - minimal README - some TODOs - server and request handler framework - contribs: file serving, request logging - server examples - CI setup --- gemini/serve.go | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 gemini/serve.go (limited to 'gemini/serve.go') diff --git a/gemini/serve.go b/gemini/serve.go new file mode 100644 index 0000000..d439472 --- /dev/null +++ b/gemini/serve.go @@ -0,0 +1,89 @@ +package gemini + +import ( + "context" + "crypto/tls" + "io" + "net" + "sync" +) + +type Server struct { + ctx context.Context + cancel context.CancelFunc + wg *sync.WaitGroup + listener net.Listener + handler Handler +} + +func NewServer(ctx context.Context, tlsConfig *tls.Config, listener net.Listener, handler Handler) *Server { + ctx, cancel := context.WithCancel(ctx) + + s := &Server{ + ctx: ctx, + cancel: cancel, + wg: &sync.WaitGroup{}, + listener: tls.NewListener(listener, tlsConfig), + handler: handler, + } + go s.propagateCancel() + + return s +} + +func (s *Server) Close() { + s.cancel() + s.wg.Wait() +} + +func (s *Server) Serve() { + s.wg.Add(1) + defer s.wg.Done() + + for { + conn, err := s.listener.Accept() + if err != nil { + return + } + + s.wg.Add(1) + go s.handleConn(conn) + } +} + +func (s *Server) handleConn(conn net.Conn) { + defer s.wg.Done() + defer conn.Close() + + req, err := ParseRequest(conn) + if tlsconn, ok := conn.(*tls.Conn); req != nil && ok { + state := tlsconn.ConnectionState() + req.TLSState = &state + } + + var resp *Response + if err == nil { + resp = s.handler(s.ctx, req) + } else { + resp = BadRequest(err.Error()) + } + defer resp.Close() + + _, _ = io.Copy(conn, resp) +} + +func (s *Server) propagateCancel() { + go func() { + <-s.ctx.Done() + _ = s.listener.Close() + }() +} + +func (s *Server) closed() bool { + select { + case <-s.ctx.Done(): + return true + default: + return false + } +} -- cgit v1.2.3