+
+ @Override
+ void appendTo(final StringBuilder sb) {
+ super.appendTo(sb);
+ sb.append('=');
+ final var it = keyValues.iterator();
+ while (true) {
+ sb.append(PERCENT_ESCAPER.escape(it.next()));
+ if (it.hasNext()) {
+ sb.append(',');
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ // Escaper based on RFC8040-requirement to percent-encode reserved characters, as defined in
+ // https://tools.ietf.org/html/rfc3986#section-2.2
+ public static final Escaper PERCENT_ESCAPER;
+
+ static {
+ final var hexFormat = HexFormat.of().withUpperCase();
+ final var builder = Escapers.builder();
+ for (char ch : new char[] {
+ // Reserved characters as per https://tools.ietf.org/html/rfc3986#section-2.2
+ ':', '/', '?', '#', '[', ']', '@',
+ '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=',
+ // FIXME: this space should not be here, but that was a day-0 bug and we have asserts on this
+ ' '
+ }) {
+ builder.addEscape(ch, "%" + hexFormat.toHighHexDigit(ch) + hexFormat.toLowHexDigit(ch));
+ }
+ PERCENT_ESCAPER = builder.build();