Skip to content

Commit 0c0a32f

Browse files
authored
Merge pull request #11 from nats-io/encoding-update
Update Encoding API
2 parents 6c949fe + 50cabc2 commit 0c0a32f

15 files changed

+266
-126
lines changed

src/main/java/io/nats/json/Encoding.java

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,32 @@
2121
public abstract class Encoding {
2222
private Encoding() {} /* ensures cannot be constructed */
2323

24+
/**
25+
* base64 encode a byte array to a byte array
26+
* @param input the input byte array to encode
27+
* @return the encoded byte array
28+
*/
29+
public static byte[] base64BasicEncode(byte[] input) {
30+
return Base64.getEncoder().encode(input);
31+
}
32+
33+
/**
34+
* base64 encode a byte array to a byte array
35+
* @param input the input byte array to encode
36+
* @return the encoded byte array
37+
*/
38+
public static String base64BasicEncodeToString(byte[] input) {
39+
return Base64.getEncoder().encodeToString(input);
40+
}
41+
2442
/**
2543
* base64 url encode a byte array to a byte array
2644
* @param input the input byte array to encode
2745
* @return the encoded byte array
28-
* @deprecated prefer base64UrlEncode
2946
*/
30-
@Deprecated
31-
public static byte[] base64Encode(byte[] input) {
32-
return Base64.getUrlEncoder().withoutPadding().encode(input);
47+
public static String base64BasicEncodeToString(String input) {
48+
return Base64.getEncoder()
49+
.encodeToString(input.getBytes(StandardCharsets.UTF_8));
3350
}
3451

3552
/**
@@ -42,21 +59,50 @@ public static byte[] base64UrlEncode(byte[] input) {
4259
}
4360

4461
/**
45-
* base64 url encode a byte array to a string
62+
* base64 url encode a byte array to a byte array
4663
* @param input the input byte array to encode
47-
* @return the encoded string
64+
* @return the encoded byte array
4865
*/
49-
public static String toBase64Url(byte[] input) {
50-
return new String(base64UrlEncode(input));
66+
public static String base64UrlEncodeToString(byte[] input) {
67+
return Base64.getUrlEncoder().withoutPadding().encodeToString(input);
5168
}
5269

5370
/**
54-
* base64 url encode a string to a string
55-
* @param input the input string to encode
56-
* @return the encoded string
71+
* base64 url encode a byte array to a byte array
72+
* @param input the input byte array to encode
73+
* @return the encoded byte array
5774
*/
58-
public static String toBase64Url(String input) {
59-
return new String(base64UrlEncode(input.getBytes(StandardCharsets.US_ASCII)));
75+
public static String base64UrlEncodeToString(String input) {
76+
return Base64.getUrlEncoder()
77+
.withoutPadding()
78+
.encodeToString(input.getBytes(StandardCharsets.UTF_8));
79+
}
80+
81+
/**
82+
* base64 decode a byte array
83+
* @param input the input byte array to decode
84+
* @return the decoded byte array
85+
*/
86+
public static byte[] base64BasicDecode(byte[] input) {
87+
return Base64.getDecoder().decode(input);
88+
}
89+
90+
/**
91+
* base64 decode a base64 encoded string
92+
* @param input the input string to decode
93+
* @return the decoded byte array
94+
*/
95+
public static byte[] base64BasicDecode(String input) {
96+
return Base64.getDecoder().decode(input);
97+
}
98+
99+
/**
100+
* base64 decode a base64 encoded string
101+
* @param input the input string to decode
102+
* @return the decoded string
103+
*/
104+
public static String base64BasicDecodeToString(String input) {
105+
return new String(Base64.getDecoder().decode(input));
60106
}
61107

62108
/**
@@ -69,12 +115,21 @@ public static byte[] base64UrlDecode(byte[] input) {
69115
}
70116

71117
/**
72-
* get a string from a base64 url encoded byte array
118+
* base64 url decode a base64 url encoded string
119+
* @param input the input string to decode
120+
* @return the decoded byte array
121+
*/
122+
public static byte[] base64UrlDecode(String input) {
123+
return Base64.getUrlDecoder().decode(input);
124+
}
125+
126+
/**
127+
* base64 url decode a base64 url encoded string
73128
* @param input the input string to decode
74129
* @return the decoded string
75130
*/
76-
public static String fromBase64Url(String input) {
77-
return new String(base64UrlDecode(input.getBytes(StandardCharsets.US_ASCII)));
131+
public static String base64UrlDecodeToString(String input) {
132+
return new String(Base64.getUrlDecoder().decode(input));
78133
}
79134

80135
public static String jsonDecode(String s) {
@@ -86,7 +141,6 @@ public static String jsonDecode(String s) {
86141
char nextChar = (x == len - 1) ? '\\' : s.charAt(x + 1);
87142
switch (nextChar) {
88143
case '\\':
89-
ch = '\\';
90144
break;
91145
case 'b':
92146
ch = '\b';
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
// Copyright 2015-2024 The NATS Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at:
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package io.nats.json;
15+
16+
import static io.nats.json.Encoding.base64BasicDecode;
17+
import static io.nats.json.Encoding.base64BasicDecodeToString;
18+
import static io.nats.json.Encoding.base64BasicEncode;
19+
import static io.nats.json.Encoding.base64BasicEncodeToString;
20+
import static io.nats.json.Encoding.base64UrlDecode;
21+
import static io.nats.json.Encoding.base64UrlEncode;
22+
import static io.nats.json.Encoding.base64UrlEncodeToString;
23+
import static io.nats.json.Encoding.jsonDecode;
24+
import static io.nats.json.Encoding.jsonEncode;
25+
import static io.nats.json.Encoding.uriDecode;
26+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
27+
import static org.junit.jupiter.api.Assertions.assertEquals;
28+
29+
import java.nio.charset.StandardCharsets;
30+
import java.util.List;
31+
32+
import org.junit.jupiter.api.Test;
33+
34+
import io.ResourceUtils;
35+
36+
public final class EncodingTests {
37+
@Test
38+
public void testJsonEncodeDecode() {
39+
_testJsonEncodeDecode("b4\\\\after", "b4\\after", null); // a single slash with a meaningless letter after it
40+
_testJsonEncodeDecode("b4\\\\tafter", "b4\\tafter", null); // a single slash with a char that can be part of an escape
41+
42+
_testJsonEncodeDecode("b4\\bafter", "b4\bafter", null);
43+
_testJsonEncodeDecode("b4\\fafter", "b4\fafter", null);
44+
_testJsonEncodeDecode("b4\\nafter", "b4\nafter", null);
45+
_testJsonEncodeDecode("b4\\rafter", "b4\rafter", null);
46+
_testJsonEncodeDecode("b4\\tafter", "b4\tafter", null);
47+
48+
_testJsonEncodeDecode("b4\\u0000after", "b4" + (char) 0 + "after", null);
49+
_testJsonEncodeDecode("b4\\u001fafter", "b4" + (char) 0x1f + "after", "b4\\u001fafter");
50+
_testJsonEncodeDecode("b4\\u0020after", "b4 after", "b4 after");
51+
_testJsonEncodeDecode("b4\\u0022after", "b4\"after", "b4\\\"after");
52+
_testJsonEncodeDecode("b4\\u0027after", "b4'after", "b4'after");
53+
_testJsonEncodeDecode("b4\\u003dafter", "b4=after", "b4=after");
54+
_testJsonEncodeDecode("b4\\u003Dafter", "b4=after", "b4=after");
55+
_testJsonEncodeDecode("b4\\u003cafter", "b4<after", "b4<after");
56+
_testJsonEncodeDecode("b4\\u003Cafter", "b4<after", "b4<after");
57+
_testJsonEncodeDecode("b4\\u003eafter", "b4>after", "b4>after");
58+
_testJsonEncodeDecode("b4\\u003Eafter", "b4>after", "b4>after");
59+
_testJsonEncodeDecode("b4\\u0060after", "b4`after", "b4`after");
60+
_testJsonEncodeDecode("b4\\xafter", "b4xafter", "b4xafter"); // unknown escape
61+
_testJsonEncodeDecode("b4\\", "b4\\", "b4\\\\"); // last char is \
62+
_testJsonEncodeDecode("b4\\/after", "b4/after", null);
63+
64+
List<String> utfs = ResourceUtils.resourceAsLines("utf8-only-no-ws-test-strings.txt");
65+
for (String u : utfs) {
66+
String uu = "b4\\b\\f\\n\\r\\t" + u + "after";
67+
_testJsonEncodeDecode(uu, "b4\b\f\n\r\t" + u + "after", uu);
68+
}
69+
}
70+
71+
private void _testJsonEncodeDecode(String encodedInput, String targetDecode, String targetEncode) {
72+
String decoded = jsonDecode(encodedInput);
73+
assertEquals(targetDecode, decoded);
74+
String encoded = jsonEncode(new StringBuilder(), decoded).toString();
75+
if (targetEncode == null) {
76+
assertEquals(encodedInput, encoded);
77+
}
78+
else {
79+
assertEquals(targetEncode, encoded);
80+
}
81+
}
82+
83+
@Test
84+
public void testBase64BasicEncoding() {
85+
String text = "blahblah";
86+
byte[] btxt = text.getBytes();
87+
88+
byte[] encBytesFromBytes = base64BasicEncode(btxt);
89+
String encFromBytes = base64BasicEncodeToString(btxt);
90+
String encFromString = base64BasicEncodeToString(text);
91+
assertEquals("YmxhaGJsYWg=", new String(encBytesFromBytes));
92+
assertEquals("YmxhaGJsYWg=", encFromBytes);
93+
assertEquals("YmxhaGJsYWg=", encFromString);
94+
95+
assertArrayEquals(btxt, base64BasicDecode(encBytesFromBytes));
96+
assertArrayEquals(btxt, base64BasicDecode(encFromBytes));
97+
assertEquals(text, base64BasicDecodeToString(encFromBytes));
98+
99+
String data = ResourceUtils.resourceAsString("test_bytes_000100.txt");
100+
String check = ResourceUtils.resourceAsString("basic_encoded_000100.txt");
101+
byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
102+
String enc = base64BasicEncodeToString(data.getBytes());
103+
assertEquals(check, enc);
104+
assertArrayEquals(bytes, base64BasicDecode(enc));
105+
106+
data = ResourceUtils.resourceAsString("test_bytes_001000.txt");
107+
check = ResourceUtils.resourceAsString("basic_encoded_001000.txt");
108+
bytes = data.getBytes(StandardCharsets.UTF_8);
109+
enc = base64BasicEncodeToString(data.getBytes());
110+
assertEquals(check, enc);
111+
assertArrayEquals(bytes, base64BasicDecode(enc));
112+
113+
data = ResourceUtils.resourceAsString("test_bytes_010000.txt");
114+
check = ResourceUtils.resourceAsString("basic_encoded_010000.txt");
115+
bytes = data.getBytes(StandardCharsets.UTF_8);
116+
enc = base64BasicEncodeToString(data.getBytes());
117+
assertEquals(check, enc);
118+
assertArrayEquals(bytes, base64BasicDecode(enc));
119+
120+
data = ResourceUtils.resourceAsString("test_bytes_100000.txt");
121+
check = ResourceUtils.resourceAsString("basic_encoded_100000.txt");
122+
bytes = data.getBytes(StandardCharsets.UTF_8);
123+
enc = base64BasicEncodeToString(data.getBytes());
124+
assertEquals(check, enc);
125+
assertArrayEquals(bytes, base64BasicDecode(enc));
126+
}
127+
128+
@Test
129+
public void testBase64UrlEncoding() {
130+
String text = "blahblah";
131+
byte[] btxt = text.getBytes();
132+
String surl = "https://nats.io/";
133+
byte[] burl = surl.getBytes();
134+
135+
byte[] uencBytes = base64UrlEncode(btxt);
136+
assertEquals("YmxhaGJsYWg", base64UrlEncodeToString(text));
137+
assertEquals("YmxhaGJsYWg", new String(uencBytes));
138+
assertArrayEquals(btxt, base64UrlDecode(uencBytes));
139+
140+
uencBytes = base64UrlEncode(burl);
141+
assertEquals("aHR0cHM6Ly9uYXRzLmlvLw", base64UrlEncodeToString(surl));
142+
assertEquals("aHR0cHM6Ly9uYXRzLmlvLw", new String(uencBytes));
143+
assertArrayEquals(burl, base64UrlDecode(uencBytes));
144+
145+
assertEquals("+ hello world", uriDecode("+%20hello%20world"));
146+
147+
String str = ResourceUtils.resourceAsString("test_bytes_000100.txt");
148+
String check = ResourceUtils.resourceAsString("url_encoded_000100.txt");
149+
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
150+
String senc = base64UrlEncodeToString(str);
151+
assertEquals(check, senc);
152+
String benc = base64UrlEncodeToString(bytes);
153+
assertEquals(check, benc);
154+
assertArrayEquals(bytes, base64UrlDecode(benc));
155+
156+
str = ResourceUtils.resourceAsString("test_bytes_001000.txt");
157+
check = ResourceUtils.resourceAsString("url_encoded_001000.txt");
158+
bytes = str.getBytes(StandardCharsets.UTF_8);
159+
senc = base64UrlEncodeToString(str);
160+
assertEquals(check, senc);
161+
benc = base64UrlEncodeToString(bytes);
162+
assertEquals(check, benc);
163+
assertArrayEquals(bytes, base64UrlDecode(benc));
164+
165+
str = ResourceUtils.resourceAsString("test_bytes_010000.txt");
166+
check = ResourceUtils.resourceAsString("url_encoded_010000.txt");
167+
bytes = str.getBytes(StandardCharsets.UTF_8);
168+
senc = base64UrlEncodeToString(str);
169+
assertEquals(check, senc);
170+
benc = base64UrlEncodeToString(bytes);
171+
assertEquals(check, benc);
172+
assertArrayEquals(bytes, base64UrlDecode(benc));
173+
174+
str = ResourceUtils.resourceAsString("test_bytes_100000.txt");
175+
check = ResourceUtils.resourceAsString("url_encoded_100000.txt");
176+
bytes = str.getBytes(StandardCharsets.UTF_8);
177+
senc = base64UrlEncodeToString(str);
178+
assertEquals(check, senc);
179+
benc = base64UrlEncodeToString(bytes);
180+
assertEquals(check, benc);
181+
assertArrayEquals(bytes, base64UrlDecode(benc));
182+
}
183+
}

0 commit comments

Comments
 (0)