2021-01-26 18:36:53 +03:00
// Copyright 2020 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2021-01-26 18:36:53 +03:00
package web
import (
"net/http"
2024-06-18 02:28:47 +03:00
"net/url"
2024-11-12 05:38:22 +03:00
"reflect"
2021-01-26 18:36:53 +03:00
"strings"
2024-12-04 05:11:34 +03:00
"code.gitea.io/gitea/modules/htmlutil"
2024-06-18 02:28:47 +03:00
"code.gitea.io/gitea/modules/setting"
2021-01-30 11:55:53 +03:00
"code.gitea.io/gitea/modules/web/middleware"
2021-01-26 18:36:53 +03:00
"gitea.com/go-chi/binding"
2023-06-18 10:59:09 +03:00
"github.com/go-chi/chi/v5"
2021-01-26 18:36:53 +03:00
)
2023-06-18 10:59:09 +03:00
// Bind binding an obj to a handler's context data
func Bind [ T any ] ( _ T ) http . HandlerFunc {
return func ( resp http . ResponseWriter , req * http . Request ) {
2022-12-12 11:09:26 +03:00
theObj := new ( T ) // create a new form obj for every request but not use obj directly
2023-06-18 10:59:09 +03:00
data := middleware . GetContextData ( req . Context ( ) )
binding . Bind ( req , theObj )
SetForm ( data , theObj )
middleware . AssignForm ( theObj , data )
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
}
2021-01-26 18:36:53 +03:00
}
// SetForm set the form object
2023-07-04 21:36:08 +03:00
func SetForm ( dataStore middleware . ContextDataStore , obj any ) {
2023-06-18 10:59:09 +03:00
dataStore . GetData ( ) [ "__form" ] = obj
2021-01-26 18:36:53 +03:00
}
// GetForm returns the validate form information
2023-07-04 21:36:08 +03:00
func GetForm ( dataStore middleware . ContextDataStore ) any {
2023-06-18 10:59:09 +03:00
return dataStore . GetData ( ) [ "__form" ]
2021-01-26 18:36:53 +03:00
}
2024-06-19 01:32:45 +03:00
// Router defines a route based on chi's router
type Router struct {
chiRouter chi . Router
2021-01-26 18:36:53 +03:00
curGroupPrefix string
2023-07-04 21:36:08 +03:00
curMiddlewares [ ] any
2021-01-26 18:36:53 +03:00
}
2024-06-19 01:32:45 +03:00
// NewRouter creates a new route
func NewRouter ( ) * Router {
2021-01-26 18:36:53 +03:00
r := chi . NewRouter ( )
2024-06-19 01:32:45 +03:00
return & Router { chiRouter : r }
2021-01-26 18:36:53 +03:00
}
// Use supports two middlewares
2024-06-19 01:32:45 +03:00
func ( r * Router ) Use ( middlewares ... any ) {
2023-04-27 09:06:45 +03:00
for _ , m := range middlewares {
2023-07-09 15:25:53 +03:00
if m != nil {
2024-06-19 01:32:45 +03:00
r . chiRouter . Use ( toHandlerProvider ( m ) )
2023-07-09 15:25:53 +03:00
}
2021-01-26 18:36:53 +03:00
}
}
// Group mounts a sub-Router along a `pattern` string.
2024-06-19 01:32:45 +03:00
func ( r * Router ) Group ( pattern string , fn func ( ) , middlewares ... any ) {
2022-01-20 20:46:10 +03:00
previousGroupPrefix := r . curGroupPrefix
previousMiddlewares := r . curMiddlewares
2021-01-26 18:36:53 +03:00
r . curGroupPrefix += pattern
r . curMiddlewares = append ( r . curMiddlewares , middlewares ... )
fn ( )
r . curGroupPrefix = previousGroupPrefix
r . curMiddlewares = previousMiddlewares
}
2024-06-19 01:32:45 +03:00
func ( r * Router ) getPattern ( pattern string ) string {
2021-01-26 18:36:53 +03:00
newPattern := r . curGroupPrefix + pattern
if ! strings . HasPrefix ( newPattern , "/" ) {
newPattern = "/" + newPattern
}
if newPattern == "/" {
return newPattern
}
return strings . TrimSuffix ( newPattern , "/" )
}
2024-11-12 05:38:22 +03:00
func isNilOrFuncNil ( v any ) bool {
if v == nil {
return true
}
r := reflect . ValueOf ( v )
return r . Kind ( ) == reflect . Func && r . IsNil ( )
}
2024-06-19 01:32:45 +03:00
func ( r * Router ) wrapMiddlewareAndHandler ( h [ ] any ) ( [ ] func ( http . Handler ) http . Handler , http . HandlerFunc ) {
2023-07-09 15:25:53 +03:00
handlerProviders := make ( [ ] func ( http . Handler ) http . Handler , 0 , len ( r . curMiddlewares ) + len ( h ) + 1 )
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
for _ , m := range r . curMiddlewares {
2024-11-12 05:38:22 +03:00
if ! isNilOrFuncNil ( m ) {
2023-07-09 15:25:53 +03:00
handlerProviders = append ( handlerProviders , toHandlerProvider ( m ) )
}
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
}
for _ , m := range h {
2024-11-12 05:38:22 +03:00
if ! isNilOrFuncNil ( m ) {
2023-07-09 15:25:53 +03:00
handlerProviders = append ( handlerProviders , toHandlerProvider ( m ) )
}
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
}
middlewares := handlerProviders [ : len ( handlerProviders ) - 1 ]
handlerFunc := handlerProviders [ len ( handlerProviders ) - 1 ] ( nil ) . ServeHTTP
2024-06-19 01:32:45 +03:00
mockPoint := RouterMockPoint ( MockAfterMiddlewares )
2023-07-09 15:25:53 +03:00
if mockPoint != nil {
middlewares = append ( middlewares , mockPoint )
}
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
return middlewares , handlerFunc
}
2023-12-25 15:13:18 +03:00
// Methods adds the same handlers for multiple http "methods" (separated by ",").
// If any method is invalid, the lower level router will panic.
2024-06-19 01:32:45 +03:00
func ( r * Router ) Methods ( methods , pattern string , h ... any ) {
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
middlewares , handlerFunc := r . wrapMiddlewareAndHandler ( h )
fullPattern := r . getPattern ( pattern )
2023-12-25 15:13:18 +03:00
if strings . Contains ( methods , "," ) {
methods := strings . Split ( methods , "," )
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
for _ , method := range methods {
2024-06-19 01:32:45 +03:00
r . chiRouter . With ( middlewares ... ) . Method ( strings . TrimSpace ( method ) , fullPattern , handlerFunc )
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
}
} else {
2024-06-19 01:32:45 +03:00
r . chiRouter . With ( middlewares ... ) . Method ( methods , fullPattern , handlerFunc )
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
}
}
2024-06-19 01:32:45 +03:00
// Mount attaches another Router along ./pattern/*
func ( r * Router ) Mount ( pattern string , subRouter * Router ) {
subRouter . Use ( r . curMiddlewares ... )
r . chiRouter . Mount ( r . getPattern ( pattern ) , subRouter . chiRouter )
2021-01-26 18:36:53 +03:00
}
// Any delegate requests for all methods
2024-06-19 01:32:45 +03:00
func ( r * Router ) Any ( pattern string , h ... any ) {
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
middlewares , handlerFunc := r . wrapMiddlewareAndHandler ( h )
2024-06-19 01:32:45 +03:00
r . chiRouter . With ( middlewares ... ) . HandleFunc ( r . getPattern ( pattern ) , handlerFunc )
2021-01-26 18:36:53 +03:00
}
// Delete delegate delete method
2024-06-19 01:32:45 +03:00
func ( r * Router ) Delete ( pattern string , h ... any ) {
2023-07-21 01:43:49 +03:00
r . Methods ( "DELETE" , pattern , h ... )
2021-01-26 18:36:53 +03:00
}
// Get delegate get method
2024-06-19 01:32:45 +03:00
func ( r * Router ) Get ( pattern string , h ... any ) {
2023-07-21 01:43:49 +03:00
r . Methods ( "GET" , pattern , h ... )
2021-07-21 06:32:35 +03:00
}
2021-01-26 18:36:53 +03:00
// Head delegate head method
2024-06-19 01:32:45 +03:00
func ( r * Router ) Head ( pattern string , h ... any ) {
2023-07-21 01:43:49 +03:00
r . Methods ( "HEAD" , pattern , h ... )
2021-01-26 18:36:53 +03:00
}
// Post delegate post method
2024-06-19 01:32:45 +03:00
func ( r * Router ) Post ( pattern string , h ... any ) {
2023-07-21 01:43:49 +03:00
r . Methods ( "POST" , pattern , h ... )
2021-01-26 18:36:53 +03:00
}
// Put delegate put method
2024-06-19 01:32:45 +03:00
func ( r * Router ) Put ( pattern string , h ... any ) {
2023-07-21 01:43:49 +03:00
r . Methods ( "PUT" , pattern , h ... )
2021-01-26 18:36:53 +03:00
}
// Patch delegate patch method
2024-06-19 01:32:45 +03:00
func ( r * Router ) Patch ( pattern string , h ... any ) {
2023-07-21 01:43:49 +03:00
r . Methods ( "PATCH" , pattern , h ... )
2021-01-26 18:36:53 +03:00
}
// ServeHTTP implements http.Handler
2024-06-19 01:32:45 +03:00
func ( r * Router ) ServeHTTP ( w http . ResponseWriter , req * http . Request ) {
r . normalizeRequestPath ( w , req , r . chiRouter )
2021-01-26 18:36:53 +03:00
}
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
// NotFound defines a handler to respond whenever a route could not be found.
2024-06-19 01:32:45 +03:00
func ( r * Router ) NotFound ( h http . HandlerFunc ) {
r . chiRouter . NotFound ( h )
2021-01-26 18:36:53 +03:00
}
2024-06-19 01:32:45 +03:00
func ( r * Router ) normalizeRequestPath ( resp http . ResponseWriter , req * http . Request , next http . Handler ) {
2024-06-18 02:28:47 +03:00
normalized := false
normalizedPath := req . URL . EscapedPath ( )
if normalizedPath == "" {
normalizedPath , normalized = "/" , true
} else if normalizedPath != "/" {
normalized = strings . HasSuffix ( normalizedPath , "/" )
normalizedPath = strings . TrimRight ( normalizedPath , "/" )
}
removeRepeatedSlashes := strings . Contains ( normalizedPath , "//" )
normalized = normalized || removeRepeatedSlashes
// the following code block is a slow-path for replacing all repeated slashes "//" to one single "/"
// if the path doesn't have repeated slashes, then no need to execute it
if removeRepeatedSlashes {
buf := & strings . Builder { }
for i := 0 ; i < len ( normalizedPath ) ; i ++ {
if i == 0 || normalizedPath [ i - 1 ] != '/' || normalizedPath [ i ] != '/' {
buf . WriteByte ( normalizedPath [ i ] )
}
}
normalizedPath = buf . String ( )
}
// If the config tells Gitea to use a sub-url path directly without reverse proxy,
// then we need to remove the sub-url path from the request URL path.
// But "/v2" is special for OCI container registry, it should always be in the root of the site.
if setting . UseSubURLPath {
remainingPath , ok := strings . CutPrefix ( normalizedPath , setting . AppSubURL + "/" )
if ok {
normalizedPath = "/" + remainingPath
} else if normalizedPath == setting . AppSubURL {
normalizedPath = "/"
} else if ! strings . HasPrefix ( normalizedPath + "/" , "/v2/" ) {
// do not respond to other requests, to simulate a real sub-path environment
2024-12-04 05:11:34 +03:00
resp . Header ( ) . Add ( "Content-Type" , "text/html; charset=utf-8" )
resp . WriteHeader ( http . StatusNotFound )
_ , _ = resp . Write ( [ ] byte ( htmlutil . HTMLFormat ( ` 404 page not found, sub-path is: <a href="%s">%s</a> ` , setting . AppSubURL , setting . AppSubURL ) ) )
2024-06-18 02:28:47 +03:00
return
}
normalized = true
}
// if the path is normalized, then fill it back to the request
if normalized {
decodedPath , err := url . PathUnescape ( normalizedPath )
if err != nil {
http . Error ( resp , "400 Bad Request: unable to unescape path " + normalizedPath , http . StatusBadRequest )
return
}
req . URL . RawPath = normalizedPath
req . URL . Path = decodedPath
}
next . ServeHTTP ( resp , req )
}
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
// Combo delegates requests to Combo
2024-06-19 01:32:45 +03:00
func ( r * Router ) Combo ( pattern string , h ... any ) * Combo {
2021-01-26 18:36:53 +03:00
return & Combo { r , pattern , h }
}
// Combo represents a tiny group routes with same pattern
type Combo struct {
2024-06-19 01:32:45 +03:00
r * Router
2021-01-26 18:36:53 +03:00
pattern string
2023-07-04 21:36:08 +03:00
h [ ] any
2021-01-26 18:36:53 +03:00
}
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
// Get delegates Get method
2023-07-04 21:36:08 +03:00
func ( c * Combo ) Get ( h ... any ) * Combo {
2021-01-26 18:36:53 +03:00
c . r . Get ( c . pattern , append ( c . h , h ... ) ... )
return c
}
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
// Post delegates Post method
2023-07-04 21:36:08 +03:00
func ( c * Combo ) Post ( h ... any ) * Combo {
2021-01-26 18:36:53 +03:00
c . r . Post ( c . pattern , append ( c . h , h ... ) ... )
return c
}
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
// Delete delegates Delete method
2023-07-04 21:36:08 +03:00
func ( c * Combo ) Delete ( h ... any ) * Combo {
2021-01-26 18:36:53 +03:00
c . r . Delete ( c . pattern , append ( c . h , h ... ) ... )
return c
}
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
// Put delegates Put method
2023-07-04 21:36:08 +03:00
func ( c * Combo ) Put ( h ... any ) * Combo {
2021-01-26 18:36:53 +03:00
c . r . Put ( c . pattern , append ( c . h , h ... ) ... )
return c
}
Refactor web route (#24080)
The old code is unnecessarily complex, and has many misuses.
Old code "wraps" a lot, wrap wrap wrap, it's difficult to understand
which kind of handler is used.
The new code uses a general approach, we do not need to write all kinds
of handlers into the "wrapper", do not need to wrap them again and
again.
New code, there are only 2 concepts:
1. HandlerProvider: `func (h any) (handlerProvider func (next)
http.Handler)`, it can be used as middleware
2. Use HandlerProvider to get the final HandlerFunc, and use it for
`r.Get()`
And we can decouple the route package from context package (see the
TODO).
# FAQ
## Is `reflect` safe?
Yes, all handlers are checked during startup, see the `preCheckHandler`
comment. If any handler is wrong, developers could know it in the first
time.
## Does `reflect` affect performance?
No. https://github.com/go-gitea/gitea/pull/24080#discussion_r1164825901
1. This reflect code only runs for each web handler call, handler is far
more slower: 10ms-50ms
2. The reflect is pretty fast (comparing to other code): 0.000265ms
3. XORM has more reflect operations already
2023-04-20 21:49:06 +03:00
// Patch delegates Patch method
2023-07-04 21:36:08 +03:00
func ( c * Combo ) Patch ( h ... any ) * Combo {
2021-01-26 18:36:53 +03:00
c . r . Patch ( c . pattern , append ( c . h , h ... ) ... )
return c
}