diff --git a/middleware/body_dump.go b/middleware/body_dump.go index 88b75ee1..14cf33d1 100644 --- a/middleware/body_dump.go +++ b/middleware/body_dump.go @@ -33,7 +33,7 @@ type ( ) var ( - // DefaultBodyDumpConfig is the default Gzip middleware config. + // DefaultBodyDumpConfig is the default BodyDump middleware config. DefaultBodyDumpConfig = BodyDumpConfig{ Skipper: DefaultSkipper, } diff --git a/middleware/body_limit.go b/middleware/body_limit.go index b964cd29..8d8281f4 100644 --- a/middleware/body_limit.go +++ b/middleware/body_limit.go @@ -17,7 +17,7 @@ type ( // Maximum allowed size for a request body, it can be specified // as `4x` or `4xB`, where x is one of the multiple from K, M, G, T or P. - Limit string `json:"limit"` + Limit string `yaml:"limit"` limit int64 } diff --git a/middleware/compress.go b/middleware/compress.go index 1615624c..b876009c 100644 --- a/middleware/compress.go +++ b/middleware/compress.go @@ -20,7 +20,7 @@ type ( // Gzip compression level. // Optional. Default value -1. - Level int `json:"level"` + Level int `yaml:"level"` } gzipResponseWriter struct { diff --git a/middleware/cors.go b/middleware/cors.go index c35fc36c..771000a5 100644 --- a/middleware/cors.go +++ b/middleware/cors.go @@ -16,34 +16,34 @@ type ( // AllowOrigin defines a list of origins that may access the resource. // Optional. Default value []string{"*"}. - AllowOrigins []string `json:"allow_origins"` + AllowOrigins []string `yaml:"allow_origins"` // AllowMethods defines a list methods allowed when accessing the resource. // This is used in response to a preflight request. // Optional. Default value DefaultCORSConfig.AllowMethods. - AllowMethods []string `json:"allow_methods"` + AllowMethods []string `yaml:"allow_methods"` // AllowHeaders defines a list of request headers that can be used when // making the actual request. This in response to a preflight request. // Optional. Default value []string{}. - AllowHeaders []string `json:"allow_headers"` + AllowHeaders []string `yaml:"allow_headers"` // AllowCredentials indicates whether or not the response to the request // can be exposed when the credentials flag is true. When used as part of // a response to a preflight request, this indicates whether or not the // actual request can be made using credentials. // Optional. Default value false. - AllowCredentials bool `json:"allow_credentials"` + AllowCredentials bool `yaml:"allow_credentials"` // ExposeHeaders defines a whitelist headers that clients are allowed to // access. // Optional. Default value []string{}. - ExposeHeaders []string `json:"expose_headers"` + ExposeHeaders []string `yaml:"expose_headers"` // MaxAge indicates how long (in seconds) the results of a preflight request // can be cached. // Optional. Default value 0. - MaxAge int `json:"max_age"` + MaxAge int `yaml:"max_age"` } ) diff --git a/middleware/csrf.go b/middleware/csrf.go index 5bbeecb4..0d2b7fd6 100644 --- a/middleware/csrf.go +++ b/middleware/csrf.go @@ -18,7 +18,7 @@ type ( Skipper Skipper // TokenLength is the length of the generated token. - TokenLength uint8 `json:"token_length"` + TokenLength uint8 `yaml:"token_length"` // Optional. Default value 32. // TokenLookup is a string in the form of ":" that is used @@ -28,35 +28,35 @@ type ( // - "header:" // - "form:" // - "query:" - TokenLookup string `json:"token_lookup"` + TokenLookup string `yaml:"token_lookup"` // Context key to store generated CSRF token into context. // Optional. Default value "csrf". - ContextKey string `json:"context_key"` + ContextKey string `yaml:"context_key"` // Name of the CSRF cookie. This cookie will store CSRF token. // Optional. Default value "csrf". - CookieName string `json:"cookie_name"` + CookieName string `yaml:"cookie_name"` // Domain of the CSRF cookie. // Optional. Default value none. - CookieDomain string `json:"cookie_domain"` + CookieDomain string `yaml:"cookie_domain"` // Path of the CSRF cookie. // Optional. Default value none. - CookiePath string `json:"cookie_path"` + CookiePath string `yaml:"cookie_path"` // Max age (in seconds) of the CSRF cookie. // Optional. Default value 86400 (24hr). - CookieMaxAge int `json:"cookie_max_age"` + CookieMaxAge int `yaml:"cookie_max_age"` // Indicates if CSRF cookie is secure. // Optional. Default value false. - CookieSecure bool `json:"cookie_secure"` + CookieSecure bool `yaml:"cookie_secure"` // Indicates if CSRF cookie is HTTP only. // Optional. Default value false. - CookieHTTPOnly bool `json:"cookie_http_only"` + CookieHTTPOnly bool `yaml:"cookie_http_only"` } // csrfTokenExtractor defines a function that takes `echo.Context` and returns diff --git a/middleware/key_auth.go b/middleware/key_auth.go index 75d2f146..4990afd9 100644 --- a/middleware/key_auth.go +++ b/middleware/key_auth.go @@ -21,7 +21,7 @@ type ( // - "header:" // - "query:" // - "form:" - KeyLookup string `json:"key_lookup"` + KeyLookup string `yaml:"key_lookup"` // AuthScheme to be used in the Authorization header. // Optional. Default value "Bearer". diff --git a/middleware/logger.go b/middleware/logger.go index b9c54468..dfba093c 100644 --- a/middleware/logger.go +++ b/middleware/logger.go @@ -46,7 +46,7 @@ type ( // Example "${remote_ip} ${status}" // // Optional. Default value DefaultLoggerConfig.Format. - Format string `json:"format"` + Format string `yaml:"format"` // Output is a writer where logs in JSON format are written. // Optional. Default value os.Stdout. diff --git a/middleware/proxy_test.go b/middleware/proxy_test.go index 017bb5eb..06d93166 100644 --- a/middleware/proxy_test.go +++ b/middleware/proxy_test.go @@ -87,7 +87,7 @@ func TestProxy(t *testing.T) { // Rewrite e = echo.New() - e.Pre(ProxyWithConfig(ProxyConfig{ + e.Use(ProxyWithConfig(ProxyConfig{ Balancer: rrb, Rewrite: map[string]string{ "/old": "/new", diff --git a/middleware/recover.go b/middleware/recover.go index 687a198a..2a42c5b1 100644 --- a/middleware/recover.go +++ b/middleware/recover.go @@ -15,16 +15,16 @@ type ( // Size of the stack to be printed. // Optional. Default value 4KB. - StackSize int `json:"stack_size"` + StackSize int `yaml:"stack_size"` // DisableStackAll disables formatting stack traces of all other goroutines // into buffer after the trace for the current goroutine. // Optional. Default value false. - DisableStackAll bool `json:"disable_stack_all"` + DisableStackAll bool `yaml:"disable_stack_all"` // DisablePrintStack disables printing stack trace. // Optional. Default value as false. - DisablePrintStack bool `json:"disable_print_stack"` + DisablePrintStack bool `yaml:"disable_print_stack"` } ) diff --git a/middleware/redirect.go b/middleware/redirect.go index b87dab09..6017ddbb 100644 --- a/middleware/redirect.go +++ b/middleware/redirect.go @@ -14,7 +14,7 @@ type ( // Status code to be used when redirecting the request. // Optional. Default value http.StatusMovedPermanently. - Code int `json:"code"` + Code int `yaml:"code"` } ) diff --git a/middleware/rewrite.go b/middleware/rewrite.go new file mode 100644 index 00000000..fc8fd9a0 --- /dev/null +++ b/middleware/rewrite.go @@ -0,0 +1,83 @@ +package middleware + +import ( + "regexp" + "strings" + + "github.com/labstack/echo" +) + +type ( + // RewriteConfig defines the config for Rewrite middleware. + RewriteConfig struct { + // Skipper defines a function to skip middleware. + Skipper Skipper + + // Rules defines the URL path rewrite rules. The values captured in asterisk can be + // retrieved by index e.g. $1, $2 and so on. + // Examples: + // "/old": "/new", + // "/api/*": "/$1", + // "/js/*": "/public/javascripts/$1", + // "/users/*/orders/*": "/user/$1/order/$2", + // Required. + Rules map[string]string `yaml:"rules"` + + rulesRegex map[*regexp.Regexp]string + } +) + +var ( + // DefaultRewriteConfig is the default Rewrite middleware config. + DefaultRewriteConfig = RewriteConfig{ + Skipper: DefaultSkipper, + } +) + +// Rewrite returns a Rewrite middleware. +// +// Rewrite middleware rewrites the URL path based on the provided rules. +func Rewrite(rules map[string]string) echo.MiddlewareFunc { + c := DefaultRewriteConfig + c.Rules = rules + return RewriteWithConfig(c) +} + +// RewriteWithConfig returns a Rewrite middleware with config. +// See: `Rewrite()`. +func RewriteWithConfig(config RewriteConfig) echo.MiddlewareFunc { + // Defaults + if config.Rules == nil { + panic("echo: rewrite middleware requires url path rewrite rules") + } + if config.Skipper == nil { + config.Skipper = DefaultBodyDumpConfig.Skipper + } + config.rulesRegex = map[*regexp.Regexp]string{} + + // Initialize + for k, v := range config.Rules { + k = strings.Replace(k, "*", "(\\S*)", -1) + config.rulesRegex[regexp.MustCompile(k)] = v + } + + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) (err error) { + if config.Skipper(c) { + return next(c) + } + + req := c.Request() + + // Rewrite + for k, v := range config.rulesRegex { + replacer := captureTokens(k, req.URL.Path) + if replacer != nil { + req.URL.Path = replacer.Replace(v) + } + } + + return + } + } +} diff --git a/middleware/rewrite_test.go b/middleware/rewrite_test.go new file mode 100644 index 00000000..56e9c9d2 --- /dev/null +++ b/middleware/rewrite_test.go @@ -0,0 +1,35 @@ +package middleware + +import ( + "net/http/httptest" + "testing" + + "github.com/labstack/echo" + "github.com/stretchr/testify/assert" +) + +func TestRewrite(t *testing.T) { + e := echo.New() + e.Use(RewriteWithConfig(RewriteConfig{ + Rules: map[string]string{ + "/old": "/new", + "/api/*": "/$1", + "/js/*": "/public/javascripts/$1", + "/users/*/orders/*": "/user/$1/order/$2", + }, + })) + req := httptest.NewRequest(echo.GET, "/", nil) + rec := httptest.NewRecorder() + req.URL.Path = "/api/users" + e.ServeHTTP(rec, req) + assert.Equal(t, "/users", req.URL.Path) + req.URL.Path = "/js/main.js" + e.ServeHTTP(rec, req) + assert.Equal(t, "/public/javascripts/main.js", req.URL.Path) + req.URL.Path = "/old" + e.ServeHTTP(rec, req) + assert.Equal(t, "/new", req.URL.Path) + req.URL.Path = "/users/jack/orders/1" + e.ServeHTTP(rec, req) + assert.Equal(t, "/user/jack/order/1", req.URL.Path) +} diff --git a/middleware/secure.go b/middleware/secure.go index 0125e74a..188c0c40 100644 --- a/middleware/secure.go +++ b/middleware/secure.go @@ -15,12 +15,12 @@ type ( // XSSProtection provides protection against cross-site scripting attack (XSS) // by setting the `X-XSS-Protection` header. // Optional. Default value "1; mode=block". - XSSProtection string `json:"xss_protection"` + XSSProtection string `yaml:"xss_protection"` // ContentTypeNosniff provides protection against overriding Content-Type // header by setting the `X-Content-Type-Options` header. // Optional. Default value "nosniff". - ContentTypeNosniff string `json:"content_type_nosniff"` + ContentTypeNosniff string `yaml:"content_type_nosniff"` // XFrameOptions can be used to indicate whether or not a browser should // be allowed to render a page in a ,