From 1ec155c76f3f0d91a743693b6bf9a4512b90e291 Mon Sep 17 00:00:00 2001 From: Jacob Moore Date: Mon, 24 Jun 2024 19:41:09 -0400 Subject: [PATCH] OPENAPI: added better logging to path rewriting. Specifically, if an identifier is provided in a path config, it now ends up in the log message. --- config/paths.go | 130 +++++++++++++++++++++++----------------- config/paths_test.go | 16 ++--- daemon/api.go | 11 +++- daemon/build_request.go | 4 +- 4 files changed, 94 insertions(+), 67 deletions(-) diff --git a/config/paths.go b/config/paths.go index daa4a3c..cd1c89f 100644 --- a/config/paths.go +++ b/config/paths.go @@ -15,6 +15,11 @@ const ( RewriteIdHeader = "RewriteId" ) +type PathRewrite struct { + RewrittenPath string + PathConfiguration *shared.WiretapPathConfig +} + func FindPaths(path string, configuration *shared.WiretapConfiguration) []*shared.WiretapPathConfig { var foundConfigurations []*shared.WiretapPathConfig for x := configuration.CompiledPaths.First(); x != nil; x = x.Next() { @@ -72,7 +77,7 @@ func PathValidationAllowListed(path string, configuration *shared.WiretapConfigu return false } -func rewriteTaget(path string, pathConfig *shared.WiretapPathConfig, configuration *shared.WiretapConfiguration) string { +func rewriteTaget(path string, pathConfig *shared.WiretapPathConfig, configuration *shared.WiretapConfiguration) *PathRewrite { scheme := "http://" if pathConfig.Secure { scheme = "https://" @@ -83,7 +88,10 @@ func rewriteTaget(path string, pathConfig *shared.WiretapPathConfig, configurati if path[0] != '/' && pathConfig.Target[len(pathConfig.Target)-1] != '/' { path = fmt.Sprintf("/%s", path) } - return fmt.Sprintf("%s%s%s", scheme, target, path) + return &PathRewrite{ + RewrittenPath: fmt.Sprintf("%s%s%s", scheme, target, path), + PathConfiguration: pathConfig, + } } func FindPathWithRewriteId(paths []*shared.WiretapPathConfig, req *http.Request) *shared.WiretapPathConfig { @@ -108,76 +116,90 @@ func FindPathWithRewriteId(paths []*shared.WiretapPathConfig, req *http.Request) return nil } -func RewritePath(path string, req *http.Request, configuration *shared.WiretapConfiguration) string { +func RewritePath(path string, req *http.Request, configuration *shared.WiretapConfiguration) *PathRewrite { paths := FindPaths(path, configuration) - var replaced = path - if len(paths) > 0 { - var pathConfig *shared.WiretapPathConfig + // If there are no configurations that match the request path, we should crash out early + if len(paths) == 0 { + return &PathRewrite{ + RewrittenPath: path, + PathConfiguration: nil, + } + } - // Check if request headers have rewrite id; if so, we should try to find a matching rewrite config - pathConfig = FindPathWithRewriteId(paths, req) + var pathConfig *shared.WiretapPathConfig - // if rewriteId not specified in request or not found, extract first path - if pathConfig == nil { - pathConfig = paths[0] - } + // Check if request headers have rewrite id; if so, we should try to find a matching rewrite config + pathConfig = FindPathWithRewriteId(paths, req) + + // if rewriteId not specified in request or not found, extract first path + if pathConfig == nil { + pathConfig = paths[0] + } - replaced = "" - - for _, globalIgnoreRewrite := range configuration.CompiledIgnorePathRewrite { - // If the current path matches the ignore rewrite, we should skip rewriting, - // and instead check if we even want to rewrite the target - if globalIgnoreRewrite.CompiledIgnoreRewrite.Match(path) { - if globalIgnoreRewrite.RewriteTarget { - return rewriteTaget(path, pathConfig, configuration) - } else { - pterm.Info.Printf("[wiretap] Not re-writing path '%s' due to global ignore rewrite configuration\n", path) - return path + for _, globalIgnoreRewrite := range configuration.CompiledIgnorePathRewrite { + // If the current path matches the ignore rewrite, we should skip rewriting, + // and instead check if we even want to rewrite the target + if globalIgnoreRewrite.CompiledIgnoreRewrite.Match(path) { + if globalIgnoreRewrite.RewriteTarget { + return rewriteTaget(path, pathConfig, configuration) + } else { + pterm.Info.Printf("[wiretap] Not re-writing path '%s' due to global ignore rewrite configuration\n", path) + return &PathRewrite{ + RewrittenPath: path, + PathConfiguration: pathConfig, } } } + } - for key := range pathConfig.CompiledPath.CompiledPathRewrite { - if pathConfig.CompiledPath.CompiledPathRewrite[key].MatchString(path) { - - // Check if this path matches a local ignore rewrite. If so, then check if we need to rewrite the target - for _, ignoreRewrite := range pathConfig.CompiledIgnoreRewrite { - if ignoreRewrite.CompiledIgnoreRewrite.Match(path) { - if ignoreRewrite.RewriteTarget { - return rewriteTaget(path, pathConfig, configuration) - } else { - pterm.Info.Printf("[wiretap] Not re-writing path '%s' due to local ignore rewrite configuration\n", path) - return path + var replaced = "" + + for key := range pathConfig.CompiledPath.CompiledPathRewrite { + if pathConfig.CompiledPath.CompiledPathRewrite[key].MatchString(path) { + + // Check if this path matches a local ignore rewrite. If so, then check if we need to rewrite the target + for _, ignoreRewrite := range pathConfig.CompiledIgnoreRewrite { + if ignoreRewrite.CompiledIgnoreRewrite.Match(path) { + if ignoreRewrite.RewriteTarget { + return rewriteTaget(path, pathConfig, configuration) + } else { + pterm.Info.Printf("[wiretap] Not re-writing path '%s' due to local ignore rewrite configuration\n", path) + return &PathRewrite{ + RewrittenPath: path, + PathConfiguration: pathConfig, } } } + } - replace := pathConfig.PathRewrite[key] - rex := pathConfig.CompiledPath.CompiledPathRewrite[key] - replacedPath := rex.ReplaceAllString(path, replace) - - scheme := "http://" - if pathConfig.Secure { - scheme = "https://" - } - if replacedPath[0] != '/' && pathConfig.Target[len(pathConfig.Target)-1] != '/' { - replacedPath = fmt.Sprintf("/%s", replacedPath) - } - target := strings.ReplaceAll(strings.ReplaceAll(configuration.ReplaceWithVariables(pathConfig.Target), - "http://", ""), "https://", "") + replace := pathConfig.PathRewrite[key] + rex := pathConfig.CompiledPath.CompiledPathRewrite[key] + replacedPath := rex.ReplaceAllString(path, replace) - replaced = fmt.Sprintf("%s%s%s", scheme, target, replacedPath) - break + scheme := "http://" + if pathConfig.Secure { + scheme = "https://" } - } + if replacedPath[0] != '/' && pathConfig.Target[len(pathConfig.Target)-1] != '/' { + replacedPath = fmt.Sprintf("/%s", replacedPath) + } + target := strings.ReplaceAll(strings.ReplaceAll(configuration.ReplaceWithVariables(pathConfig.Target), + "http://", ""), "https://", "") - // no rewriting, just replace target. - if replaced == "" { - replaced = rewriteTaget(path, pathConfig, configuration) + replaced = fmt.Sprintf("%s%s%s", scheme, target, replacedPath) + break } + } + // If we already replaced the path, then we should just return that + if replaced != "" { + return &PathRewrite{ + RewrittenPath: replaced, + PathConfiguration: pathConfig, + } } - return replaced + // Otherwise, there's no rewriting, and we just try to replace the target. + return rewriteTaget(path, pathConfig, configuration) } diff --git a/config/paths_test.go b/config/paths_test.go index c3e3eac..c52a377 100644 --- a/config/paths_test.go +++ b/config/paths_test.go @@ -85,7 +85,7 @@ paths: wcConfig.CompilePaths() path := RewritePath("/pb33f/test/123/slap/a/chap", nil, &wcConfig) - assert.Equal(t, "http://localhost:9093/123/slap/a/chap", path) + assert.Equal(t, "http://localhost:9093/123/slap/a/chap", path.RewrittenPath) } @@ -105,7 +105,7 @@ paths: wcConfig.CompilePaths() path := RewritePath("/pb33f/cakes/test/123/smelly/jelly", nil, &wcConfig) - assert.Equal(t, "https://localhost:9093/flat/jam/123/smelly/jelly", path) + assert.Equal(t, "https://localhost:9093/flat/jam/123/smelly/jelly", path.RewrittenPath) } @@ -125,7 +125,7 @@ paths: wcConfig.CompilePaths() path := RewritePath("/pb33f/cakes/test/lemons/321/smelly/jelly", nil, &wcConfig) - assert.Equal(t, "https://localhost:9093/slippy/cakes/whip/321/lemons/smelly/jelly", path) + assert.Equal(t, "https://localhost:9093/slippy/cakes/whip/321/lemons/smelly/jelly", path.RewrittenPath) } @@ -148,7 +148,7 @@ paths: c.CompilePaths() path := RewritePath("/en-US/burgerd/__raw/noKetchupPlease/nobody/", nil, &c) - assert.Equal(t, "http://localhost:80/noKetchupPlease/-/", path) + assert.Equal(t, "http://localhost:80/noKetchupPlease/-/", path.RewrittenPath) } @@ -171,7 +171,7 @@ paths: c.CompilePaths() path := RewritePath("/en-US/burgerd/__raw/noKetchupPlease/nobody/yummy/yum?onions=true", nil, &c) - assert.Equal(t, "http://localhost:80/noKetchupPlease/-/yummy/yum?onions=true", path) + assert.Equal(t, "http://localhost:80/noKetchupPlease/-/yummy/yum?onions=true", path.RewrittenPath) } @@ -210,7 +210,7 @@ paths: } path := RewritePath("/pb33f/test/id", req, &c) - assert.Equal(t, "https://localhost:9093/pb33f/correct/id", path) + assert.Equal(t, "https://localhost:9093/pb33f/correct/id", path.RewrittenPath) actualConfig := FindPathWithRewriteId(pathConfigs, req) expectedConfig := pathConfigs[1] // second config is the valid one @@ -244,7 +244,7 @@ paths: } path := RewritePath("/pb33f/test/id", req, &c) - assert.Equal(t, "https://localhost:9093/pb33f/correct/id", path) + assert.Equal(t, "https://localhost:9093/pb33f/correct/id", path.RewrittenPath) } @@ -277,7 +277,7 @@ paths: } path := RewritePath("/pb33f/test/id", req, &c) - assert.Equal(t, "https://localhost:9093/pb33f/correct/id", path) + assert.Equal(t, "https://localhost:9093/pb33f/correct/id", path.RewrittenPath) } diff --git a/daemon/api.go b/daemon/api.go index fec0b45..e645192 100644 --- a/daemon/api.go +++ b/daemon/api.go @@ -46,12 +46,17 @@ func (ws *WiretapService) callAPI(req *http.Request) (*http.Response, error) { // lookup path and determine if we need to redirect it. replaced := config.RewritePath(req.URL.Path, req, wiretapConfig) - if replaced != req.URL.Path { - newUrl, _ := url.Parse(replaced) + if replaced.RewrittenPath != req.URL.Path { + newUrl, _ := url.Parse(replaced.RewrittenPath) if req.URL.RawQuery != "" { newUrl.RawQuery = req.URL.RawQuery } - pterm.Info.Printf("[wiretap] Re-writing path '%s' to '%s'\n", req.URL.String(), newUrl.String()) + if replaced.PathConfiguration != nil && replaced.PathConfiguration.RewriteId != "" { + rewriteId := replaced.PathConfiguration.RewriteId + pterm.Info.Printf("[wiretap] Re-writing path '%s' to '%s' with identifier '%s'\n", req.URL.String(), newUrl.String(), rewriteId) + } else { + pterm.Info.Printf("[wiretap] Re-writing path '%s' to '%s'\n", req.URL.String(), newUrl.String()) + } req.URL = newUrl } diff --git a/daemon/build_request.go b/daemon/build_request.go index a4c5044..abd45b3 100644 --- a/daemon/build_request.go +++ b/daemon/build_request.go @@ -136,9 +136,9 @@ func BuildHttpTransaction(build HttpTransactionConfig) *HttpTransaction { replaced := config.RewritePath(build.NewRequest.URL.Path, newReq, cf) var newUrl = build.NewRequest.URL - if replaced != "" { + if replaced.RewrittenPath != "" { var e error - newUrl, e = url.Parse(replaced) + newUrl, e = url.Parse(replaced.RewrittenPath) if e != nil { newUrl = build.NewRequest.URL pterm.Error.Printf("major configuration problem: cannot parse URL: `%s`: %s", replaced, e.Error())