2021-06-09 02:33:54 +03:00
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package common
import (
"fmt"
"net/http"
"strings"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
2021-11-30 23:06:32 +03:00
"code.gitea.io/gitea/modules/process"
2021-06-09 02:33:54 +03:00
"code.gitea.io/gitea/modules/setting"
2022-01-20 14:41:25 +03:00
"code.gitea.io/gitea/modules/web/routing"
2021-06-09 02:33:54 +03:00
"github.com/chi-middleware/proxy"
2021-12-02 23:58:08 +03:00
"github.com/go-chi/chi/v5/middleware"
2021-06-09 02:33:54 +03:00
)
// Middlewares returns common middlewares
func Middlewares ( ) [ ] func ( http . Handler ) http . Handler {
2022-01-20 20:46:10 +03:00
handlers := [ ] func ( http . Handler ) http . Handler {
2021-06-09 02:33:54 +03:00
func ( next http . Handler ) http . Handler {
return http . HandlerFunc ( func ( resp http . ResponseWriter , req * http . Request ) {
2021-12-24 19:50:49 +03:00
// First of all escape the URL RawPath to ensure that all routing is done using a correctly escaped URL
req . URL . RawPath = req . URL . EscapedPath ( )
2022-03-31 20:01:43 +03:00
ctx , _ , finished := process . GetManager ( ) . AddTypedContext ( req . Context ( ) , fmt . Sprintf ( "%s: %s" , req . Method , req . RequestURI ) , process . RequestProcessType , true )
2021-11-30 23:06:32 +03:00
defer finished ( )
next . ServeHTTP ( context . NewResponse ( resp ) , req . WithContext ( ctx ) )
2021-06-09 02:33:54 +03:00
} )
} ,
}
if setting . ReverseProxyLimit > 0 {
opt := proxy . NewForwardedHeadersOptions ( ) .
WithForwardLimit ( setting . ReverseProxyLimit ) .
ClearTrustedProxies ( )
for _ , n := range setting . ReverseProxyTrustedProxies {
if ! strings . Contains ( n , "/" ) {
opt . AddTrustedProxy ( n )
} else {
opt . AddTrustedNetwork ( n )
}
}
handlers = append ( handlers , proxy . ForwardedHeaders ( opt ) )
}
handlers = append ( handlers , middleware . StripSlashes )
2022-01-20 14:41:25 +03:00
if ! setting . DisableRouterLog {
handlers = append ( handlers , routing . NewLoggerHandler ( ) )
2021-06-09 02:33:54 +03:00
}
2022-01-20 14:41:25 +03:00
2021-06-09 02:33:54 +03:00
if setting . EnableAccessLog {
handlers = append ( handlers , context . AccessLogger ( ) )
}
handlers = append ( handlers , func ( next http . Handler ) http . Handler {
return http . HandlerFunc ( func ( resp http . ResponseWriter , req * http . Request ) {
// Why we need this? The Recovery() will try to render a beautiful
// error page for user, but the process can still panic again, and other
// middleware like session also may panic then we have to recover twice
2022-01-20 14:41:25 +03:00
// and send a simple error page that should not panic anymore.
2021-06-09 02:33:54 +03:00
defer func ( ) {
if err := recover ( ) ; err != nil {
2022-01-20 14:41:25 +03:00
routing . UpdatePanicError ( req . Context ( ) , err )
combinedErr := fmt . Sprintf ( "PANIC: %v\n%s" , err , log . Stack ( 2 ) )
2021-06-09 02:33:54 +03:00
log . Error ( "%v" , combinedErr )
2021-10-20 17:37:19 +03:00
if setting . IsProd {
2022-03-23 07:54:07 +03:00
http . Error ( resp , http . StatusText ( http . StatusInternalServerError ) , http . StatusInternalServerError )
2021-06-09 02:33:54 +03:00
} else {
2022-03-23 07:54:07 +03:00
http . Error ( resp , combinedErr , http . StatusInternalServerError )
2021-06-09 02:33:54 +03:00
}
}
} ( )
next . ServeHTTP ( resp , req )
} )
} )
return handlers
}