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 2022/05/28 13:52:30 UTC
[httpcomponents-client] branch master updated: HTTPCLIENT-2218: Use Java 8 Base64 utility (#370)
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-client.git
The following commit(s) were added to refs/heads/master by this push:
new 5b0733ad5 HTTPCLIENT-2218: Use Java 8 Base64 utility (#370)
5b0733ad5 is described below
commit 5b0733ad5dfca583f852bbb456c8578d2203c1d8
Author: j3graham <j3...@gmail.com>
AuthorDate: Sat May 28 09:52:24 2022 -0400
HTTPCLIENT-2218: Use Java 8 Base64 utility (#370)
---
.../cache/memcached/SHA256KeyHashingScheme.java | 2 +-
.../testing/auth/BasicAuthTokenExtractor.java | 8 +-
.../http/impl/win/WindowsNegotiateScheme.java | 2 +-
httpclient5/pom.xml | 4 -
.../http/entity/mime/HttpRFC7578Multipart.java | 11 +-
.../hc/client5/http/impl/auth/BasicScheme.java | 2 +-
.../hc/client5/http/impl/auth/GGSSchemeBase.java | 2 +-
.../hc/client5/http/impl/auth/NTLMEngineImpl.java | 2 +-
.../org/apache/hc/client5/http/utils/Base64.java | 164 +++++++++++++++++++++
.../java/org/apache/hc/client5/http/utils/Hex.java | 94 ++++++++++++
.../http/entity/mime/HttpRFC7578MultipartTest.java | 3 +-
.../hc/client5/http/impl/auth/TestBasicScheme.java | 10 +-
.../apache/hc/client5/http/utils/TestBase64.java | 129 ++++++++++++++++
pom.xml | 6 -
14 files changed, 407 insertions(+), 32 deletions(-)
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/SHA256KeyHashingScheme.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/SHA256KeyHashingScheme.java
index 10a1c3f37..898b40569 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/SHA256KeyHashingScheme.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/memcached/SHA256KeyHashingScheme.java
@@ -29,7 +29,7 @@ package org.apache.hc.client5.http.impl.cache.memcached;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import org.apache.commons.codec.binary.Hex;
+import org.apache.hc.client5.http.utils.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/BasicAuthTokenExtractor.java b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/BasicAuthTokenExtractor.java
index a57605788..b07dc9ccf 100644
--- a/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/BasicAuthTokenExtractor.java
+++ b/httpclient5-testing/src/main/java/org/apache/hc/client5/testing/auth/BasicAuthTokenExtractor.java
@@ -29,9 +29,7 @@ package org.apache.hc.client5.testing.auth;
import java.nio.charset.StandardCharsets;
-import org.apache.commons.codec.BinaryDecoder;
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.binary.Base64;
+import org.apache.hc.client5.http.utils.Base64;
import org.apache.hc.client5.http.auth.StandardAuthScheme;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.ProtocolException;
@@ -49,9 +47,9 @@ public class BasicAuthTokenExtractor {
final String s = challengeResponse.substring(i + 1).trim();
try {
final byte[] credsRaw = s.getBytes(StandardCharsets.US_ASCII);
- final BinaryDecoder codec = new Base64();
+ final Base64 codec = new Base64();
return new String(codec.decode(credsRaw), StandardCharsets.US_ASCII);
- } catch (final DecoderException ex) {
+ } catch (final IllegalArgumentException ex) {
throw new ProtocolException("Malformed Basic credentials");
}
}
diff --git a/httpclient5-win/src/main/java/org/apache/hc/client5/http/impl/win/WindowsNegotiateScheme.java b/httpclient5-win/src/main/java/org/apache/hc/client5/http/impl/win/WindowsNegotiateScheme.java
index 0daed7e7e..da1a629ff 100644
--- a/httpclient5-win/src/main/java/org/apache/hc/client5/http/impl/win/WindowsNegotiateScheme.java
+++ b/httpclient5-win/src/main/java/org/apache/hc/client5/http/impl/win/WindowsNegotiateScheme.java
@@ -28,7 +28,7 @@ package org.apache.hc.client5.http.impl.win;
import java.security.Principal;
-import org.apache.commons.codec.binary.Base64;
+import org.apache.hc.client5.http.utils.Base64;
import org.apache.hc.client5.http.RouteInfo;
import org.apache.hc.client5.http.auth.AuthChallenge;
import org.apache.hc.client5.http.auth.AuthScheme;
diff --git a/httpclient5/pom.xml b/httpclient5/pom.xml
index 77695c9bd..9f234c88e 100644
--- a/httpclient5/pom.xml
+++ b/httpclient5/pom.xml
@@ -77,10 +77,6 @@
<artifactId>log4j-core</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- </dependency>
<dependency>
<groupId>org.brotli</groupId>
<artifactId>dec</artifactId>
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/entity/mime/HttpRFC7578Multipart.java b/httpclient5/src/main/java/org/apache/hc/client5/http/entity/mime/HttpRFC7578Multipart.java
index 485605783..64407f08f 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/entity/mime/HttpRFC7578Multipart.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/entity/mime/HttpRFC7578Multipart.java
@@ -36,7 +36,6 @@ import java.nio.charset.StandardCharsets;
import java.util.BitSet;
import java.util.List;
-import org.apache.commons.codec.DecoderException;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.util.ByteArrayBuffer;
@@ -129,7 +128,7 @@ class HttpRFC7578Multipart extends AbstractMultipartFormat {
return buffer.toByteArray();
}
- public byte[] decode(final byte[] bytes) throws DecoderException {
+ public byte[] decode(final byte[] bytes) {
if (bytes == null) {
return null;
}
@@ -138,7 +137,7 @@ class HttpRFC7578Multipart extends AbstractMultipartFormat {
final int b = bytes[i];
if (b == ESCAPE_CHAR) {
if (i >= bytes.length - 2) {
- throw new DecoderException("Invalid URL encoding: too short");
+ throw new IllegalArgumentException("Invalid encoding: too short");
}
final int u = digit16(bytes[++i]);
final int l = digit16(bytes[++i]);
@@ -163,13 +162,13 @@ class HttpRFC7578Multipart extends AbstractMultipartFormat {
* The byte to be converted.
* @return The numeric value represented by the character in radix 16.
*
- * @throws DecoderException
+ * @throws IllegalArgumentException
* Thrown when the byte is not valid per {@link Character#digit(char,int)}
*/
- static int digit16(final byte b) throws DecoderException {
+ static int digit16(final byte b) {
final int i = Character.digit((char) b, RADIX);
if (i == -1) {
- throw new DecoderException("Invalid URL encoding: not a valid digit (radix " + RADIX + "): " + b);
+ throw new IllegalArgumentException("Invalid encoding: not a valid digit (radix " + RADIX + "): " + b);
}
return i;
}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java
index 43cf32a61..87d11448c 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java
@@ -39,7 +39,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
-import org.apache.commons.codec.binary.Base64;
+import org.apache.hc.client5.http.utils.Base64;
import org.apache.hc.client5.http.auth.AuthChallenge;
import org.apache.hc.client5.http.auth.AuthScheme;
import org.apache.hc.client5.http.auth.AuthScope;
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java
index 86e40a626..b8c6ed8ed 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/GGSSchemeBase.java
@@ -29,7 +29,7 @@ package org.apache.hc.client5.http.impl.auth;
import java.net.UnknownHostException;
import java.security.Principal;
-import org.apache.commons.codec.binary.Base64;
+import org.apache.hc.client5.http.utils.Base64;
import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
import org.apache.hc.client5.http.auth.AuthChallenge;
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java
index 3bf9f61ed..fa0548da0 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/NTLMEngineImpl.java
@@ -40,7 +40,7 @@ import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
-import org.apache.commons.codec.binary.Base64;
+import org.apache.hc.client5.http.utils.Base64;
import org.apache.hc.client5.http.utils.ByteArrayBuilder;
/**
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/utils/Base64.java b/httpclient5/src/main/java/org/apache/hc/client5/http/utils/Base64.java
new file mode 100644
index 000000000..20216a7ee
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/utils/Base64.java
@@ -0,0 +1,164 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.client5.http.utils;
+
+
+import org.apache.hc.core5.annotation.Internal;
+
+import static java.util.Base64.getEncoder;
+import static java.util.Base64.getMimeDecoder;
+
+/**
+ * Provide implementations of the Base64 conversion methods from Commons Codec, delegating to the Java Base64
+ * implementation.
+ * <p>
+ * * <ul>Only the features currently used by HttpClient are implemented here rather than all the features of Commons Codec</ul>
+ * Notes:
+ * <p>
+ * <ul>Commons Codec accepts null inputs, so this is also accepted here. This is not done in the Java 8 implementation</ul>
+ * <ul>Decoding invalid input returns an empty value. The Java 8 implementation throws an exception, which is caught here</ul>
+ * <ul>Commons Codec decoders accept both standard and url-safe variants of input. As this is not a requirement for
+ * HttpClient, this is NOT implemented here.
+ * </ul>
+ * <p>
+ * This class is intended as in interim convenience. Any new code should use `java.util.Base64` directly.
+ */
+@Internal
+public class Base64 {
+ private static final Base64 CODEC = new Base64();
+ private static final byte[] EMPTY_BYTES = new byte[0];
+
+ /**
+ * Return an instance of the Base64 codec that use the regular Base64 alphabet
+ * (as opposed to the URL-safe alphabet). Note that unlike the Commons Codec version,
+ * thus class will NOT decode characters from URL-safe alphabet.
+ */
+ public Base64() {
+ }
+
+ /**
+ * Creates a Base64 codec used for decoding and encoding in URL-unsafe mode.
+ * <p>
+ * As HttpClient never uses a non-zero length, this feature is not implemented here.
+ */
+
+ public Base64(final int lineLength) {
+ if (lineLength != 0) {
+ throw new UnsupportedOperationException("Line breaks not supported");
+ }
+ }
+
+ /**
+ * Decodes Base64 data into octets.
+ * <p>
+ * <b>Note:</b> this method does NOT accept URL-safe encodings
+ */
+ public static byte[] decodeBase64(final byte[] base64) {
+ return CODEC.decode(base64);
+ }
+
+ /**
+ * Decodes a Base64 String into octets.
+ * <p>
+ * <b>Note:</b> this method does NOT accept URL-safe encodings
+ */
+
+ public static byte[] decodeBase64(final String base64) {
+ return CODEC.decode(base64);
+ }
+
+ /**
+ * Encodes binary data using the base64 algorithm but does not chunk the output.
+ */
+
+ public static byte[] encodeBase64(final byte[] base64) {
+ return CODEC.encode(base64);
+ }
+
+ /**
+ * Encodes binary data using the base64 algorithm but does not chunk the output.
+ */
+
+ public static String encodeBase64String(final byte[] bytes) {
+ if (null == bytes) {
+ return null;
+ }
+
+ return getEncoder().encodeToString(bytes);
+ }
+
+ /**
+ * Decode Base64-encoded bytes to their original form, using specifications from this codec instance
+ */
+
+ public byte[] decode(final byte[] base64) {
+ if (null == base64) {
+ return null;
+ }
+
+ try {
+ return getMimeDecoder().decode(base64);
+ } catch (final IllegalArgumentException e) {
+ return EMPTY_BYTES;
+ }
+ }
+
+ /**
+ * Decode a Base64 String to its original form, using specifications from this codec instance
+ */
+
+ public byte[] decode(final String base64) {
+ if (null == base64) {
+ return null;
+ }
+
+ try {
+
+ // getMimeDecoder is used instead of getDecoder as it better matches the
+ // functionality of the default Commons Codec implementation (primarily more forgiving of strictly
+ // invalid inputs to decode)
+ // Code using java.util.Base64 directly should make a choice based on whether this forgiving nature is
+ // appropriate.
+
+ return getMimeDecoder().decode(base64);
+ } catch (final IllegalArgumentException e) {
+ return EMPTY_BYTES;
+ }
+ }
+
+ /**
+ * Encode bytes to their Base64 form, using specifications from this codec instance
+ */
+ public byte[] encode(final byte[] value) {
+ if (null == value) {
+ return null;
+ }
+ return getEncoder().encode(value);
+ }
+
+}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/utils/Hex.java b/httpclient5/src/main/java/org/apache/hc/client5/http/utils/Hex.java
new file mode 100644
index 000000000..b3f6f6f4f
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/utils/Hex.java
@@ -0,0 +1,94 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+
+package org.apache.hc.client5.http.utils;
+
+import org.apache.hc.core5.annotation.Internal;
+
+@Internal
+public class Hex {
+
+ private Hex() {
+ }
+
+ public static String encodeHexString(final byte[] bytes) {
+
+ final char[] out = new char[bytes.length * 2];
+
+ encodeHex(bytes, 0, bytes.length, DIGITS_LOWER, out, 0);
+ return new String(out);
+ }
+
+ //
+ // The following comes from commons-codec
+ // https://github.com/apache/commons-codec/blob/master/src/main/java/org/apache/commons/codec/binary/Hex.java
+
+ /**
+ * Used to build output as hex.
+ */
+
+ private static final char[] DIGITS_LOWER = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ /**
+ * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
+ *
+ * @param data a byte[] to convert to hex characters
+ * @param dataOffset the position in {@code data} to start encoding from
+ * @param dataLen the number of bytes from {@code dataOffset} to encode
+ * @param toDigits the output alphabet (must contain at least 16 chars)
+ * @param out a char[] which will hold the resultant appropriate characters from the alphabet.
+ * @param outOffset the position within {@code out} at which to start writing the encoded characters.
+ */
+ private static void encodeHex(final byte[] data, final int dataOffset, final int dataLen, final char[] toDigits,
+ final char[] out, final int outOffset) {
+ // two characters form the hex value.
+ for (int i = dataOffset, j = outOffset; i < dataOffset + dataLen; i++) {
+ out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
+ out[j++] = toDigits[0x0F & data[i]];
+ }
+ }
+
+ /*
+
+ // Can be replaced in Java 17 with the following:
+
+
+ private static final java.util.HexFormat HEX_FORMAT = HexFormat.of();
+
+ public static String encodeHex(byte[] bytes) {
+ return HEX_FORMAT.formatHex(bytes);
+ }
+
+
+ */
+
+
+}
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/entity/mime/HttpRFC7578MultipartTest.java b/httpclient5/src/test/java/org/apache/hc/client5/http/entity/mime/HttpRFC7578MultipartTest.java
index b8cb4e013..870482a1f 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/entity/mime/HttpRFC7578MultipartTest.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/entity/mime/HttpRFC7578MultipartTest.java
@@ -29,7 +29,6 @@ package org.apache.hc.client5.http.entity.mime;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import org.apache.commons.codec.DecoderException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -37,7 +36,7 @@ public class HttpRFC7578MultipartTest {
@Test
public void testPercentDecodingWithTooShortMessage() throws Exception {
- Assertions.assertThrows(DecoderException.class, () ->
+ Assertions.assertThrows(java.lang.IllegalArgumentException.class, () ->
new HttpRFC7578Multipart.PercentCodec().decode("%".getBytes()));
}
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicScheme.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicScheme.java
index 5cd4b257b..252fa89af 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicScheme.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicScheme.java
@@ -31,9 +31,9 @@ import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.charset.StandardCharsets;
+import java.util.Base64;
import java.util.List;
-import org.apache.commons.codec.binary.Base64;
import org.apache.hc.client5.http.auth.AuthChallenge;
import org.apache.hc.client5.http.auth.AuthScheme;
import org.apache.hc.client5.http.auth.AuthScope;
@@ -55,6 +55,7 @@ import org.junit.jupiter.api.Test;
* Basic authentication test cases.
*/
public class TestBasicScheme {
+ private static final Base64.Encoder BASE64_ENC = Base64.getEncoder();
private static AuthChallenge parse(final String s) throws ParseException {
final CharArrayBuffer buffer = new CharArrayBuffer(s.length());
@@ -90,9 +91,10 @@ public class TestBasicScheme {
Assertions.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
final String authResponse = authscheme.generateAuthResponse(host, request, null);
- final String expected = "Basic " + new String(
- Base64.encodeBase64("testuser:testpass".getBytes(StandardCharsets.US_ASCII)),
- StandardCharsets.US_ASCII);
+ final byte[] testCreds = "testuser:testpass".getBytes(StandardCharsets.US_ASCII);
+
+ final String expected = "Basic " + BASE64_ENC.encodeToString(testCreds);
+
Assertions.assertEquals(expected, authResponse);
Assertions.assertEquals("test", authscheme.getRealm());
Assertions.assertTrue(authscheme.isChallengeComplete());
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestBase64.java b/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestBase64.java
new file mode 100644
index 000000000..53307dbbf
--- /dev/null
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestBase64.java
@@ -0,0 +1,129 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+
+package org.apache.hc.client5.http.utils;
+
+import org.junit.jupiter.api.Test;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class TestBase64 {
+
+ public static final char CHAR_ZERO = 0;
+ public static final String EMPTY_STR = "";
+ public static final byte[] EMPTY_BYTES = new byte[0];
+ public static final String NULL_STR = null;
+ public static final byte[] NULL_BYTE_ARRAY = null;
+ public static final String EMOJI = "\uD83D\uDE15";
+ public static final char SPACE = ' ';
+
+ private final Base64 target = new Base64();
+
+ @Test
+ void nullHandling() {
+ assertNull(target.decode(NULL_STR));
+ assertNull(target.decode(NULL_BYTE_ARRAY));
+ assertNull(Base64.decodeBase64(NULL_STR));
+ assertNull(Base64.decodeBase64(NULL_BYTE_ARRAY));
+
+ assertNull(target.encode(NULL_BYTE_ARRAY));
+ assertNull(Base64.encodeBase64(NULL_BYTE_ARRAY));
+ assertNull(Base64.encodeBase64String(NULL_BYTE_ARRAY));
+ }
+
+ @Test
+ void zeroLength() {
+ assertArrayEquals(EMPTY_BYTES, target.decode(EMPTY_STR));
+ assertArrayEquals(EMPTY_BYTES, target.decode(EMPTY_BYTES));
+ assertArrayEquals(EMPTY_BYTES, Base64.decodeBase64(EMPTY_STR));
+ assertArrayEquals(EMPTY_BYTES, Base64.decodeBase64(EMPTY_BYTES));
+
+ assertArrayEquals(EMPTY_BYTES, target.encode(EMPTY_BYTES));
+ assertArrayEquals(EMPTY_BYTES, Base64.encodeBase64(EMPTY_BYTES));
+ assertEquals(EMPTY_STR, Base64.encodeBase64String(EMPTY_BYTES));
+ }
+
+ @Test
+ void validValues() {
+ final byte[] unencodedBytes = "Hello World!".getBytes(US_ASCII);
+ checkDecode(unencodedBytes, "SGVsbG8gV29ybGQh");
+ checkEncode("SGVsbG8gV29ybGQh", unencodedBytes);
+ }
+
+ @Test
+ void decodeIgnoresEmbeddedInvalidChars() {
+ checkEquivalentDecode(fourOf("A"), " A A A A ");
+ checkEquivalentDecode(fourOf("A"), "AA" + EMOJI + "AA");
+ }
+
+ @Test
+ void decodeInvalid() {
+ checkDecode(EMPTY_BYTES, fourOf(EMOJI));
+ checkDecode(EMPTY_BYTES, "A");
+ checkDecode(EMPTY_BYTES, "A===");
+ checkDecode(EMPTY_BYTES, fourOf(SPACE));
+ checkDecode(EMPTY_BYTES, fourOf('='));
+ checkDecode(EMPTY_BYTES, fourOf('@'));
+ checkDecode(EMPTY_BYTES, fourOf(CHAR_ZERO));
+ }
+
+ @Test
+ void decodeUnpadded() {
+ checkEquivalentDecode("AA==", "AA");
+ }
+
+ private void checkDecode(final byte[] expectedDecoded, final String testInput) {
+ final byte[] decoded = target.decode(testInput);
+ assertArrayEquals(expectedDecoded, decoded);
+ }
+
+ private void checkEncode(final String expectedEncoded, final byte[] testInput) {
+ final byte[] encoded = target.encode(testInput);
+ assertEquals(expectedEncoded, new String(encoded, US_ASCII));
+ }
+
+ private void checkEquivalentDecode(final String expectedEquivalentTo, final String testInput) {
+ final byte[] decoded = target.decode(testInput);
+
+ final byte[] expectedDecoded = java.util.Base64.getDecoder().decode(expectedEquivalentTo);
+ assertArrayEquals(expectedDecoded, decoded);
+ }
+
+ private static String fourOf(final char c) {
+ final String charStr = String.valueOf(c);
+ return fourOf(charStr);
+ }
+
+ private static String fourOf(final String str) {
+ return str + str + str + str;
+ }
+
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 3d12b1b94..6224f7e69 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,7 +64,6 @@
<maven.compiler.target>1.8</maven.compiler.target>
<httpcore.version>5.2-beta1</httpcore.version>
<log4j.version>2.17.0</log4j.version>
- <commons-codec.version>1.15</commons-codec.version>
<brotli.version>0.1.2</brotli.version>
<conscrypt.version>2.5.2</conscrypt.version>
<ehcache.version>3.9.6</ehcache.version>
@@ -144,11 +143,6 @@
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <version>${commons-codec.version}</version>
- </dependency>
<dependency>
<groupId>org.brotli</groupId>
<artifactId>dec</artifactId>