You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2023/12/13 08:24:04 UTC
(httpcomponents-core) 37/37: Support for percent coding as defined in RFC 5987
This is an automated email from the ASF dual-hosted git repository.
olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git
commit e5ba6e1fab154d63d0387911253cefbba76eec25
Author: Arturo Bernal <ab...@apache.org>
AuthorDate: Fri Dec 8 18:54:32 2023 +0100
Support for percent coding as defined in RFC 5987
---
.../java/org/apache/hc/core5/net/PercentCodec.java | 70 +++++++++++++++++++++-
.../org/apache/hc/core5/net/TestPercentCodec.java | 30 ++++++++++
2 files changed, 99 insertions(+), 1 deletion(-)
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/net/PercentCodec.java b/httpcore5/src/main/java/org/apache/hc/core5/net/PercentCodec.java
index 2782282a4..40ebc9cb8 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/net/PercentCodec.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/net/PercentCodec.java
@@ -34,7 +34,7 @@ import java.nio.charset.StandardCharsets;
import java.util.BitSet;
/**
- * Percent-encoding mechanism defined in RFC 3986
+ * Percent-encoding.
*
* @since 5.1
*/
@@ -84,6 +84,35 @@ public class PercentCodec {
URIC.or(UNRESERVED);
}
+ static final BitSet RFC5987_UNRESERVED = new BitSet(256);
+
+ static {
+ // Alphanumeric characters
+ for (int i = 'a'; i <= 'z'; i++) {
+ RFC5987_UNRESERVED.set(i);
+ }
+ for (int i = 'A'; i <= 'Z'; i++) {
+ RFC5987_UNRESERVED.set(i);
+ }
+ for (int i = '0'; i <= '9'; i++) {
+ RFC5987_UNRESERVED.set(i);
+ }
+
+ // Additional characters as per RFC 5987 attr-char
+ RFC5987_UNRESERVED.set('!');
+ RFC5987_UNRESERVED.set('#');
+ RFC5987_UNRESERVED.set('$');
+ RFC5987_UNRESERVED.set('&');
+ RFC5987_UNRESERVED.set('+');
+ RFC5987_UNRESERVED.set('-');
+ RFC5987_UNRESERVED.set('.');
+ RFC5987_UNRESERVED.set('^');
+ RFC5987_UNRESERVED.set('_');
+ RFC5987_UNRESERVED.set('`');
+ RFC5987_UNRESERVED.set('|');
+ RFC5987_UNRESERVED.set('~');
+ }
+
private static final int RADIX = 16;
static void encode(final StringBuilder buf, final CharSequence content, final Charset charset,
@@ -160,4 +189,43 @@ public class PercentCodec {
return decode(content, charset, false);
}
+ public static final PercentCodec RFC3986 = new PercentCodec(UNRESERVED);
+ public static final PercentCodec RFC5987 = new PercentCodec(RFC5987_UNRESERVED);
+
+ private final BitSet unreserved;
+
+ private PercentCodec(final BitSet unreserved) {
+ this.unreserved = unreserved;
+ }
+
+ public PercentCodec() {
+ this.unreserved = UNRESERVED;
+ }
+
+ /**
+ * @since 5.3
+ */
+ public void encode(final StringBuilder buf, final CharSequence content) {
+ encode(buf, content, StandardCharsets.UTF_8, unreserved, false);
+ }
+
+ /**
+ * @since 5.3
+ */
+ public String encode(final CharSequence content) {
+ if (content == null) {
+ return null;
+ }
+ final StringBuilder buf = new StringBuilder();
+ encode(buf, content, StandardCharsets.UTF_8, unreserved, false);
+ return buf.toString();
+ }
+
+ /**
+ * @since 5.3
+ */
+ public String decode(final CharSequence content) {
+ return decode(content, StandardCharsets.UTF_8, false);
+ }
+
}
diff --git a/httpcore5/src/test/java/org/apache/hc/core5/net/TestPercentCodec.java b/httpcore5/src/test/java/org/apache/hc/core5/net/TestPercentCodec.java
index 99fe9a050..48ea00efb 100644
--- a/httpcore5/src/test/java/org/apache/hc/core5/net/TestPercentCodec.java
+++ b/httpcore5/src/test/java/org/apache/hc/core5/net/TestPercentCodec.java
@@ -28,11 +28,15 @@
package org.apache.hc.core5.net;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import java.nio.charset.StandardCharsets;
+import java.util.stream.Stream;
import org.hamcrest.CoreMatchers;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
/**
* Unit tests for {@link PercentCodec}.
@@ -68,4 +72,30 @@ public class TestPercentCodec {
CoreMatchers.equalTo("blah! %wa"));
}
+ @ParameterizedTest
+ @MethodSource("params")
+ public void testRfc5987EncodingDecoding(final String input, final String expected) {
+ assertEquals(expected, PercentCodec.RFC5987.encode(input));
+ assertEquals(input, PercentCodec.RFC5987.decode(expected));
+ }
+
+ static Stream<Object[]> params() {
+ return Stream.of(
+ new Object[]{"foo-ä-€.html", "foo-%C3%A4-%E2%82%AC.html"},
+ new Object[]{"世界ーファイル 2.jpg", "%E4%B8%96%E7%95%8C%E3%83%BC%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%202.jpg"},
+ new Object[]{"foo.jpg", "foo.jpg"},
+ new Object[]{"simple", "simple"}, // Unreserved characters
+ new Object[]{"reserved/chars?", "reserved%2Fchars%3F"}, // Reserved characters
+ new Object[]{"", ""}, // Empty string
+ new Object[]{"space test", "space%20test"}, // String with space
+ new Object[]{"ümlaut", "%C3%BCmlaut"} // Non-ASCII characters
+ );
+ }
+
+ @Test
+ public void verifyRfc5987EncodingandDecoding() {
+ final String s = "!\"$£%^&*()_-+={[}]:@~;'#,./<>?\\|✓éèæðŃœ";
+ assertThat(PercentCodec.RFC5987.decode(PercentCodec.RFC5987.encode(s)), CoreMatchers.equalTo(s));
+ }
+
}