Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for quoted (default) MongoDB search term values in SearchQueryParser (6.1) #21606

Open
wants to merge 1 commit into
base: 6.1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog/unreleased/issue-21565.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type = "fixed"
message = "Fixed issue preventing quoted entity search values from finding exact matches on various pages throughout Graylog."

issues = ["21565"]
pulls = ["21567"]
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,16 @@ public class SearchQueryParser {
private static final Splitter FIELD_VALUE_SPLITTER = Splitter.on(":").limit(2).omitEmptyStrings().trimResults();
private static final Splitter VALUE_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();

// Pattern to split a search query into individual parsable elements terms.
private static final String TERM_SPLIT_PATTERN =
"(\\S+:(=|=~|<|<=|>|>=)?'(?:[^'\\\\]|\\\\.)*')|" + // Split field-specific terms with single-quotes: title:'value'
"(\\S+:(=|=~|<|<=|>|>=)?\"(?:[^\"\\\\]|\\\\.)*\")|" + // Split field-specific terms with double-quotes title:"value"
"['\"][^\\\\]*?(?:\\\\.[^\\\\]*)*?['\"]|" + // Split single quoted value: "value one"
"\\S+:(=|=~|<|<=|>|>=)?\\S+|" + // Split field-specific terms without quotes title:value
"\\S+"; // Split the words of any other string value

// This needs to be updated if more operators are added
private static final Pattern QUERY_SPLITTER_PATTERN = Pattern.compile("(\\S+:(=|=~|<|<=|>|>=)?'(?:[^'\\\\]|\\\\.)*')|(\\S+:(=|=~|<|<=|>|>=)?\"(?:[^\"\\\\]|\\\\.)*\")|\\S+|\\S+:(=|=~|<|<=|>|>=)?\\S+");
private static final Pattern QUERY_SPLITTER_PATTERN = Pattern.compile(TERM_SPLIT_PATTERN);
private static final String INVALID_ENTRY_MESSAGE = "Chunk [%s] is not a valid entry";
private static final String QUOTE_REPLACE_REGEX = "^[\"']|[\"']$";
public static final SearchQueryOperator DEFAULT_STRING_OPERATOR = SearchQueryOperators.REGEXP;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,31 @@ void emptyFieldPrefixDoesNotChangeDefaultBehavior() {
assertThat(searchQuery.hasDisallowedKeys()).isFalse();
}

@Test
void unquotedEmptyFieldPrefixSingleSearchTerm() {
final SearchQueryParser parser = new SearchQueryParser("name", Set.of(), "");
// Verify unquoted term is split into two search values.
final SearchQuery searchQuery = parser.parse("Bobby testerson");
final Multimap<String, SearchQueryParser.FieldValue> queryMap = searchQuery.getQueryMap();
assertThat(queryMap.keySet().size()).isEqualTo(1);
final Collection<SearchQueryParser.FieldValue> values = queryMap.get("name");
assertThat(values.size()).isEqualTo(2);
assertThat(values).contains(new SearchQueryParser.FieldValue("Bobby", false));
assertThat(values).contains(new SearchQueryParser.FieldValue("testerson", false));
}

@Test
void quotedEmptyFieldPrefixSingleSearchTerm() {
final SearchQueryParser parser = new SearchQueryParser("name", Set.of(), "");
// Verify quoted term is maintained as a single search value.
final SearchQuery searchQuery = parser.parse("\"Bobby testerson\"");
final Multimap<String, SearchQueryParser.FieldValue> queryMap = searchQuery.getQueryMap();
assertThat(queryMap.keySet().size()).isEqualTo(1);
final Collection<SearchQueryParser.FieldValue> values = queryMap.get("name");
assertThat(values.size()).isEqualTo(1);
assertThat(values).containsOnly(new SearchQueryParser.FieldValue("Bobby testerson", false));
}

@Test
void booleanValuesSupported() {
final SearchQueryParser parser = new SearchQueryParser("name",
Expand Down
Loading