Skip to content

Commit 914c761

Browse files
avoid guava causing problems
1 parent 6fb3f29 commit 914c761

File tree

2 files changed

+153
-19
lines changed

2 files changed

+153
-19
lines changed

dd-trace-api/dd-trace-api.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ excludedClassesCoverage += [
99
'datadog.trace.api.DDTraceApiInfo',
1010
'datadog.trace.api.GlobalTracer*',
1111
'datadog.trace.api.CorrelationIdentifier',
12-
'datadog.trace.api.DDTags'
12+
'datadog.trace.api.DDTags',
13+
'datadog.trace.api.DDId.Base64Decoder'
1314
]
1415

1516
description = 'dd-trace-api'
1617
dependencies {
1718
compile deps.slf4j
18-
// TODO kill this off in JDK8
19-
compile deps.guava
2019

20+
testCompile deps.guava
2121
testCompile project(':utils:test-utils')
2222
}

dd-trace-api/src/main/java/datadog/trace/api/DDId.java

Lines changed: 150 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package datadog.trace.api;
22

3-
import com.google.common.io.BaseEncoding;
43
import java.nio.charset.StandardCharsets;
4+
import java.util.Arrays;
55
import java.util.concurrent.ThreadLocalRandom;
66
import lombok.extern.slf4j.Slf4j;
77

@@ -18,7 +18,7 @@ public class DDId {
1818
public static final DDId ZERO = new DDId(0, "0");
1919
public static final DDId MAX = new DDId(-1, "18446744073709551615"); // All bits set
2020

21-
private static final BaseEncoding BASE64 = BaseEncoding.base64();
21+
private static final Base64Decoder BASE64 = new Base64Decoder();
2222

2323
// Convenience constant used from tests
2424
private static final DDId ONE = DDId.from(1);
@@ -66,13 +66,17 @@ public static DDId from(String s) throws NumberFormatException {
6666
// we have reports of Kakfa mirror maker base64 encoding record headers
6767
// attempting to base64 decode the ids here rather than in the Kafka instrumentation
6868
// helps users understand they have a problem without making other users pay for it
69-
if (null != s && BASE64.canDecode(s)) {
70-
String decoded = new String(BASE64.decode(s), StandardCharsets.ISO_8859_1);
71-
log.debug(
72-
"id {} was base 64 encoded to {}, it was decoded but this indicates there is a problem elsewhere in your system",
73-
decoded,
74-
s);
75-
return DDId.create(parseUnsignedLong(decoded), decoded);
69+
if (null != s) {
70+
try {
71+
String decoded = new String(BASE64.decode(s), StandardCharsets.ISO_8859_1);
72+
log.debug(
73+
"id {} was base 64 encoded to {}, it was decoded but this indicates there is a problem elsewhere in your system",
74+
decoded,
75+
s);
76+
return DDId.create(parseUnsignedLong(decoded), decoded);
77+
} catch (Exception ignored) {
78+
79+
}
7680
}
7781
throw e;
7882
}
@@ -94,13 +98,16 @@ public static DDId fromHex(String s) throws NumberFormatException {
9498
// we have reports of Kakfa mirror maker base64 encoding record headers
9599
// attempting to base64 decode the ids here rather than in the Kafka instrumentation
96100
// helps users understand they have a problem without making other users pay for it
97-
if (null != s && BASE64.canDecode(s)) {
98-
String decoded = new String(BASE64.decode(s), StandardCharsets.ISO_8859_1);
99-
log.debug(
100-
"id {} was base 64 encoded to {}, it was decoded but this indicates there is a problem elsewhere in your system",
101-
decoded,
102-
s);
103-
return DDId.create(parseUnsignedLongHex(decoded), null);
101+
if (null != s) {
102+
try {
103+
String decoded = new String(BASE64.decode(s), StandardCharsets.ISO_8859_1);
104+
log.debug(
105+
"id {} was base 64 encoded to {}, it was decoded but this indicates there is a problem elsewhere in your system",
106+
decoded,
107+
s);
108+
return DDId.create(parseUnsignedLongHex(decoded), null);
109+
} catch (Exception ignored) {
110+
}
104111
}
105112
throw e;
106113
}
@@ -209,6 +216,133 @@ private static long parseUnsignedLongHex(String s) throws NumberFormatException
209216
}
210217
}
211218

219+
// TODO - can be removed when JDK7 is dropped (adapted from JDK8 source)
220+
private static class Base64Decoder {
221+
222+
private static final int[] BASE_64 = new int[256];
223+
224+
static {
225+
Arrays.fill(BASE_64, -1);
226+
int i = 0;
227+
for (char c = 'A'; c <= 'Z'; ++c) {
228+
BASE_64[c] = i++;
229+
}
230+
for (char c = 'a'; c <= 'z'; ++c) {
231+
BASE_64[c] = i++;
232+
}
233+
for (char c = '0'; c <= '9'; ++c) {
234+
BASE_64[c] = i++;
235+
}
236+
BASE_64['+'] = i++;
237+
BASE_64['/'] = i;
238+
BASE_64['='] = -2;
239+
}
240+
241+
public byte[] decode(byte[] src) {
242+
byte[] dst = new byte[outLength(src, 0, src.length)];
243+
int ret = decode0(src, 0, src.length, dst);
244+
if (ret != dst.length) {
245+
dst = Arrays.copyOf(dst, ret);
246+
}
247+
return dst;
248+
}
249+
250+
public byte[] decode(String src) {
251+
return decode(src.getBytes(StandardCharsets.ISO_8859_1));
252+
}
253+
254+
private int outLength(byte[] src, int sp, int sl) {
255+
int paddings = 0;
256+
int len = sl - sp;
257+
if (len == 0) return 0;
258+
if (len < 2) {
259+
if (BASE_64[0] == -1) return 0;
260+
throw new IllegalArgumentException(
261+
"Input byte[] should at least have 2 bytes for base64 bytes");
262+
}
263+
// scan all bytes to fill out all non-alphabet. a performance
264+
// trade-off of pre-scan or Arrays.copyOf
265+
int n = 0;
266+
while (sp < sl) {
267+
int b = src[sp++] & 0xff;
268+
if (b == '=') {
269+
len -= (sl - sp + 1);
270+
break;
271+
}
272+
if ((b = BASE_64[b]) == -1) n++;
273+
}
274+
len -= n;
275+
if ((len & 0x3) != 0) paddings = 4 - (len & 0x3);
276+
return 3 * ((len + 3) / 4) - paddings;
277+
}
278+
279+
private int decode0(byte[] src, int sp, int sl, byte[] dst) {
280+
int dp = 0;
281+
int bits = 0;
282+
int shiftto = 18; // pos of first byte of 4-byte atom
283+
284+
while (sp < sl) {
285+
if (shiftto == 18 && sp + 4 < sl) { // fast path
286+
int sl0 = sp + ((sl - sp) & ~0b11);
287+
while (sp < sl0) {
288+
int b1 = BASE_64[src[sp++] & 0xff];
289+
int b2 = BASE_64[src[sp++] & 0xff];
290+
int b3 = BASE_64[src[sp++] & 0xff];
291+
int b4 = BASE_64[src[sp++] & 0xff];
292+
if ((b1 | b2 | b3 | b4) < 0) { // non base64 byte
293+
sp -= 4;
294+
break;
295+
}
296+
int bits0 = b1 << 18 | b2 << 12 | b3 << 6 | b4;
297+
dst[dp++] = (byte) (bits0 >> 16);
298+
dst[dp++] = (byte) (bits0 >> 8);
299+
dst[dp++] = (byte) (bits0);
300+
}
301+
if (sp >= sl) break;
302+
}
303+
int b = src[sp++] & 0xff;
304+
if ((b = BASE_64[b]) < 0) {
305+
if (b == -2) { // padding byte '='
306+
// = shiftto==18 unnecessary padding
307+
// x= shiftto==12 a dangling single x
308+
// x to be handled together with non-padding case
309+
// xx= shiftto==6&&sp==sl missing last =
310+
// xx=y shiftto==6 last is not =
311+
if (shiftto == 6 && (sp == sl || src[sp++] != '=') || shiftto == 18) {
312+
throw new IllegalArgumentException("Input byte array has wrong 4-byte ending unit");
313+
}
314+
break;
315+
}
316+
}
317+
bits |= (b << shiftto);
318+
shiftto -= 6;
319+
if (shiftto < 0) {
320+
dst[dp++] = (byte) (bits >> 16);
321+
dst[dp++] = (byte) (bits >> 8);
322+
dst[dp++] = (byte) (bits);
323+
shiftto = 18;
324+
bits = 0;
325+
}
326+
}
327+
// reached end of byte array or hit padding '=' characters.
328+
if (shiftto == 6) {
329+
dst[dp++] = (byte) (bits >> 16);
330+
} else if (shiftto == 0) {
331+
dst[dp++] = (byte) (bits >> 16);
332+
dst[dp++] = (byte) (bits >> 8);
333+
} else if (shiftto == 12) {
334+
// dangling single "x", incorrectly encoded.
335+
throw new IllegalArgumentException("Last unit does not have enough valid bits");
336+
}
337+
// ignore all non-base64 character
338+
while (sp < sl) {
339+
if (BASE_64[src[sp++] & 0xff] < 0) continue;
340+
throw new IllegalArgumentException("Input byte array has incorrect ending byte at " + sp);
341+
}
342+
return dp;
343+
}
344+
}
345+
212346
// TODO Can be removed when Java7 support is removed
213347
private static String toUnsignedString(long l) {
214348
if (l >= 0) return Long.toString(l);

0 commit comments

Comments
 (0)