filter: Fix unparse to round-trip Unicode whitespace operands.

Previously [{operator: "topic", operand: "one\xa0two"}] would be
unparsed to "topic:one\xa0two" which parses as [{operator: "topic",
operand: "one"}, {operator: "search", operand: "two"}], leading to
exceptions in the search pill system.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2024-10-02 12:48:53 -07:00 committed by Tim Abbott
parent 81efecf463
commit 9c2da46966
2 changed files with 18 additions and 9 deletions

View File

@ -448,20 +448,19 @@ export class Filter {
This is just for the search bar, not for saving the
narrow in the URL fragment. There we do use full
URI encoding to avoid problematic characters. */
static encodeOperand(operand: string): string {
return operand
.replaceAll("%", "%25")
.replaceAll("+", "%2B")
.replaceAll(" ", "+")
.replaceAll('"', "%22");
static encodeOperand(operand: string, operator: string): string {
if (USER_OPERATORS.has(operator)) {
return operand.replaceAll(/[\s"%]/g, (c) => encodeURIComponent(c));
}
return operand.replaceAll(/[\s"%+]/g, (c) => (c === " " ? "+" : encodeURIComponent(c)));
}
static decodeOperand(encoded: string, operator: string): string {
encoded = encoded.replaceAll('"', "");
encoded = encoded.trim().replaceAll('"', "");
if (!USER_OPERATORS.has(operator)) {
encoded = encoded.replaceAll("+", " ");
}
return util.robust_url_decode(encoded).trim();
return util.robust_url_decode(encoded);
}
// Parse a string into a list of terms (see below).
@ -618,7 +617,9 @@ export class Filter {
return term.operand;
}
const operator = Filter.canonicalize_operator(term.operator);
return sign + operator + ":" + Filter.encodeOperand(term.operand.toString());
return (
sign + operator + ":" + Filter.encodeOperand(term.operand.toString(), term.operator)
);
});
return term_strings.join(" ");
}

View File

@ -1461,6 +1461,14 @@ test("unparse", () => {
];
string = `channel:${foo_stream_id} topic:Bar`;
assert.deepEqual(Filter.unparse(terms), string);
terms = [
{operator: "dm", operand: '\t "%+.\u00A0'},
{operator: "topic", operand: '\t "%+.\u00A0'},
];
string = "dm:%09%20%22%25+.%C2%A0 topic:%09+%22%25%2B.%C2%A0";
assert.equal(Filter.unparse(terms), string);
assert_same_terms(Filter.parse(string), terms);
});
test("describe", ({mock_template}) => {