Sort ServeMux entries by length

This commit is contained in:
adnano 2020-09-25 11:00:18 -04:00
parent eb8c9e0c03
commit 99b50e6caf
2 changed files with 59 additions and 10 deletions

View File

@ -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,

View File

@ -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)