Skip to content

Commit 3bd75f6

Browse files
committed
Revert back to the custom decode method for Otel decoding
spring-projects/spring-framework#34570 See gh-44677
1 parent 03974f2 commit 3bd75f6

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/opentelemetry/OpenTelemetryResourceAttributes.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.opentelemetry;
1818

19+
import java.io.ByteArrayOutputStream;
1920
import java.nio.charset.StandardCharsets;
2021
import java.util.Collections;
2122
import java.util.LinkedHashMap;
@@ -138,7 +139,7 @@ private Map<String, String> getResourceAttributesFromEnv() {
138139
if (index > 0) {
139140
String key = attribute.substring(0, index);
140141
String value = attribute.substring(index + 1);
141-
attributes.put(key.trim(), StringUtils.uriDecode(value.trim(), StandardCharsets.UTF_8));
142+
attributes.put(key.trim(), decode(value.trim()));
142143
}
143144
}
144145
String otelServiceName = getEnv("OTEL_SERVICE_NAME");
@@ -152,4 +153,43 @@ private String getEnv(String name) {
152153
return this.getEnv.apply(name);
153154
}
154155

156+
/**
157+
* Decodes a percent-encoded string. Converts sequences like '%HH' (where HH
158+
* represents hexadecimal digits) back into their literal representations.
159+
* <p>
160+
* Inspired by {@code org.apache.commons.codec.net.PercentCodec}.
161+
* @param value value to decode
162+
* @return the decoded string
163+
*/
164+
private static String decode(String value) {
165+
if (value.indexOf('%') < 0) {
166+
return value;
167+
}
168+
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
169+
ByteArrayOutputStream bos = new ByteArrayOutputStream(bytes.length);
170+
for (int i = 0; i < bytes.length; i++) {
171+
byte b = bytes[i];
172+
if (b != '%') {
173+
bos.write(b);
174+
continue;
175+
}
176+
int u = decodeHex(bytes, i + 1);
177+
int l = decodeHex(bytes, i + 2);
178+
if (u >= 0 && l >= 0) {
179+
bos.write((u << 4) + l);
180+
}
181+
else {
182+
throw new IllegalArgumentException(
183+
"Failed to decode percent-encoded characters at index %d in the value: '%s'".formatted(i,
184+
value));
185+
}
186+
i += 2;
187+
}
188+
return bos.toString(StandardCharsets.UTF_8);
189+
}
190+
191+
private static int decodeHex(byte[] bytes, int index) {
192+
return (index < bytes.length) ? Character.digit(bytes[index], 16) : -1;
193+
}
194+
155195
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/opentelemetry/OpenTelemetryResourceAttributesTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ void otelResourceAttributeValuesShouldBePercentDecoded() {
121121
void illegalArgumentExceptionShouldBeThrownWhenDecodingIllegalHexCharPercentEncodedValue() {
122122
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "key=abc%ß");
123123
assertThatIllegalArgumentException().isThrownBy(this::getAttributes)
124-
.withMessage("Invalid encoded sequence \"\"");
124+
.withMessage("Failed to decode percent-encoded characters at index 3 in the value: 'abc%ß'");
125125
}
126126

127127
@Test
@@ -134,7 +134,7 @@ void replacementCharShouldBeUsedWhenDecodingNonUtf8Character() {
134134
void illegalArgumentExceptionShouldBeThrownWhenDecodingInvalidPercentEncodedValue() {
135135
this.environmentVariables.put("OTEL_RESOURCE_ATTRIBUTES", "key=%");
136136
assertThatIllegalArgumentException().isThrownBy(this::getAttributes)
137-
.withMessage("Invalid encoded sequence \"%\"");
137+
.withMessage("Failed to decode percent-encoded characters at index 0 in the value: '%'");
138138
}
139139

140140
@Test

0 commit comments

Comments
 (0)