recover from panics such as out-of-bounds array access & nil pointer access, print a stack trace and return 5xx error instead of the service crashing and relying on Execution framework to handle crashes
89 lines
2.1 KiB
Go
89 lines
2.1 KiB
Go
package middleware
|
|
|
|
import (
|
|
"net/http"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
)
|
|
|
|
type (
|
|
// Skipper defines a function to skip middleware. Returning true skips processing
|
|
// the middleware.
|
|
Skipper func(echo.Context) bool
|
|
|
|
// BeforeFunc defines a function which is executed just before the middleware.
|
|
BeforeFunc func(echo.Context)
|
|
)
|
|
|
|
func captureTokens(pattern *regexp.Regexp, input string) *strings.Replacer {
|
|
groups := pattern.FindAllStringSubmatch(input, -1)
|
|
if groups == nil {
|
|
return nil
|
|
}
|
|
values := groups[0][1:]
|
|
replace := make([]string, 2*len(values))
|
|
for i, v := range values {
|
|
j := 2 * i
|
|
replace[j] = "$" + strconv.Itoa(i+1)
|
|
replace[j+1] = v
|
|
}
|
|
return strings.NewReplacer(replace...)
|
|
}
|
|
|
|
func rewriteRulesRegex(rewrite map[string]string) map[*regexp.Regexp]string {
|
|
// Initialize
|
|
rulesRegex := map[*regexp.Regexp]string{}
|
|
for k, v := range rewrite {
|
|
k = regexp.QuoteMeta(k)
|
|
k = strings.Replace(k, `\*`, "(.*?)", -1)
|
|
if strings.HasPrefix(k, `\^`) {
|
|
k = strings.Replace(k, `\^`, "^", -1)
|
|
}
|
|
k = k + "$"
|
|
rulesRegex[regexp.MustCompile(k)] = v
|
|
}
|
|
return rulesRegex
|
|
}
|
|
|
|
func rewriteURL(rewriteRegex map[*regexp.Regexp]string, req *http.Request) error {
|
|
if len(rewriteRegex) == 0 {
|
|
return nil
|
|
}
|
|
|
|
// Depending how HTTP request is sent RequestURI could contain Scheme://Host/path or be just /path.
|
|
// We only want to use path part for rewriting and therefore trim prefix if it exists
|
|
rawURI := req.RequestURI
|
|
if rawURI != "" && rawURI[0] != '/' {
|
|
prefix := ""
|
|
if req.URL.Scheme != "" {
|
|
prefix = req.URL.Scheme + "://"
|
|
}
|
|
if req.URL.Host != "" {
|
|
prefix += req.URL.Host // host or host:port
|
|
}
|
|
if prefix != "" {
|
|
rawURI = strings.TrimPrefix(rawURI, prefix)
|
|
}
|
|
}
|
|
|
|
for k, v := range rewriteRegex {
|
|
if replacer := captureTokens(k, rawURI); replacer != nil {
|
|
url, err := req.URL.Parse(replacer.Replace(v))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req.URL = url
|
|
|
|
return nil // rewrite only once
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DefaultSkipper returns false which processes the middleware.
|
|
func DefaultSkipper(echo.Context) bool {
|
|
return false
|
|
}
|