aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradnano <[email protected]>2020-09-25 11:00:18 -0400
committeradnano <[email protected]>2020-09-25 11:00:18 -0400
commit99b50e6caf9f9bd4665df527905efe00657cfb2b (patch)
treede010f3b738b5fda62add0e6adccf7f070189f71
parentUpdate README.md (diff)
downloadgo-gemini-99b50e6caf9f9bd4665df527905efe00657cfb2b.tar.xz
go-gemini-99b50e6caf9f9bd4665df527905efe00657cfb2b.zip
Sort ServeMux entries by length
-rw-r--r--examples/server/server.go22
-rw-r--r--gemini.go47
2 files changed, 59 insertions, 10 deletions
diff --git a/examples/server/server.go b/examples/server/server.go
index 466d024..3d1145d 100644
--- a/examples/server/server.go
+++ b/examples/server/server.go
@@ -30,14 +30,20 @@ func main() {
}
mux := &gemini.ServeMux{}
- mux.HandleFunc("/cert", func(rw *gemini.ResponseWriter, req *gemini.Request) {
- rw.WriteHeader(gemini.StatusClientCertificateRequired, "Certificate required")
- })
- mux.HandleFunc("/", func(rw *gemini.ResponseWriter, req *gemini.Request) {
- log.Printf("Request from %s for %s with certificates %v", req.RemoteAddr.String(), req.URL.String(), req.TLS.PeerCertificates)
- rw.WriteHeader(gemini.StatusSuccess, "text/gemini")
- rw.Write([]byte("You requested " + req.URL.String()))
- })
+ // mux.HandleFunc("/", func(rw *gemini.ResponseWriter, req *gemini.Request) {
+ // log.Printf("Request from %s for %s with certificates %v", req.RemoteAddr.String(), req.URL.String(), req.TLS.PeerCertificates)
+ // rw.WriteHeader(gemini.StatusSuccess, "text/gemini")
+ // rw.Write([]byte("You requested " + req.URL.String()))
+ // })
+ // mux.HandleFunc("/cert", func(rw *gemini.ResponseWriter, req *gemini.Request) {
+ // rw.WriteHeader(gemini.StatusClientCertificateRequired, "Certificate required")
+ // })
+
+ mux.HandleFunc("https://example.com/path", nil)
+ mux.HandleFunc("http://example.com/path", nil)
+ mux.HandleFunc("example.com/path", nil)
+ mux.HandleFunc("/path", nil)
+ mux.HandleFunc("/longpath", nil)
server := gemini.Server{
TLSConfig: config,
diff --git a/gemini.go b/gemini.go
index f94c01e..514fc36 100644
--- a/gemini.go
+++ b/gemini.go
@@ -9,6 +9,7 @@ import (
"log"
"net"
"net/url"
+ "sort"
"strconv"
"strings"
"time"
@@ -437,12 +438,14 @@ func (m *ServeMux) Handle(pattern string, handler Handler) {
if err != nil {
panic(err)
}
- m.entries = append(m.entries, muxEntry{
+ e := muxEntry{
url.Scheme,
url.Host,
url.Path,
handler,
- })
+ }
+ m.entries = appendSorted(m.entries, e)
+ log.Print(m.entries)
}
// HandleFunc registers a HandlerFunc for the given pattern.
@@ -461,6 +464,46 @@ func (m *ServeMux) Serve(rw *ResponseWriter, req *Request) {
h.Serve(rw, req)
}
+// appendSorted appends the entry e in the proper place in entries.
+func appendSorted(es []muxEntry, e muxEntry) []muxEntry {
+ n := len(es)
+ // sort by length
+ i := sort.Search(n, func(i int) bool {
+ // Sort entries by length.
+ // - Entries with a scheme take preference over entries without.
+ // - Entries with a host take preference over entries without.
+ // - Longer paths take preference over shorter paths.
+ //
+ // Long version:
+ // if es[i].scheme != "" {
+ // if e.scheme == "" {
+ // return false
+ // }
+ // return len(es[i].scheme) < len(e.scheme)
+ // }
+ // if es[i].host != "" {
+ // if e.host == "" {
+ // return false
+ // }
+ // return len(es[i].host) < len(e.host)
+ // }
+ // return len(es[i].path) < len(e.path)
+
+ // Condensed version:
+ return (es[i].scheme == "" || (e.scheme != "" && len(es[i].scheme) < len(e.scheme))) &&
+ (es[i].host == "" || (e.host != "" && len(es[i].host) < len(e.host))) &&
+ len(es[i].path) < len(e.path)
+ })
+ if i == n {
+ return append(es, e)
+ }
+ // we now know that i points at where we want to insert
+ es = append(es, muxEntry{}) // try to grow the slice in place, any entry works.
+ copy(es[i+1:], es[i:]) // Move shorter entries down
+ es[i] = e
+ return es
+}
+
// A wrapper around a bare function that implements Handler.
type HandlerFunc func(*ResponseWriter, *Request)