diff options
| author | adnano <[email protected]> | 2020-09-24 00:26:30 -0400 |
|---|---|---|
| committer | adnano <[email protected]> | 2020-09-24 00:26:30 -0400 |
| commit | 758e0569524ec83966ca3167d543d32ca08be8df (patch) | |
| tree | 483ab2b5d856cd17ccdb489fc44132dd29ac0e29 | |
| parent | Enforce valid URLs (diff) | |
| download | go-gemini-758e0569524ec83966ca3167d543d32ca08be8df.tar.xz go-gemini-758e0569524ec83966ca3167d543d32ca08be8df.zip | |
Handle more than one request at a time
| -rw-r--r-- | server.go | 84 |
1 files changed, 55 insertions, 29 deletions
@@ -3,9 +3,11 @@ package gemini import ( "crypto/tls" "crypto/x509" + "log" "net" "net/url" "strings" + "time" ) // Server is a Gemini server. @@ -33,43 +35,67 @@ func (s *Server) ListenAndServe() error { } // Serve listens for requests on the provided listener. -func (s *Server) Serve(ln net.Listener) error { +func (s *Server) Serve(l net.Listener) error { + var tempDelay time.Duration // how long to sleep on accept failure + for { - rw, err := ln.Accept() + 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 } - var resp *Response + tempDelay = 0 + go s.respond(rw) + } +} - 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) - } +// respond responds to a connection. +func (s *Server) respond(rw net.Conn) { + var resp *Response - resp.Write(rw) - rw.Close() + 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. |