snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
This commit is contained in:
164
oryx/httprouterx/router.go
Normal file
164
oryx/httprouterx/router.go
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package httprouterx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
AdminPrefix = "/admin"
|
||||
|
||||
afterMatchHooks contextKey = 1
|
||||
)
|
||||
|
||||
type (
|
||||
contextKey int
|
||||
AfterMatchHookFunc func(*http.Request)
|
||||
|
||||
router struct {
|
||||
mux *http.ServeMux
|
||||
prefix string
|
||||
}
|
||||
RouterAdmin struct{ router }
|
||||
RouterPublic struct{ router }
|
||||
|
||||
Router interface {
|
||||
http.Handler
|
||||
|
||||
Handle(pattern string, handler http.Handler)
|
||||
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
|
||||
|
||||
GET(route string, handle http.HandlerFunc)
|
||||
OPTIONS(route string, handle http.HandlerFunc)
|
||||
HEAD(route string, handle http.HandlerFunc)
|
||||
POST(route string, handle http.HandlerFunc)
|
||||
PUT(route string, handle http.HandlerFunc)
|
||||
PATCH(route string, handle http.HandlerFunc)
|
||||
DELETE(route string, handle http.HandlerFunc)
|
||||
}
|
||||
)
|
||||
|
||||
func newRouter() *router { return &router{mux: http.NewServeMux()} }
|
||||
|
||||
// NewRouter creates a new general purpose router. It should only be used when neither the admin nor the public router is applicable.
|
||||
func NewRouter() Router { return newRouter() }
|
||||
|
||||
// NewRouterAdmin creates a new admin router.
|
||||
func NewRouterAdmin() *RouterAdmin {
|
||||
return &RouterAdmin{router: *newRouter()}
|
||||
}
|
||||
|
||||
func (r *RouterAdmin) ToPublic() *RouterPublic {
|
||||
return &RouterPublic{router: router{
|
||||
mux: r.mux,
|
||||
prefix: "", // do not copy the admin prefix
|
||||
}}
|
||||
}
|
||||
|
||||
// NewRouterPublic returns a public router.
|
||||
func NewRouterPublic() *RouterPublic {
|
||||
return &RouterPublic{router: *newRouter()}
|
||||
}
|
||||
|
||||
// NewRouterAdminWithPrefix creates a new router with the admin prefix.
|
||||
func NewRouterAdminWithPrefix() *RouterAdmin {
|
||||
r := NewRouterAdmin()
|
||||
r.prefix = AdminPrefix
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *router) GET(route string, handle http.HandlerFunc) {
|
||||
r.handle(http.MethodGet, route, handle)
|
||||
}
|
||||
|
||||
func (r *router) OPTIONS(route string, handle http.HandlerFunc) {
|
||||
r.handle(http.MethodOptions, route, handle)
|
||||
}
|
||||
|
||||
func (r *router) HEAD(route string, handle http.HandlerFunc) {
|
||||
r.handle(http.MethodHead, route, handle)
|
||||
}
|
||||
|
||||
func (r *router) POST(route string, handle http.HandlerFunc) {
|
||||
r.handle(http.MethodPost, route, handle)
|
||||
}
|
||||
|
||||
func (r *router) PUT(route string, handle http.HandlerFunc) {
|
||||
r.handle(http.MethodPut, route, handle)
|
||||
}
|
||||
|
||||
func (r *router) PATCH(route string, handle http.HandlerFunc) {
|
||||
r.handle(http.MethodPatch, route, handle)
|
||||
}
|
||||
|
||||
func (r *router) DELETE(route string, handle http.HandlerFunc) {
|
||||
r.handle(http.MethodDelete, route, handle)
|
||||
}
|
||||
|
||||
func (r *router) handle(method string, route string, handler http.Handler) {
|
||||
route = path.Join(r.prefix, route)
|
||||
r.mux.Handle(method+" "+route, afterMatchHookExecutor(handler))
|
||||
}
|
||||
|
||||
func afterMatchHookExecutor(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if hooks, ok := r.Context().Value(afterMatchHooks).([]AfterMatchHookFunc); ok {
|
||||
for _, hook := range hooks {
|
||||
hook(r)
|
||||
}
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// Handle registers the handler for the given pattern. It does not prepend the admin prefix, so the caller is responsible for ensuring that the pattern is correct.
|
||||
func (r *router) Handle(pattern string, handler http.Handler) {
|
||||
r.mux.Handle(pattern, afterMatchHookExecutor(handler))
|
||||
}
|
||||
|
||||
// HandleFunc registers the handler for the given pattern. It does not prepend the admin prefix, so the caller is responsible for ensuring that the pattern is correct.
|
||||
func (r *router) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
|
||||
r.Handle(pattern, http.HandlerFunc(handler))
|
||||
}
|
||||
|
||||
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) { r.mux.ServeHTTP(w, req) }
|
||||
|
||||
func TrimTrailingSlashNegroni(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
r.URL.Path = strings.TrimSuffix(r.URL.Path, "/")
|
||||
|
||||
next(rw, r)
|
||||
}
|
||||
|
||||
func NoCacheNegroni(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
if r.Method == "GET" {
|
||||
rw.Header().Set("Cache-Control", "private, no-cache, no-store, must-revalidate")
|
||||
}
|
||||
|
||||
next(rw, r)
|
||||
}
|
||||
|
||||
func AddAdminPrefixIfNotPresentNegroni(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||
if !strings.HasPrefix(r.URL.Path, AdminPrefix) {
|
||||
r.URL.Path = path.Join(AdminPrefix, r.URL.Path)
|
||||
if r.URL.RawPath != "" {
|
||||
r.URL.RawPath = path.Join(AdminPrefix, r.URL.RawPath)
|
||||
}
|
||||
}
|
||||
|
||||
next(rw, r)
|
||||
}
|
||||
|
||||
// WithAfterMatchHook adds the passed AfterMatchHookFunc to the request's context. The hook is called after the
|
||||
// router matched the request, but before it is passed to the handler. This allows middlewares to access the matched
|
||||
// pattern and other information that is only available after the router has matched the request.
|
||||
// Note that this hook is called multiple times per request if routers are nested, the hook should anticipate that.
|
||||
func WithAfterMatchHook(req *http.Request, newHooks ...AfterMatchHookFunc) *http.Request {
|
||||
hooks, _ := req.Context().Value(afterMatchHooks).([]AfterMatchHookFunc)
|
||||
ctx := context.WithValue(req.Context(), afterMatchHooks, append(hooks, newHooks...))
|
||||
return req.WithContext(ctx)
|
||||
}
|
||||
Reference in New Issue
Block a user