2021-01-26 23:36:53 +08:00
// Copyright 2020 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2021-01-26 23:36:53 +08:00
package web
import (
2021-05-06 00:30:25 +01:00
goctx "context"
2021-01-26 23:36:53 +08:00
"fmt"
"net/http"
"reflect"
"strings"
"code.gitea.io/gitea/modules/context"
2021-01-30 16:55:53 +08:00
"code.gitea.io/gitea/modules/web/middleware"
2021-01-26 23:36:53 +08:00
"gitea.com/go-chi/binding"
2021-10-14 10:50:23 +08:00
chi "github.com/go-chi/chi/v5"
2021-01-26 23:36:53 +08:00
)
// Bind binding an obj to a handler
func Bind ( obj interface { } ) http . HandlerFunc {
2022-01-20 18:46:10 +01:00
tp := reflect . TypeOf ( obj )
2021-01-26 23:36:53 +08:00
if tp . Kind ( ) == reflect . Ptr {
tp = tp . Elem ( )
}
if tp . Kind ( ) != reflect . Struct {
panic ( "Only structs are allowed to bind" )
}
return Wrap ( func ( ctx * context . Context ) {
2022-01-20 18:46:10 +01:00
theObj := reflect . New ( tp ) . Interface ( ) // create a new form obj for every request but not use obj directly
2021-01-26 23:36:53 +08:00
binding . Bind ( ctx . Req , theObj )
SetForm ( ctx , theObj )
2021-01-30 16:55:53 +08:00
middleware . AssignForm ( theObj , ctx . Data )
2021-01-26 23:36:53 +08:00
} )
}
// SetForm set the form object
2021-01-30 16:55:53 +08:00
func SetForm ( data middleware . DataStore , obj interface { } ) {
2021-01-26 23:36:53 +08:00
data . GetData ( ) [ "__form" ] = obj
}
// GetForm returns the validate form information
2021-01-30 16:55:53 +08:00
func GetForm ( data middleware . DataStore ) interface { } {
2021-01-26 23:36:53 +08:00
return data . GetData ( ) [ "__form" ]
}
// Route defines a route based on chi's router
type Route struct {
R chi . Router
curGroupPrefix string
curMiddlewares [ ] interface { }
}
// NewRoute creates a new route
func NewRoute ( ) * Route {
r := chi . NewRouter ( )
return & Route {
R : r ,
curGroupPrefix : "" ,
curMiddlewares : [ ] interface { } { } ,
}
}
// Use supports two middlewares
func ( r * Route ) Use ( middlewares ... interface { } ) {
if r . curGroupPrefix != "" {
r . curMiddlewares = append ( r . curMiddlewares , middlewares ... )
} else {
for _ , middle := range middlewares {
switch t := middle . ( type ) {
case func ( http . Handler ) http . Handler :
r . R . Use ( t )
case func ( * context . Context ) :
r . R . Use ( Middle ( t ) )
2021-05-06 00:30:25 +01:00
case func ( * context . Context ) goctx . CancelFunc :
r . R . Use ( MiddleCancel ( t ) )
2021-01-26 23:36:53 +08:00
case func ( * context . APIContext ) :
r . R . Use ( MiddleAPI ( t ) )
default :
panic ( fmt . Sprintf ( "Unsupported middleware type: %#v" , t ) )
}
}
}
}
// Group mounts a sub-Router along a `pattern` string.
func ( r * Route ) Group ( pattern string , fn func ( ) , middlewares ... interface { } ) {
2022-01-20 18:46:10 +01:00
previousGroupPrefix := r . curGroupPrefix
previousMiddlewares := r . curMiddlewares
2021-01-26 23:36:53 +08:00
r . curGroupPrefix += pattern
r . curMiddlewares = append ( r . curMiddlewares , middlewares ... )
fn ( )
r . curGroupPrefix = previousGroupPrefix
r . curMiddlewares = previousMiddlewares
}
func ( r * Route ) getPattern ( pattern string ) string {
newPattern := r . curGroupPrefix + pattern
if ! strings . HasPrefix ( newPattern , "/" ) {
newPattern = "/" + newPattern
}
if newPattern == "/" {
return newPattern
}
return strings . TrimSuffix ( newPattern , "/" )
}
// Mount attaches another Route along ./pattern/*
func ( r * Route ) Mount ( pattern string , subR * Route ) {
2022-01-20 18:46:10 +01:00
middlewares := make ( [ ] interface { } , len ( r . curMiddlewares ) )
2021-01-26 23:36:53 +08:00
copy ( middlewares , r . curMiddlewares )
subR . Use ( middlewares ... )
r . R . Mount ( r . getPattern ( pattern ) , subR . R )
}
// Any delegate requests for all methods
func ( r * Route ) Any ( pattern string , h ... interface { } ) {
2022-01-20 18:46:10 +01:00
middlewares := r . getMiddlewares ( h )
2021-01-26 23:36:53 +08:00
r . R . HandleFunc ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
}
// Route delegate special methods
2021-12-20 05:41:31 +01:00
func ( r * Route ) Route ( pattern , methods string , h ... interface { } ) {
2021-01-26 23:36:53 +08:00
p := r . getPattern ( pattern )
ms := strings . Split ( methods , "," )
2022-01-20 18:46:10 +01:00
middlewares := r . getMiddlewares ( h )
2021-01-26 23:36:53 +08:00
for _ , method := range ms {
r . R . MethodFunc ( strings . TrimSpace ( method ) , p , Wrap ( middlewares ... ) )
}
}
// Delete delegate delete method
func ( r * Route ) Delete ( pattern string , h ... interface { } ) {
2022-01-20 18:46:10 +01:00
middlewares := r . getMiddlewares ( h )
2021-01-26 23:36:53 +08:00
r . R . Delete ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
}
func ( r * Route ) getMiddlewares ( h [ ] interface { } ) [ ] interface { } {
2022-01-20 18:46:10 +01:00
middlewares := make ( [ ] interface { } , len ( r . curMiddlewares ) , len ( r . curMiddlewares ) + len ( h ) )
2021-01-26 23:36:53 +08:00
copy ( middlewares , r . curMiddlewares )
middlewares = append ( middlewares , h ... )
return middlewares
}
// Get delegate get method
func ( r * Route ) Get ( pattern string , h ... interface { } ) {
2022-01-20 18:46:10 +01:00
middlewares := r . getMiddlewares ( h )
2021-01-26 23:36:53 +08:00
r . R . Get ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
}
2021-07-21 04:32:35 +01:00
// Options delegate options method
func ( r * Route ) Options ( pattern string , h ... interface { } ) {
2022-01-20 18:46:10 +01:00
middlewares := r . getMiddlewares ( h )
2021-07-21 04:32:35 +01:00
r . R . Options ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
}
// GetOptions delegate get and options method
func ( r * Route ) GetOptions ( pattern string , h ... interface { } ) {
2022-01-20 18:46:10 +01:00
middlewares := r . getMiddlewares ( h )
2021-07-21 04:32:35 +01:00
r . R . Get ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
r . R . Options ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
}
// PostOptions delegate post and options method
func ( r * Route ) PostOptions ( pattern string , h ... interface { } ) {
2022-01-20 18:46:10 +01:00
middlewares := r . getMiddlewares ( h )
2021-07-21 04:32:35 +01:00
r . R . Post ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
r . R . Options ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
}
2021-01-26 23:36:53 +08:00
// Head delegate head method
func ( r * Route ) Head ( pattern string , h ... interface { } ) {
2022-01-20 18:46:10 +01:00
middlewares := r . getMiddlewares ( h )
2021-01-26 23:36:53 +08:00
r . R . Head ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
}
// Post delegate post method
func ( r * Route ) Post ( pattern string , h ... interface { } ) {
2022-01-20 18:46:10 +01:00
middlewares := r . getMiddlewares ( h )
2021-01-26 23:36:53 +08:00
r . R . Post ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
}
// Put delegate put method
func ( r * Route ) Put ( pattern string , h ... interface { } ) {
2022-01-20 18:46:10 +01:00
middlewares := r . getMiddlewares ( h )
2021-01-26 23:36:53 +08:00
r . R . Put ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
}
// Patch delegate patch method
func ( r * Route ) Patch ( pattern string , h ... interface { } ) {
2022-01-20 18:46:10 +01:00
middlewares := r . getMiddlewares ( h )
2021-01-26 23:36:53 +08:00
r . R . Patch ( r . getPattern ( pattern ) , Wrap ( middlewares ... ) )
}
// ServeHTTP implements http.Handler
func ( r * Route ) ServeHTTP ( w http . ResponseWriter , req * http . Request ) {
r . R . ServeHTTP ( w , req )
}
// NotFound defines a handler to respond whenever a route could
// not be found.
func ( r * Route ) NotFound ( h http . HandlerFunc ) {
r . R . NotFound ( h )
}
// MethodNotAllowed defines a handler to respond whenever a method is
// not allowed.
func ( r * Route ) MethodNotAllowed ( h http . HandlerFunc ) {
r . R . MethodNotAllowed ( h )
}
// Combo deletegate requests to Combo
func ( r * Route ) Combo ( pattern string , h ... interface { } ) * Combo {
return & Combo { r , pattern , h }
}
// Combo represents a tiny group routes with same pattern
type Combo struct {
r * Route
pattern string
h [ ] interface { }
}
// Get deletegate Get method
func ( c * Combo ) Get ( h ... interface { } ) * Combo {
c . r . Get ( c . pattern , append ( c . h , h ... ) ... )
return c
}
// Post deletegate Post method
func ( c * Combo ) Post ( h ... interface { } ) * Combo {
c . r . Post ( c . pattern , append ( c . h , h ... ) ... )
return c
}
// Delete deletegate Delete method
func ( c * Combo ) Delete ( h ... interface { } ) * Combo {
c . r . Delete ( c . pattern , append ( c . h , h ... ) ... )
return c
}
// Put deletegate Put method
func ( c * Combo ) Put ( h ... interface { } ) * Combo {
c . r . Put ( c . pattern , append ( c . h , h ... ) ... )
return c
}
// Patch deletegate Patch method
func ( c * Combo ) Patch ( h ... interface { } ) * Combo {
c . r . Patch ( c . pattern , append ( c . h , h ... ) ... )
return c
}