|
|
@ -11,12 +11,33 @@ import ( |
|
|
|
"github.com/go-chi/chi" |
|
|
|
) |
|
|
|
|
|
|
|
// ProxyHandler is the interface that must be implemented by types that intend
|
|
|
|
// to be used as proxy handlers. Proxy handlers may be comparatively simple,
|
|
|
|
// such as the `proxy` type, or they may be more complex and implement
|
|
|
|
// host-lookup functionality such as the `multiAppProxy` type.
|
|
|
|
//
|
|
|
|
// Proxies are required in order to support rebinding and endpoint deletion
|
|
|
|
// since go-chi doesn't currently allow us to overwrite or delete endpoints
|
|
|
|
// directly. So, what we do instead, is to regenerate the go-chi bindings when a
|
|
|
|
// rebind or endpoint deletion is requested, call Switch() on the proxy, and
|
|
|
|
// "switch" to the new chi.Router.
|
|
|
|
//
|
|
|
|
// Multiple proxies are arranged in a hierarchical structure, such as for
|
|
|
|
// multiapp support. In this case, the multiapp proxy handles dispatching
|
|
|
|
// requests based on the incoming domain, path, or domain + path, and then
|
|
|
|
// passes it to the underlying `proxy` which performs the rest of the work. This
|
|
|
|
// allows us to Switch() on a per-application bases, as required, while still
|
|
|
|
// supporting multiple applications within the same Capstan-hosted instance.
|
|
|
|
type ProxyHandler interface { |
|
|
|
// ServeHTTP allows ProxyHandler to implement http.Handler.
|
|
|
|
ServeHTTP(http.ResponseWriter, *http.Request) |
|
|
|
|
|
|
|
// Switch the current router to a new router instance.
|
|
|
|
Switch(chi.Router) |
|
|
|
SwitchFunc() func(chi.Router) |
|
|
|
} |
|
|
|
|
|
|
|
// MultiAppProxyHandler defines the interface to expose for types supporting
|
|
|
|
// multi-application loading.
|
|
|
|
type MultiAppProxyHandler interface { |
|
|
|
ProxyHandler |
|
|
|
Loader() api.ApplicationLoader |
|
|
@ -35,6 +56,7 @@ type proxy struct { |
|
|
|
mux *chi.Mux |
|
|
|
} |
|
|
|
|
|
|
|
// `proxy` type configuration options.
|
|
|
|
type proxyOptions struct { |
|
|
|
ListenAddr string |
|
|
|
Hostname string |
|
|
@ -43,11 +65,6 @@ type proxyOptions struct { |
|
|
|
MaxRequestDuration int |
|
|
|
} |
|
|
|
|
|
|
|
type handlerFinder interface { |
|
|
|
FindHandlerByDomain(string) http.Handler |
|
|
|
FindHandlerByName(string) http.Handler |
|
|
|
} |
|
|
|
|
|
|
|
// Returns a new proxy object with its router and mux unset.
|
|
|
|
//
|
|
|
|
// TODO: Replace or add feature for using a radix trie to determine the
|
|
|
@ -93,10 +110,6 @@ func (d *proxy) Switch(router chi.Router) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func (d *proxy) SwitchFunc() func(chi.Router) { |
|
|
|
return d.Switch |
|
|
|
} |
|
|
|
|
|
|
|
type multiappProxy struct { |
|
|
|
loader api.ApplicationLoader |
|
|
|
} |
|
|
@ -128,9 +141,6 @@ func (m *multiappProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
|
|
|
} |
|
|
|
|
|
|
|
func (m *multiappProxy) Switch(router chi.Router) {} |
|
|
|
func (m *multiappProxy) SwitchFunc() func(chi.Router) { |
|
|
|
return m.Switch |
|
|
|
} |
|
|
|
|
|
|
|
// mappedLoader is a map-backed loader for multi-application support.
|
|
|
|
type mappedLoader struct { |
|
|
@ -141,6 +151,9 @@ type mappedLoader struct { |
|
|
|
// NewMappedLoader returns a map-backed loader for multi-application support.
|
|
|
|
// Map-backed loaders can only map hostnames to handlers and cannot map base
|
|
|
|
// paths.
|
|
|
|
//
|
|
|
|
// The application loader interface is defined as an internal API interface (see
|
|
|
|
// internal/api/application.go for ApplicationLoader).
|
|
|
|
func NewMappedLoader(def http.Handler) *mappedLoader { |
|
|
|
return &mappedLoader{ |
|
|
|
def: def, |
|
|
@ -171,6 +184,20 @@ type radixLoader struct { |
|
|
|
def http.Handler |
|
|
|
} |
|
|
|
|
|
|
|
// NewRadixLoader returns a loader backed by a radix trie providing longest
|
|
|
|
// matching prefix support. If you need to match both the hostname and the base
|
|
|
|
// path for routing incoming requests per-application, use this loader.
|
|
|
|
//
|
|
|
|
// Be aware that there are some limitations with assigning handlers via longest
|
|
|
|
// matching prefixes. In particular, the radix loader is NOT path aware, meaning
|
|
|
|
// that a request containing the hostname + base path assignment of
|
|
|
|
// "example.com/store" will, by its nature, also match "example.com/stores" and
|
|
|
|
// any derivative thereafter.
|
|
|
|
//
|
|
|
|
// The intent behind this loader is to match the first hostname + base path
|
|
|
|
// segment of the incoming request, pass it along to the assigned application,
|
|
|
|
// and allow that application to determine whether the request should be handled
|
|
|
|
// or an error should be returned.
|
|
|
|
func NewRadixLoader(def http.Handler) *radixLoader { |
|
|
|
return &radixLoader{ |
|
|
|
trie: NewProxyTrie(), |
|
|
@ -196,6 +223,9 @@ func (r *radixLoader) AddApplicationHandler(uri string, handler http.Handler) er |
|
|
|
|
|
|
|
func (r *radixLoader) Handler(uri url.URL) (http.Handler, bool) { |
|
|
|
u := uri.String()[2:] |
|
|
|
|
|
|
|
// We don't include the trailing slash here since attached handlers should
|
|
|
|
// not include it either.
|
|
|
|
if strings.HasSuffix(u, "/") { |
|
|
|
u = u[:len(u)-1] |
|
|
|
} |
|
|
|