diff --git a/group.go b/group.go index ad8f82a..319b152 100644 --- a/group.go +++ b/group.go @@ -1,18 +1,8 @@ package mux -import ( - "net/http" - "strings" -) - -func Group(mux *http.ServeMux, prefix string, group func(sm *http.ServeMux), middlewares ...Middleware) { - groupMux := http.NewServeMux() - group(groupMux) - if !strings.HasSuffix(prefix, "/") { - prefix += "/" - } - mux.Handle( - prefix, - http.StripPrefix(strings.TrimSuffix(prefix, "/"), Use(groupMux, middlewares...)), - ) +func (m *Mux) Group(prefix string, group func(sm *Mux), middlewares ...Middleware) { + child := New() + group(child) + child.Use(middlewares...) + m.groups[prefix] = child } diff --git a/middleware.go b/middleware.go index 2b56105..7892966 100644 --- a/middleware.go +++ b/middleware.go @@ -4,10 +4,6 @@ import "net/http" type Middleware func(http.Handler) http.Handler -func Use(handler http.Handler, middlewares ...Middleware) http.Handler { - for _, h := range middlewares { - handler = h(handler) - } - - return handler +func (m *Mux) Use(middlewares ...Middleware) { + m.middlewares = append(m.middlewares, middlewares...) } diff --git a/middleware/basic_auth.go b/middleware/basic_auth.go new file mode 100644 index 0000000..847ee79 --- /dev/null +++ b/middleware/basic_auth.go @@ -0,0 +1,44 @@ +package middleware + +import ( + "fmt" + "net/http" + "strings" + + "go.neonxp.ru/mux" +) + +const basicAuthScheme = "Basic" + +type BasicAuthConfig struct { + Skipper func(r *http.Request) bool + Realm string + Validator func(r *http.Request, login, password string) error +} + +func DefaultSkipper(*http.Request) bool { + return false +} + +func BasicAuth(config BasicAuthConfig) mux.Middleware { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if config.Skipper(r) { + next.ServeHTTP(w, r) + return + } + authString := r.Header.Get("Authorization") + if authString == "" { + w.Header().Set("WWW-Authenticate", fmt.Sprintf(`%s realm="%s", charset="UTF-8"`, basicAuthScheme, config.Realm)) + w.WriteHeader(http.StatusUnauthorized) + return + } + parts := strings.SplitN(authString, " ", 2) + if strings.EqualFold(parts[0], basicAuthScheme) { + w.Header().Set("WWW-Authenticate", fmt.Sprintf(`%s realm="%s", charset="UTF-8"`, basicAuthScheme, config.Realm)) + w.WriteHeader(http.StatusUnauthorized) + return + } + }) + } +} diff --git a/mux.go b/mux.go new file mode 100644 index 0000000..1631d10 --- /dev/null +++ b/mux.go @@ -0,0 +1,28 @@ +package mux + +import "net/http" + +type Mux struct { + http.ServeMux + middlewares []Middleware + groups map[string]*Mux +} + +func New() *Mux { + return &Mux{ + ServeMux: http.ServeMux{}, + middlewares: []Middleware{}, + groups: map[string]*Mux{}, + } +} + +func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { + for path, g := range m.groups { + m.Handle(path, g) + } + h := http.Handler(&m.ServeMux) + for _, mw := range m.middlewares { + h = mw(h) + } + h.ServeHTTP(w, r) +}