|
@@ -34,8 +34,10 @@ import java.io.InputStream;
|
|
|
import java.io.InputStreamReader;
|
|
|
import java.io.UncheckedIOException;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
+import java.util.ArrayList;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.Iterator;
|
|
|
+import java.util.List;
|
|
|
import java.util.Locale;
|
|
|
import java.util.Map;
|
|
|
import java.util.Collections;
|
|
@@ -74,8 +76,6 @@ public final class Grok {
|
|
|
private final Map<String, String> patternBank;
|
|
|
private final boolean namedCaptures;
|
|
|
private final Regex compiledExpression;
|
|
|
- private final String expression;
|
|
|
-
|
|
|
|
|
|
public Grok(Map<String, String> patternBank, String grokPattern) {
|
|
|
this(patternBank, grokPattern, true);
|
|
@@ -86,11 +86,59 @@ public final class Grok {
|
|
|
this.patternBank = patternBank;
|
|
|
this.namedCaptures = namedCaptures;
|
|
|
|
|
|
- this.expression = toRegex(grokPattern);
|
|
|
+ for (Map.Entry<String, String> entry : patternBank.entrySet()) {
|
|
|
+ String name = entry.getKey();
|
|
|
+ String pattern = entry.getValue();
|
|
|
+ forbidCircularReferences(name, new ArrayList<>(), pattern);
|
|
|
+ }
|
|
|
+
|
|
|
+ String expression = toRegex(grokPattern);
|
|
|
byte[] expressionBytes = expression.getBytes(StandardCharsets.UTF_8);
|
|
|
this.compiledExpression = new Regex(expressionBytes, 0, expressionBytes.length, Option.DEFAULT, UTF8Encoding.INSTANCE);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Checks whether patterns reference each other in a circular manner and if so fail with an exception
|
|
|
+ *
|
|
|
+ * In a pattern, anything between <code>%{</code> and <code>}</code> or <code>:</code> is considered
|
|
|
+ * a reference to another named pattern. This method will navigate to all these named patterns and
|
|
|
+ * check for a circular reference.
|
|
|
+ */
|
|
|
+ private void forbidCircularReferences(String patternName, List<String> path, String pattern) {
|
|
|
+ if (pattern.contains("%{" + patternName + "}") || pattern.contains("%{" + patternName + ":")) {
|
|
|
+ String message;
|
|
|
+ if (path.isEmpty()) {
|
|
|
+ message = "circular reference in pattern [" + patternName + "][" + pattern + "]";
|
|
|
+ } else {
|
|
|
+ message = "circular reference in pattern [" + path.remove(path.size() - 1) + "][" + pattern +
|
|
|
+ "] back to pattern [" + patternName + "]";
|
|
|
+ // add rest of the path:
|
|
|
+ if (path.isEmpty() == false) {
|
|
|
+ message += " via patterns [" + String.join("=>", path) + "]";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ throw new IllegalArgumentException(message);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = pattern.indexOf("%{"); i != -1; i = pattern.indexOf("%{", i + 1)) {
|
|
|
+ int begin = i + 2;
|
|
|
+ int brackedIndex = pattern.indexOf('}', begin);
|
|
|
+ int columnIndex = pattern.indexOf(':', begin);
|
|
|
+ int end;
|
|
|
+ if (brackedIndex != -1 && columnIndex == -1) {
|
|
|
+ end = brackedIndex;
|
|
|
+ } else if (columnIndex != -1 && brackedIndex == -1) {
|
|
|
+ end = columnIndex;
|
|
|
+ } else if (brackedIndex != -1 && columnIndex != -1) {
|
|
|
+ end = Math.min(brackedIndex, columnIndex);
|
|
|
+ } else {
|
|
|
+ throw new IllegalArgumentException("pattern [" + pattern + "] has circular references to other pattern definitions");
|
|
|
+ }
|
|
|
+ String otherPatternName = pattern.substring(begin, end);
|
|
|
+ path.add(otherPatternName);
|
|
|
+ forbidCircularReferences(patternName, path, patternBank.get(otherPatternName));
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
public String groupMatch(String name, Region region, String pattern) {
|
|
|
try {
|
|
@@ -125,10 +173,12 @@ public final class Grok {
|
|
|
String patternName = groupMatch(PATTERN_GROUP, region, grokPattern);
|
|
|
|
|
|
String pattern = patternBank.get(patternName);
|
|
|
-
|
|
|
if (pattern == null) {
|
|
|
throw new IllegalArgumentException("Unable to find pattern [" + patternName + "] in Grok's pattern dictionary");
|
|
|
}
|
|
|
+ if (pattern.contains("%{" + patternName + "}") || pattern.contains("%{" + patternName + ":")) {
|
|
|
+ throw new IllegalArgumentException("circular reference in pattern back [" + patternName + "]");
|
|
|
+ }
|
|
|
|
|
|
String grokPart;
|
|
|
if (namedCaptures && subName != null) {
|