aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradnano <[email protected]>2020-09-24 00:26:30 -0400
committeradnano <[email protected]>2020-09-24 00:26:30 -0400
commit758e0569524ec83966ca3167d543d32ca08be8df (patch)
tree483ab2b5d856cd17ccdb489fc44132dd29ac0e29
parentEnforce valid URLs (diff)
downloadgo-gemini-758e0569524ec83966ca3167d543d32ca08be8df.tar.xz
go-gemini-758e0569524ec83966ca3167d543d32ca08be8df.zip
Handle more than one request at a time
-rw-r--r--server.go84
1 files changed, 55 insertions, 29 deletions
diff --git a/server.go b/server.go
index 4229301..c531671 100644
--- a/server.go
+++ b/server.go
@@ -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.