diff --git a/Makefile b/Makefile index f9e5afb09..c07d8bb45 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,6 @@ benchmark: ## Run benchmarks help: ## Display this help screen @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -goversion ?= "1.19" -test_version: ## Run tests inside Docker with given version (defaults to 1.19 oldest supported). Example: make test_version goversion=1.19 +goversion ?= "1.20" +test_version: ## Run tests inside Docker with given version (defaults to 1.20 oldest supported). Example: make test_version goversion=1.20 @docker run --rm -it -v $(shell pwd):/project golang:$(goversion) /bin/sh -c "cd /project && make init check" diff --git a/middleware/cors.go b/middleware/cors.go index 7af6a76f3..a1f445321 100644 --- a/middleware/cors.go +++ b/middleware/cors.go @@ -147,13 +147,25 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc { config.AllowMethods = DefaultCORSConfig.AllowMethods } - allowOriginPatterns := []string{} + allowOriginPatterns := make([]*regexp.Regexp, 0, len(config.AllowOrigins)) for _, origin := range config.AllowOrigins { + if origin == "*" { + continue // "*" is handled differently and does not need regexp + } pattern := regexp.QuoteMeta(origin) pattern = strings.ReplaceAll(pattern, "\\*", ".*") pattern = strings.ReplaceAll(pattern, "\\?", ".") pattern = "^" + pattern + "$" - allowOriginPatterns = append(allowOriginPatterns, pattern) + + re, err := regexp.Compile(pattern) + if err != nil { + // this is to preserve previous behaviour - invalid patterns were just ignored. + // If we would turn this to panic, users with invalid patterns + // would have applications crashing in production due unrecovered panic. + // TODO: this should be turned to error/panic in `v5` + continue + } + allowOriginPatterns = append(allowOriginPatterns, re) } allowMethods := strings.Join(config.AllowMethods, ",") @@ -239,7 +251,7 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc { } if checkPatterns { for _, re := range allowOriginPatterns { - if match, _ := regexp.MatchString(re, origin); match { + if match := re.MatchString(origin); match { allowOrigin = origin break } diff --git a/middleware/cors_test.go b/middleware/cors_test.go index 64e5c6542..5461e9362 100644 --- a/middleware/cors_test.go +++ b/middleware/cors_test.go @@ -31,6 +31,18 @@ func TestCORS(t *testing.T) { name: "ok, wildcard AllowedOrigin with no Origin header in request", notExpectHeaders: map[string]string{echo.HeaderAccessControlAllowOrigin: ""}, }, + { + name: "ok, invalid pattern is ignored", + givenMW: CORSWithConfig(CORSConfig{ + AllowOrigins: []string{ + "\xff", // Invalid UTF-8 makes regexp.Compile to error + "*.example.com", + }, + }), + whenMethod: http.MethodOptions, + whenHeaders: map[string]string{echo.HeaderOrigin: "http://aaa.example.com"}, + expectHeaders: map[string]string{echo.HeaderAccessControlAllowOrigin: "http://aaa.example.com"}, + }, { name: "ok, specific AllowOrigins and AllowCredentials", givenMW: CORSWithConfig(CORSConfig{