-
Notifications
You must be signed in to change notification settings - Fork 333
Add items and bytes limits to baggage extraction #11265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,5 @@ | ||
| package datadog.trace.core.baggage; | ||
|
|
||
| import static java.util.Collections.emptyMap; | ||
|
|
||
| import datadog.context.Context; | ||
| import datadog.context.propagation.CarrierSetter; | ||
| import datadog.context.propagation.CarrierVisitor; | ||
|
|
@@ -19,6 +17,7 @@ | |
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import java.util.function.BiConsumer; | ||
| import javax.annotation.Nullable; | ||
| import javax.annotation.ParametersAreNonnullByDefault; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
@@ -142,8 +141,7 @@ public <C> Context extract(Context context, C carrier, CarrierVisitor<C> visitor | |
| private class BaggageExtractor implements BiConsumer<String, String> { | ||
| private static final char KEY_VALUE_SEPARATOR = '='; | ||
| private static final char PAIR_SEPARATOR = ','; | ||
| private Baggage extracted; | ||
| private String w3cHeader; | ||
| @Nullable private Baggage extracted; | ||
|
|
||
| /** URL decode value */ | ||
| private String decode(final String value) { | ||
|
|
@@ -156,41 +154,42 @@ private String decode(final String value) { | |
| return decoded; | ||
| } | ||
|
|
||
| private Map<String, String> parseBaggageHeaders(String input) { | ||
| private Baggage parseBaggageHeaders(String input) { | ||
| Map<String, String> baggage = new HashMap<>(); | ||
| int start = 0; | ||
| boolean truncatedCache = false; | ||
| String w3cHeader = input; | ||
| int pairSeparatorInd = input.indexOf(PAIR_SEPARATOR); | ||
| pairSeparatorInd = pairSeparatorInd == -1 ? input.length() : pairSeparatorInd; | ||
| int kvSeparatorInd = input.indexOf(KEY_VALUE_SEPARATOR); | ||
| while (kvSeparatorInd != -1) { | ||
| int end = pairSeparatorInd; | ||
| boolean limitReached = baggage.size() >= maxItems || end > maxBytes; | ||
| if (limitReached) { | ||
|
Comment on lines
+166
to
+167
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When an incoming baggage header exceeds Useful? React with 👍 / 👎.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those metrics are used for context injection, not extraction… and the team in charge of this code part and metrics already ready the patch. |
||
| // if header was not invalidated already, and we go out of range: | ||
| // - fully invalidate if it's after the first k/v pair, | ||
| // - otherwise ignore from the current k/v separator | ||
| w3cHeader = (w3cHeader == null || start == 0) ? null : w3cHeader.substring(0, start - 1); | ||
| break; | ||
| } | ||
| if (kvSeparatorInd > end) { | ||
| LOG.debug( | ||
| "Dropping baggage headers due to key with no value {}", input.substring(start, end)); | ||
| BAGGAGE_METRICS.onBaggageMalformed(); | ||
| return emptyMap(); | ||
| return null; | ||
| } | ||
| String key = decode(input.substring(start, kvSeparatorInd).trim()); | ||
| String value = decode(input.substring(kvSeparatorInd + 1, end).trim()); | ||
| if (key.isEmpty() || value.isEmpty()) { | ||
| LOG.debug("Dropping baggage headers due to empty k/v {}:{}", key, value); | ||
| BAGGAGE_METRICS.onBaggageMalformed(); | ||
| return emptyMap(); | ||
| return null; | ||
| } | ||
| baggage.put(key, value); | ||
|
|
||
| // need to percent-encode non-ascii headers we pass down | ||
| if (UTF_ESCAPER.keyNeedsEncoding(key) || UTF_ESCAPER.valNeedsEncoding(value)) { | ||
| truncatedCache = true; | ||
| this.w3cHeader = null; | ||
| } else if (!truncatedCache && (end > maxBytes || baggage.size() > maxItems)) { | ||
| if (start == 0) { // if we go out of range after first k/v pair, there is no cache | ||
| this.w3cHeader = null; | ||
| } else { | ||
| this.w3cHeader = input.substring(0, start - 1); // -1 to ignore the k/v separator | ||
| } | ||
| truncatedCache = true; | ||
| if (w3cHeader != null | ||
| && (UTF_ESCAPER.keyNeedsEncoding(key) || UTF_ESCAPER.valNeedsEncoding(value))) { | ||
| w3cHeader = null; | ||
| } | ||
|
|
||
| kvSeparatorInd = input.indexOf(KEY_VALUE_SEPARATOR, pairSeparatorInd + 1); | ||
|
|
@@ -199,20 +198,16 @@ private Map<String, String> parseBaggageHeaders(String input) { | |
| start = end + 1; | ||
| } | ||
|
|
||
| if (!truncatedCache) { | ||
| this.w3cHeader = input; | ||
| } | ||
|
|
||
| return baggage; | ||
| return baggage.isEmpty() ? null : Baggage.create(baggage, w3cHeader); | ||
| } | ||
|
|
||
| @Override | ||
| public void accept(String key, String value) { | ||
| // Only process tags that are relevant to baggage | ||
| if (BAGGAGE_KEY.equalsIgnoreCase(key)) { | ||
| Map<String, String> baggage = parseBaggageHeaders(value); | ||
| if (!baggage.isEmpty()) { | ||
| this.extracted = Baggage.create(baggage, this.w3cHeader); | ||
| Baggage parsed = parseBaggageHeaders(value); | ||
| if (parsed != null) { | ||
| this.extracted = parsed; | ||
| } | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw I think that this is an approximation since
endworks with nb of chars and not bytesThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes: byte limit is enforced against String char (UTF-16 code unit) length: exact for ASCII baggage, conservative on memory for multi-byte UTF-8 input.
Using the exact byte limit would have allocated memory which we try to prevent with this fix.