Correct handling of multiple packfiles
During the 1.3.1 update, a change was made to stop using http.Handle (and ServeMux underneath), in order to have manual control over the http.Server object. Unfortunately, it was overlooked that nothing was doing routing / multiplexing, so when using multiple packfiles only one handler (picked arbitrarily due to map) would actually be active on any given invocation. Correct this by adding an explicit handler. We don't use ServeMux so as to avoid bringing in any of its more complex behaviours like path cleaning etc.
This commit is contained in:
parent
5398dddb02
commit
2b280de481
|
@ -12,6 +12,7 @@ import (
|
|||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
@ -192,7 +193,7 @@ func run(c *cobra.Command, args []string) error {
|
|||
}
|
||||
|
||||
// load packfiles, registering handlers as we go
|
||||
var handler http.Handler
|
||||
router := &routerHandler{}
|
||||
for prefix, packfile := range packPaths {
|
||||
packHandler, err := htpack.New(packfile)
|
||||
if err != nil {
|
||||
|
@ -207,7 +208,7 @@ func run(c *cobra.Command, args []string) error {
|
|||
}
|
||||
packHandler.SetHeader("X-Frame-Options", framesHeader)
|
||||
|
||||
handler = &addHeaders{
|
||||
var handler http.Handler = &addHeaders{
|
||||
extraHeaders: extraHeaders,
|
||||
handler: packHandler,
|
||||
}
|
||||
|
@ -215,12 +216,13 @@ func run(c *cobra.Command, args []string) error {
|
|||
if prefix != "/" {
|
||||
handler = http.StripPrefix(prefix, handler)
|
||||
}
|
||||
router.AddRoute(prefix, handler)
|
||||
}
|
||||
|
||||
// HTTP server object setup
|
||||
sv := &http.Server{
|
||||
Addr: bindAddr,
|
||||
Handler: handler,
|
||||
Handler: router,
|
||||
}
|
||||
|
||||
// register SIGINT, SIGTERM handler
|
||||
|
@ -309,3 +311,53 @@ func (ah *addHeaders) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
ah.handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// routeEntry is used within routerHandler to map a specific prefix to a
|
||||
// specific handler.
|
||||
type routeEntry struct {
|
||||
// prefix is a path prefix with trailing "/" such as "/foo/".
|
||||
prefix string
|
||||
|
||||
// handler for the request if prefix matches.
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
// routerHandler holds a list of routes sorted by longest-prefix-first.
|
||||
type routerHandler struct {
|
||||
// entries are the list of prefixes, with longest prefix strings first.
|
||||
// The sorting ensures we can iterate through from the start and match
|
||||
// "/dir/subdir/" in preference to just "/dir/".
|
||||
entries []routeEntry
|
||||
}
|
||||
|
||||
// AddRoute adds a new entry into the handler. It is not concurrency safe; the
|
||||
// handler should not be in use.
|
||||
func (rh *routerHandler) AddRoute(prefix string, handler http.Handler) {
|
||||
if !strings.HasSuffix(prefix, "/") {
|
||||
prefix += "/"
|
||||
}
|
||||
rh.entries = append(rh.entries, routeEntry{
|
||||
prefix: prefix,
|
||||
handler: handler,
|
||||
})
|
||||
sort.Slice(rh.entries, func(i, j int) bool {
|
||||
l1, l2 := len(rh.entries[i].prefix), len(rh.entries[j].prefix)
|
||||
if l1 > l2 {
|
||||
return true
|
||||
}
|
||||
if l1 == l2 {
|
||||
return rh.entries[i].prefix < rh.entries[j].prefix
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
func (rh *routerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
for _, entry := range rh.entries {
|
||||
if strings.HasPrefix(r.URL.Path, entry.prefix) {
|
||||
entry.handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue