diff options
| author | adnano <[email protected]> | 2020-09-24 00:30:21 -0400 |
|---|---|---|
| committer | adnano <[email protected]> | 2020-09-24 00:30:21 -0400 |
| commit | 63696fc7c8d8f3be972d464ae847c8f1b8fcd8fd (patch) | |
| tree | 171a8ae1ba79b07767df1f9c0b45006b8127e9cb /server.go | |
| parent | Handle more than one request at a time (diff) | |
| download | go-gemini-63696fc7c8d8f3be972d464ae847c8f1b8fcd8fd.tar.xz go-gemini-63696fc7c8d8f3be972d464ae847c8f1b8fcd8fd.zip | |
Refactor
Diffstat (limited to 'server.go')
| -rw-r--r-- | server.go | 177 |
1 files changed, 0 insertions, 177 deletions
diff --git a/server.go b/server.go deleted file mode 100644 index c531671..0000000 --- a/server.go +++ /dev/null @@ -1,177 +0,0 @@ -package gemini - -import ( - "crypto/tls" - "crypto/x509" - "log" - "net" - "net/url" - "strings" - "time" -) - -// Server is a Gemini server. -type Server struct { - Addr string - TLSConfig tls.Config - Handler Handler -} - -// ListenAndServe listens for requests at the server's configured address. -func (s *Server) ListenAndServe() error { - addr := s.Addr - if addr == "" { - addr = ":1965" - } - - ln, err := net.Listen("tcp", addr) - if err != nil { - return err - } - defer ln.Close() - - tlsListener := tls.NewListener(ln, &s.TLSConfig) - return s.Serve(tlsListener) -} - -// Serve listens for requests on the provided listener. -func (s *Server) Serve(l net.Listener) error { - var tempDelay time.Duration // how long to sleep on accept failure - - for { - rw, err := l.Accept() - if err != nil { - // If this is a temporary error, sleep - if ne, ok := err.(net.Error); ok && ne.Temporary() { - if tempDelay == 0 { - tempDelay = 5 * time.Millisecond - } else { - tempDelay *= 2 - } - if max := 1 * time.Second; tempDelay > max { - tempDelay = max - } - log.Printf("gemini: Accept error: %v; retrying in %v", err, tempDelay) - time.Sleep(tempDelay) - continue - } - - // Otherwise, return the error - return err - } - - tempDelay = 0 - go s.respond(rw) - } -} - -// respond responds to a connection. -func (s *Server) respond(rw net.Conn) { - var resp *Response - - if rawurl, err := readLine(rw); err != nil { - resp = &Response{ - Status: StatusBadRequest, - Meta: "Bad request", - } - } else if len(rawurl) > 1024 { - resp = &Response{ - Status: StatusBadRequest, - Meta: "URL exceeds 1024 bytes", - } - } else if url, err := url.Parse(rawurl); err != nil || url.User != nil { - resp = &Response{ - Status: StatusBadRequest, - Meta: "Invalid URL", - } - } else { - // Gather information about the request - reqInfo := &RequestInfo{ - URL: url, - Certificates: rw.(*tls.Conn).ConnectionState().PeerCertificates, - RemoteAddr: rw.RemoteAddr(), - } - resp = s.Handler.Serve(reqInfo) - } - - resp.Write(rw) - rw.Close() -} - -// RequestInfo contains information about a request. -type RequestInfo struct { - URL *url.URL // the requested URL - Certificates []*x509.Certificate // client certificates - RemoteAddr net.Addr // client remote address -} - -// A Handler responds to a Gemini request. -type Handler interface { - // Serve accepts a Request and returns a Response. - Serve(*RequestInfo) *Response -} - -// Mux is a Gemini request multiplexer. -// It matches the URL of each incoming request against a list of registered -// patterns and calls the handler for the pattern that most closesly matches -// the URL. -type Mux struct { - entries []muxEntry -} - -type muxEntry struct { - scheme string - host string - path string - handler Handler -} - -func (m *Mux) match(url *url.URL) Handler { - for _, e := range m.entries { - if (e.scheme == "" || url.Scheme == e.scheme) && - (e.host == "" || url.Host == e.host) && - strings.HasPrefix(url.Path, e.path) { - return e.handler - } - } - return nil -} - -// Handle registers a Handler for the given pattern. -func (m *Mux) Handle(pattern string, handler Handler) { - url, err := url.Parse(pattern) - if err != nil { - panic(err) - } - m.entries = append(m.entries, muxEntry{ - url.Scheme, - url.Host, - url.Path, - handler, - }) -} - -// HandleFunc registers a HandlerFunc for the given pattern. -func (m *Mux) HandleFunc(pattern string, handlerFunc func(req *RequestInfo) *Response) { - handler := HandlerFunc(handlerFunc) - m.Handle(pattern, handler) -} - -// Serve responds to the request with the appropriate handler. -func (m *Mux) Serve(req *RequestInfo) *Response { - h := m.match(req.URL) - if h == nil { - return &Response{ - Status: StatusNotFound, - Meta: "Not found", - } - } - return h.Serve(req) -} - -// A wrapper around a bare function that implements Handler. -type HandlerFunc func(req *RequestInfo) *Response - -func (f HandlerFunc) Serve(req *RequestInfo) *Response { - return f(req) -} |