code.gitea.io/gitea@v1.22.3/modules/web/route.go (about) 1 // Copyright 2020 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package web 5 6 import ( 7 "net/http" 8 "strings" 9 10 "code.gitea.io/gitea/modules/web/middleware" 11 12 "gitea.com/go-chi/binding" 13 "github.com/go-chi/chi/v5" 14 ) 15 16 // Bind binding an obj to a handler's context data 17 func Bind[T any](_ T) http.HandlerFunc { 18 return func(resp http.ResponseWriter, req *http.Request) { 19 theObj := new(T) // create a new form obj for every request but not use obj directly 20 data := middleware.GetContextData(req.Context()) 21 binding.Bind(req, theObj) 22 SetForm(data, theObj) 23 middleware.AssignForm(theObj, data) 24 } 25 } 26 27 // SetForm set the form object 28 func SetForm(dataStore middleware.ContextDataStore, obj any) { 29 dataStore.GetData()["__form"] = obj 30 } 31 32 // GetForm returns the validate form information 33 func GetForm(dataStore middleware.ContextDataStore) any { 34 return dataStore.GetData()["__form"] 35 } 36 37 // Route defines a route based on chi's router 38 type Route struct { 39 R chi.Router 40 curGroupPrefix string 41 curMiddlewares []any 42 } 43 44 // NewRoute creates a new route 45 func NewRoute() *Route { 46 r := chi.NewRouter() 47 return &Route{R: r} 48 } 49 50 // Use supports two middlewares 51 func (r *Route) Use(middlewares ...any) { 52 for _, m := range middlewares { 53 if m != nil { 54 r.R.Use(toHandlerProvider(m)) 55 } 56 } 57 } 58 59 // Group mounts a sub-Router along a `pattern` string. 60 func (r *Route) Group(pattern string, fn func(), middlewares ...any) { 61 previousGroupPrefix := r.curGroupPrefix 62 previousMiddlewares := r.curMiddlewares 63 r.curGroupPrefix += pattern 64 r.curMiddlewares = append(r.curMiddlewares, middlewares...) 65 66 fn() 67 68 r.curGroupPrefix = previousGroupPrefix 69 r.curMiddlewares = previousMiddlewares 70 } 71 72 func (r *Route) getPattern(pattern string) string { 73 newPattern := r.curGroupPrefix + pattern 74 if !strings.HasPrefix(newPattern, "/") { 75 newPattern = "/" + newPattern 76 } 77 if newPattern == "/" { 78 return newPattern 79 } 80 return strings.TrimSuffix(newPattern, "/") 81 } 82 83 func (r *Route) wrapMiddlewareAndHandler(h []any) ([]func(http.Handler) http.Handler, http.HandlerFunc) { 84 handlerProviders := make([]func(http.Handler) http.Handler, 0, len(r.curMiddlewares)+len(h)+1) 85 for _, m := range r.curMiddlewares { 86 if m != nil { 87 handlerProviders = append(handlerProviders, toHandlerProvider(m)) 88 } 89 } 90 for _, m := range h { 91 if h != nil { 92 handlerProviders = append(handlerProviders, toHandlerProvider(m)) 93 } 94 } 95 middlewares := handlerProviders[:len(handlerProviders)-1] 96 handlerFunc := handlerProviders[len(handlerProviders)-1](nil).ServeHTTP 97 mockPoint := RouteMockPoint(MockAfterMiddlewares) 98 if mockPoint != nil { 99 middlewares = append(middlewares, mockPoint) 100 } 101 return middlewares, handlerFunc 102 } 103 104 // Methods adds the same handlers for multiple http "methods" (separated by ","). 105 // If any method is invalid, the lower level router will panic. 106 func (r *Route) Methods(methods, pattern string, h ...any) { 107 middlewares, handlerFunc := r.wrapMiddlewareAndHandler(h) 108 fullPattern := r.getPattern(pattern) 109 if strings.Contains(methods, ",") { 110 methods := strings.Split(methods, ",") 111 for _, method := range methods { 112 r.R.With(middlewares...).Method(strings.TrimSpace(method), fullPattern, handlerFunc) 113 } 114 } else { 115 r.R.With(middlewares...).Method(methods, fullPattern, handlerFunc) 116 } 117 } 118 119 // Mount attaches another Route along ./pattern/* 120 func (r *Route) Mount(pattern string, subR *Route) { 121 subR.Use(r.curMiddlewares...) 122 r.R.Mount(r.getPattern(pattern), subR.R) 123 } 124 125 // Any delegate requests for all methods 126 func (r *Route) Any(pattern string, h ...any) { 127 middlewares, handlerFunc := r.wrapMiddlewareAndHandler(h) 128 r.R.With(middlewares...).HandleFunc(r.getPattern(pattern), handlerFunc) 129 } 130 131 // Delete delegate delete method 132 func (r *Route) Delete(pattern string, h ...any) { 133 r.Methods("DELETE", pattern, h...) 134 } 135 136 // Get delegate get method 137 func (r *Route) Get(pattern string, h ...any) { 138 r.Methods("GET", pattern, h...) 139 } 140 141 // Head delegate head method 142 func (r *Route) Head(pattern string, h ...any) { 143 r.Methods("HEAD", pattern, h...) 144 } 145 146 // Post delegate post method 147 func (r *Route) Post(pattern string, h ...any) { 148 r.Methods("POST", pattern, h...) 149 } 150 151 // Put delegate put method 152 func (r *Route) Put(pattern string, h ...any) { 153 r.Methods("PUT", pattern, h...) 154 } 155 156 // Patch delegate patch method 157 func (r *Route) Patch(pattern string, h ...any) { 158 r.Methods("PATCH", pattern, h...) 159 } 160 161 // ServeHTTP implements http.Handler 162 func (r *Route) ServeHTTP(w http.ResponseWriter, req *http.Request) { 163 r.R.ServeHTTP(w, req) 164 } 165 166 // NotFound defines a handler to respond whenever a route could not be found. 167 func (r *Route) NotFound(h http.HandlerFunc) { 168 r.R.NotFound(h) 169 } 170 171 // Combo delegates requests to Combo 172 func (r *Route) Combo(pattern string, h ...any) *Combo { 173 return &Combo{r, pattern, h} 174 } 175 176 // Combo represents a tiny group routes with same pattern 177 type Combo struct { 178 r *Route 179 pattern string 180 h []any 181 } 182 183 // Get delegates Get method 184 func (c *Combo) Get(h ...any) *Combo { 185 c.r.Get(c.pattern, append(c.h, h...)...) 186 return c 187 } 188 189 // Post delegates Post method 190 func (c *Combo) Post(h ...any) *Combo { 191 c.r.Post(c.pattern, append(c.h, h...)...) 192 return c 193 } 194 195 // Delete delegates Delete method 196 func (c *Combo) Delete(h ...any) *Combo { 197 c.r.Delete(c.pattern, append(c.h, h...)...) 198 return c 199 } 200 201 // Put delegates Put method 202 func (c *Combo) Put(h ...any) *Combo { 203 c.r.Put(c.pattern, append(c.h, h...)...) 204 return c 205 } 206 207 // Patch delegates Patch method 208 func (c *Combo) Patch(h ...any) *Combo { 209 c.r.Patch(c.pattern, append(c.h, h...)...) 210 return c 211 }