violet/router/router.go

120 lines
2.8 KiB
Go
Raw Permalink Normal View History

package router
import (
"fmt"
"github.com/MrMelon54/trie"
"github.com/MrMelon54/violet/target"
"github.com/MrMelon54/violet/utils"
"net/http"
"net/http/httputil"
"strings"
)
type Router struct {
route map[string]*trie.Trie[target.Route]
redirect map[string]*trie.Trie[target.Redirect]
notFound http.Handler
proxy *httputil.ReverseProxy
}
2023-04-21 03:21:46 +01:00
func New(proxy *httputil.ReverseProxy) *Router {
return &Router{
route: make(map[string]*trie.Trie[target.Route]),
redirect: make(map[string]*trie.Trie[target.Redirect]),
notFound: http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
_, _ = fmt.Fprintf(rw, "%d %s\n", http.StatusNotFound, http.StatusText(http.StatusNotFound))
}),
2023-04-21 03:21:46 +01:00
proxy: proxy,
}
}
func (r *Router) hostRoute(host string) *trie.Trie[target.Route] {
h := r.route[host]
if h == nil {
h = &trie.Trie[target.Route]{}
r.route[host] = h
}
return h
}
func (r *Router) hostRedirect(host string) *trie.Trie[target.Redirect] {
h := r.redirect[host]
if h == nil {
h = &trie.Trie[target.Redirect]{}
r.redirect[host] = h
}
return h
}
func (r *Router) AddService(host string, t target.Route) {
2023-04-21 03:21:46 +01:00
r.AddRoute(host, "/", t)
}
func (r *Router) AddRoute(host string, path string, t target.Route) {
2023-04-21 03:21:46 +01:00
t.Proxy = r.proxy
r.hostRoute(host).PutString(path, t)
}
func (r *Router) AddRedirect(host, path string, t target.Redirect) {
r.hostRedirect(host).PutString(path, t)
}
func (r *Router) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if req.URL.Path == "" {
req.URL.Path = "/"
}
host, _, _ := utils.SplitDomainPort(req.Host, 0)
if r.serveRedirectHTTP(rw, req, host) {
return
}
if r.serveRouteHTTP(rw, req, host) {
return
}
parentHostDot := strings.IndexByte(host, '.')
if parentHostDot == -1 {
r.notFound.ServeHTTP(rw, req)
return
}
wildcardHost := "*" + host[parentHostDot:]
if r.serveRedirectHTTP(rw, req, wildcardHost) {
return
}
if r.serveRouteHTTP(rw, req, wildcardHost) {
return
}
}
func (r *Router) serveRouteHTTP(rw http.ResponseWriter, req *http.Request, host string) bool {
h := r.route[host]
if h != nil {
pairs := h.GetAllKeyValues([]byte(req.URL.Path))
for i := len(pairs) - 1; i >= 0; i-- {
if pairs[i].Value.Pre || pairs[i].Key == req.URL.Path {
req.URL.Path = strings.TrimPrefix(req.URL.Path, pairs[i].Key)
pairs[i].Value.ServeHTTP(rw, req)
return true
}
}
}
return false
}
func (r *Router) serveRedirectHTTP(rw http.ResponseWriter, req *http.Request, host string) bool {
h := r.redirect[host]
if h != nil {
pairs := h.GetAllKeyValues([]byte(req.URL.Path))
for i := len(pairs) - 1; i >= 0; i-- {
if pairs[i].Value.Pre || pairs[i].Key == req.URL.Path {
req.URL.Path = strings.TrimPrefix(req.URL.Path, pairs[i].Key)
pairs[i].Value.ServeHTTP(rw, req)
return true
}
}
}
return false
}