From 37f2f468fe2fb25cc390753f3bf0c274f473b40a Mon Sep 17 00:00:00 2001 From: Denis Kirillov Date: Wed, 5 Jul 2023 17:02:58 +0300 Subject: [PATCH] [#149] Add host bucket router Signed-off-by: Denis Kirillov --- api/host_bucket_router.go | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 api/host_bucket_router.go diff --git a/api/host_bucket_router.go b/api/host_bucket_router.go new file mode 100644 index 00000000..e5ceeb98 --- /dev/null +++ b/api/host_bucket_router.go @@ -0,0 +1,71 @@ +package api + +import ( + "net/http" + "strings" + + "github.com/go-chi/chi/v5" +) + +type HostBucketRouter struct { + routes map[string]chi.Router + bktParam string + defaultRouter chi.Router +} + +func NewHostBucketRouter(bktParam string) HostBucketRouter { + return HostBucketRouter{ + routes: make(map[string]chi.Router), + bktParam: bktParam, + } +} + +func (hr *HostBucketRouter) Default(router chi.Router) { + hr.defaultRouter = router +} + +func (hr HostBucketRouter) Map(host string, h chi.Router) { + hr.routes[strings.ToLower(host)] = h +} + +func (hr HostBucketRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) { + bucket, domain := getBucketDomain(getHost(r)) + router, ok := hr.routes[strings.ToLower(domain)] + if !ok { + router = hr.defaultRouter + if router == nil { + http.Error(w, http.StatusText(404), 404) + return + } + } + + if rctx := chi.RouteContext(r.Context()); rctx != nil && bucket != "" { + rctx.URLParams.Add(hr.bktParam, bucket) + } + + router.ServeHTTP(w, r) +} + +func getBucketDomain(host string) (bucket string, domain string) { + parts := strings.Split(host, ".") + if len(parts) > 1 { + return parts[0], strings.Join(parts[1:], ".") + } + return "", host +} + +// getHost tries its best to return the request host. +// According to section 14.23 of RFC 2616 the Host header +// can include the port number if the default value of 80 is not used. +func getHost(r *http.Request) string { + host := r.Host + if r.URL.IsAbs() { + host = r.URL.Host + } + + if i := strings.Index(host, ":"); i != -1 { + host = host[:i] + } + + return host +}