Skip to content

Commit

Permalink
fix(webserver): allow special chars in label key (#7419)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuri1969 authored Feb 19, 2025
1 parent ce15ca1 commit f1670b8
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
@Singleton
public class QueryFilterFormatBinder implements AnnotatedRequestArgumentBinder<QueryFilterFormat, List<QueryFilter>> {

private static final Pattern FILTER_PATTERN = Pattern.compile("filters\\[(.*?)\\]\\[(.*?)](?:\\[(\\w+)])?");
private static final Pattern FILTER_PATTERN = Pattern.compile("filters\\[(.*?)]\\[(.*?)](?:\\[(.+)])?");

@VisibleForTesting
static List<QueryFilter> getQueryFilters(Map<String, List<String>> queryParams) {
Expand All @@ -32,26 +32,7 @@ static List<QueryFilter> getQueryFilters(Map<String, List<String>> queryParams)
Matcher matcher = FILTER_PATTERN.matcher(key);

if (matcher.matches()) {
String fieldStr = matcher.group(1);
String operationStr = matcher.group(2);
String nestedKey = matcher.group(3); // Extract nested key if present

QueryFilter.Field field = QueryFilter.Field.fromString(fieldStr);
QueryFilter.Op operation = QueryFilter.Op.fromString(operationStr);

Object value = nestedKey != null ? Map.of(nestedKey, values.getFirst()) :
switch (field) {
case SCOPE -> RequestUtils.toFlowScopes(values);
default -> (operation == QueryFilter.Op.IN || operation == QueryFilter.Op.NOT_IN)
? List.of(URLDecoder.decode(values.getFirst(), StandardCharsets.UTF_8).replaceAll("[\\[\\]]", "").split(","))
: values.size() == 1 ? values.getFirst() : values;
};

filters.add(QueryFilter.builder()
.field(field)
.operation(operation)
.value(value)
.build());
parseFilters(values, matcher, filters);
}
});

Expand All @@ -72,4 +53,29 @@ public BindingResult<List<QueryFilter>> bind(ArgumentConversionContext<List<Quer
return () -> Optional.of(filters);
}

private static void parseFilters(List<String> values, Matcher matcher, List<QueryFilter> filters) {
String fieldStr = matcher.group(1);
String operationStr = matcher.group(2);
String nestedKey = matcher.group(3); // Extract nested key if present

QueryFilter.Field field = QueryFilter.Field.fromString(fieldStr);
QueryFilter.Op operation = QueryFilter.Op.fromString(operationStr);

Object value = nestedKey != null ? Map.of(nestedKey, values.getFirst()) : getFlatValue(values, field, operation);

filters.add(QueryFilter.builder()
.field(field)
.operation(operation)
.value(value)
.build());
}

private static Object getFlatValue(List<String> values, QueryFilter.Field field, QueryFilter.Op operation) {
return switch (field) {
case SCOPE -> RequestUtils.toFlowScopes(values);
default -> (operation == QueryFilter.Op.IN || operation == QueryFilter.Op.NOT_IN)
? List.of(URLDecoder.decode(values.getFirst(), StandardCharsets.UTF_8).replaceAll("[\\[\\]]", "").split(","))
: values.size() == 1 ? values.getFirst() : values;
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void testGetQueryFiltersWithSimpleFilters() {
void testGetQueryFiltersWithNestedFilters() {
// GIVEN
Map<String, List<String>> queryParams = Map.of(
"filters[labels][$eq][key]", List.of("value")
"filters[labels][$eq][key with special chars [(_-|&/*^)]]", List.of("value with special chars [(_-|&/*^)]")
);

// WHEN
Expand All @@ -54,10 +54,10 @@ void testGetQueryFiltersWithNestedFilters() {
// THEN
assertEquals(1, filters.size());

QueryFilter filter = filters.get(0);
QueryFilter filter = filters.getFirst();
assertEquals(QueryFilter.Field.LABELS, filter.field());
assertEquals(QueryFilter.Op.EQUALS, filter.operation());
assertEquals(Map.of("key", "value"), filter.value());
assertEquals(Map.of("key with special chars [(_-|&/*^)]", "value with special chars [(_-|&/*^)]"), filter.value());
}

@Test
Expand All @@ -70,8 +70,8 @@ void testGetQueryFiltersWithScopeParsing() {
List<QueryFilter> filters = QueryFilterFormatBinder.getQueryFilters(queryParams);
// THEN
assertEquals(1, filters.size());
assertEquals(QueryFilter.Field.SCOPE, filters.get(0).field());
assertEquals(RequestUtils.toFlowScopes(List.of("USER,SYSTEM")), filters.get(0).value());
assertEquals(QueryFilter.Field.SCOPE, filters.getFirst().field());
assertEquals(RequestUtils.toFlowScopes(List.of("USER,SYSTEM")), filters.getFirst().value());
}

@Test
Expand Down

0 comments on commit f1670b8

Please sign in to comment.