From 8da5440c2d77aa922903badc302166a2efbc1471 Mon Sep 17 00:00:00 2001 From: Pete Cornish Date: Tue, 1 Oct 2024 15:48:24 +0100 Subject: [PATCH] fix: ignore invalid expressions when parsing config. --- .../imposter/config/util/ConfigUtil.kt | 2 +- .../gatehill/imposter/util/PlaceholderUtil.kt | 2 +- .../expression/util/ExpressionUtil.kt | 49 +++++++++++++------ .../expression/util/ExpressionUtilTest.kt | 24 ++++++++- 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/core/config/src/main/java/io/gatehill/imposter/config/util/ConfigUtil.kt b/core/config/src/main/java/io/gatehill/imposter/config/util/ConfigUtil.kt index b3f978eb4..456fc594a 100644 --- a/core/config/src/main/java/io/gatehill/imposter/config/util/ConfigUtil.kt +++ b/core/config/src/main/java/io/gatehill/imposter/config/util/ConfigUtil.kt @@ -263,7 +263,7 @@ object ConfigUtil { val configFile = configRef.file try { val rawContents = configFile.readText() - val parsedContents = ExpressionUtil.eval(rawContents, expressionEvaluators, nullifyUnsupported = false) + val parsedContents = ExpressionUtil.eval(rawContents, expressionEvaluators, onUnsupported = ExpressionUtil.UnsupportedBehaviour.IGNORE) val config = lookupMapper(configFile).readValue(parsedContents, LightweightConfig::class.java) config.plugin diff --git a/core/engine/src/main/java/io/gatehill/imposter/util/PlaceholderUtil.kt b/core/engine/src/main/java/io/gatehill/imposter/util/PlaceholderUtil.kt index 2e1d0c95b..0b48ee778 100644 --- a/core/engine/src/main/java/io/gatehill/imposter/util/PlaceholderUtil.kt +++ b/core/engine/src/main/java/io/gatehill/imposter/util/PlaceholderUtil.kt @@ -93,6 +93,6 @@ object PlaceholderUtil { evaluators: Map>, ): String { val context = mapOf(HttpExpressionEvaluator.HTTP_EXCHANGE_KEY to httpExchange) - return ExpressionUtil.eval(input, evaluators, context, queryProvider, nullifyUnsupported = true) + return ExpressionUtil.eval(input, evaluators, context, queryProvider, onUnsupported = ExpressionUtil.UnsupportedBehaviour.NULLIFY) } } diff --git a/core/expression/src/main/java/io/gatehill/imposter/expression/util/ExpressionUtil.kt b/core/expression/src/main/java/io/gatehill/imposter/expression/util/ExpressionUtil.kt index b6bc6c333..e6b9f7d31 100644 --- a/core/expression/src/main/java/io/gatehill/imposter/expression/util/ExpressionUtil.kt +++ b/core/expression/src/main/java/io/gatehill/imposter/expression/util/ExpressionUtil.kt @@ -64,6 +64,16 @@ object ExpressionUtil { */ private val expressionPattern = Pattern.compile("\\$\\{(.+?)}") + enum class UnsupportedBehaviour { + NULLIFY, + IGNORE, + } + + data class MatchResult( + val replace: Boolean, + val replacement: String? = null, + ) + /** * Evaluates an expression in the form: * ``` @@ -79,7 +89,7 @@ object ExpressionUtil { evaluators: Map>, context: Map = emptyMap(), queryProvider: QueryProvider? = null, - nullifyUnsupported: Boolean, + onUnsupported: UnsupportedBehaviour, ): String { val matcher = expressionPattern.matcher(input) var matched = false @@ -88,9 +98,14 @@ object ExpressionUtil { matched = true val expression = matcher.group(1) try { - val result = evalSingle(expression, evaluators, context, queryProvider, nullifyUnsupported) + val result = evalSingle(expression, evaluators, context, queryProvider, onUnsupported) LOGGER.trace("{}={}", expression, result) - matcher.appendReplacement(sb, result) + if (result.replace) { + matcher.appendReplacement(sb, result.replacement) + } else { + matcher.appendReplacement(sb, "") + sb.append(matcher.group(0)) + } } catch (e: Exception) { throw RuntimeException("Error evaluating expression: $expression", e) } @@ -108,24 +123,26 @@ object ExpressionUtil { evaluators: Map>, context: Map, queryProvider: QueryProvider?, - nullifyUnsupported: Boolean, - ): String? { - var result: String? = null - + onUnsupported: UnsupportedBehaviour, + ): MatchResult { val evaluator = lookupEvaluator(expression, evaluators) evaluator?.let { - result = loadAndQuery(expression, context, evaluator, queryProvider) ?: "" - + return MatchResult( + replace = true, + replacement = loadAndQuery(expression, context, evaluator, queryProvider) ?: "" + ) } ?: run { - if (nullifyUnsupported) { - LOGGER.warn("Unsupported expression: $expression") - result = "" - } else { - // don't replace; should ignore match - result = "\\\${$expression}" + when (onUnsupported) { + UnsupportedBehaviour.IGNORE -> { + LOGGER.trace("Ignoring unsupported expression: $expression") + return MatchResult(replace = false) + } + UnsupportedBehaviour.NULLIFY -> { + LOGGER.warn("Nullifying unsupported expression: $expression") + return MatchResult(replace = true, replacement = "") + } } } - return result } private fun lookupEvaluator( diff --git a/core/expression/src/test/java/io/gatehill/imposter/expression/util/ExpressionUtilTest.kt b/core/expression/src/test/java/io/gatehill/imposter/expression/util/ExpressionUtilTest.kt index fa2f3d127..e25a4a299 100644 --- a/core/expression/src/test/java/io/gatehill/imposter/expression/util/ExpressionUtilTest.kt +++ b/core/expression/src/test/java/io/gatehill/imposter/expression/util/ExpressionUtilTest.kt @@ -16,7 +16,7 @@ class ExpressionUtilTest { override fun eval(expression: String, context: Map) = null } ), - nullifyUnsupported = true, + onUnsupported = ExpressionUtil.UnsupportedBehaviour.NULLIFY, ) assertThat(result, equalTo("fallback")) @@ -27,8 +27,28 @@ class ExpressionUtilTest { val result = ExpressionUtil.eval( input = "\${invalid}", evaluators = emptyMap(), - nullifyUnsupported = true, + onUnsupported = ExpressionUtil.UnsupportedBehaviour.NULLIFY, ) assertThat(result, equalTo("")) } + + @Test + fun `ignore invalid expression`() { + val result = ExpressionUtil.eval( + input = "\${some.expression.with:\$inlineDollar}", + evaluators = emptyMap(), + onUnsupported = ExpressionUtil.UnsupportedBehaviour.IGNORE, + ) + assertThat(result, equalTo("\${some.expression.with:\$inlineDollar}")) + } + + @Test + fun `ignore multiple invalid expressions`() { + val result = ExpressionUtil.eval( + input = "\${some.expression.with:\$inlineDollar} and \${another.expression}", + evaluators = emptyMap(), + onUnsupported = ExpressionUtil.UnsupportedBehaviour.IGNORE, + ) + assertThat(result, equalTo("\${some.expression.with:\$inlineDollar} and \${another.expression}")) + } }