From 91c46a99b0b9464d01b5aca2116bbe073b878725 Mon Sep 17 00:00:00 2001
From: cHengstler <69518287+cHengstler@users.noreply.github.com>
Date: Fri, 5 May 2023 19:30:13 +0200
Subject: [PATCH] fix: UriTemplate reserved expansion does not escape reserved
 chars (#1844)

When using UriTemplate.expand with a reserved expansion "{+var}", a set of allowed characters must not  be encoded. According to section of [3.2.3  Reserved Expansion: {+var}](https://www.rfc-editor.org/rfc/rfc6570#section-3.2.3), unreserved and reserved character should not be escaped.

This fix adds the missing characters `#[]` that must not be percent encoded when using reserved expansion.

- [x] Ensure the tests and linter pass
- [x] Code coverage does not decrease (if any source code was changed)
- [x] Appropriate docs were updated (if necessary)

Fixes #1838
---
 .../client/util/escape/PercentEscaper.java    | 11 +++++---
 .../api/client/http/UriTemplateTest.java      | 26 +++++++++++++++++++
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/google-http-client/src/main/java/com/google/api/client/util/escape/PercentEscaper.java b/google-http-client/src/main/java/com/google/api/client/util/escape/PercentEscaper.java
index 3866265a3..601b52c14 100644
--- a/google-http-client/src/main/java/com/google/api/client/util/escape/PercentEscaper.java
+++ b/google-http-client/src/main/java/com/google/api/client/util/escape/PercentEscaper.java
@@ -64,10 +64,15 @@ public class PercentEscaper extends UnicodeEscaper {
   public static final String SAFEPATHCHARS_URLENCODER = "-_.!~*'()@:$&,;=+";
 
   /**
-   * Contains the safe characters plus all reserved characters. This happens to be the safe path
-   * characters plus those characters which are reserved for URI segments, namely '/' and '?'.
+   * A string of characters that do not need to be encoded when used in URI Templates reserved
+   * expansion, as specified in RFC 6570. This includes the safe characters plus all reserved
+   * characters.
+   *
+   * <p>For details on escaping URI Templates using the reserved expansion, see <a
+   * href="https://www.rfc-editor.org/rfc/rfc6570#section-3.2.3">RFC 6570 - section 3.2.3</a>.
    */
-  public static final String SAFE_PLUS_RESERVED_CHARS_URLENCODER = SAFEPATHCHARS_URLENCODER + "/?";
+  public static final String SAFE_PLUS_RESERVED_CHARS_URLENCODER =
+      SAFEPATHCHARS_URLENCODER + "/?#[]";
 
   /**
    * A string of characters that do not need to be encoded when used in URI user info part, as
diff --git a/google-http-client/src/test/java/com/google/api/client/http/UriTemplateTest.java b/google-http-client/src/test/java/com/google/api/client/http/UriTemplateTest.java
index 1a38eeafa..14ebc61b6 100644
--- a/google-http-client/src/test/java/com/google/api/client/http/UriTemplateTest.java
+++ b/google-http-client/src/test/java/com/google/api/client/http/UriTemplateTest.java
@@ -322,4 +322,30 @@ public void testExpandSeveralTemplatesNoParametersUsed() {
     SortedMap<String, Object> map = Maps.newTreeMap();
     assertEquals("", UriTemplate.expand("{?id,uid}", map, false));
   }
+
+  public void testExpandTemplates_reservedExpansion_mustNotEscapeReservedCharSet() {
+
+    String reservedSet = ":/?#[]@!$&'()*+,;=";
+
+    SortedMap<String, Object> requestMap = Maps.newTreeMap();
+    requestMap.put("var", reservedSet);
+
+    assertEquals(
+        "Reserved expansion must not escape chars from reserved set according to rfc6570#section-3.2.3",
+        reservedSet,
+        UriTemplate.expand("{+var}", requestMap, false));
+  }
+
+  public void testExpandTemplates_reservedExpansion_mustNotEscapeUnreservedCharSet() {
+
+    String unReservedSet = "-._~";
+
+    SortedMap<String, Object> requestMap = Maps.newTreeMap();
+    requestMap.put("var", unReservedSet);
+
+    assertEquals(
+        "Reserved expansion must not escape chars from unreserved set according to rfc6570#section-3.2.3",
+        unReservedSet,
+        UriTemplate.expand("{+var}", requestMap, false));
+  }
 }