diff --git a/api/all/src/main/java/io/opentelemetry/api/baggage/propagation/W3CBaggagePropagator.java b/api/all/src/main/java/io/opentelemetry/api/baggage/propagation/W3CBaggagePropagator.java index dfffb518e6b..425f9451dc8 100644 --- a/api/all/src/main/java/io/opentelemetry/api/baggage/propagation/W3CBaggagePropagator.java +++ b/api/all/src/main/java/io/opentelemetry/api/baggage/propagation/W3CBaggagePropagator.java @@ -13,10 +13,12 @@ import io.opentelemetry.api.internal.PercentEscaper; import io.opentelemetry.api.internal.StringUtils; import io.opentelemetry.context.Context; +import io.opentelemetry.context.internal.propagation.ExtendedTextMapGetter; import io.opentelemetry.context.propagation.TextMapGetter; import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.context.propagation.TextMapSetter; import java.util.Collection; +import java.util.Iterator; import java.util.List; import javax.annotation.Nullable; @@ -95,14 +97,43 @@ public Context extract(Context context, @Nullable C carrier, TextMapGetter baggageHeaders = getter.getList(carrier, FIELD); - if (baggageHeaders == null || baggageHeaders.isEmpty()) { + if (getter instanceof ExtendedTextMapGetter) { + return extractMulti(context, carrier, (ExtendedTextMapGetter) getter); + } + return extractSingle(context, carrier, getter); + } + + private static Context extractSingle( + Context context, @Nullable C carrier, TextMapGetter getter) { + String baggageHeader = getter.get(carrier, FIELD); + if (baggageHeader == null) { + return context; + } + if (baggageHeader.isEmpty()) { + return context; + } + + BaggageBuilder baggageBuilder = Baggage.builder(); + try { + extractEntries(baggageHeader, baggageBuilder); + } catch (RuntimeException e) { + return context; + } + return context.with(baggageBuilder.build()); + } + + private static Context extractMulti( + Context context, @Nullable C carrier, ExtendedTextMapGetter getter) { + Iterator baggageHeaders = getter.getAll(carrier, FIELD); + if (baggageHeaders == null) { return context; } boolean extracted = false; BaggageBuilder baggageBuilder = Baggage.builder(); - for (String header : baggageHeaders) { + + while (baggageHeaders.hasNext()) { + String header = baggageHeaders.next(); if (header.isEmpty()) { continue; } @@ -114,6 +145,7 @@ public Context extract(Context context, @Nullable C carrier, TextMapGetter carrier, String key) { } }; - private static final TextMapGetter>> multiGetter = - new TextMapGetter>>() { + private static final ExtendedTextMapGetter>> multiGetter = + new ExtendedTextMapGetter>>() { @Override public Iterable keys(Map> carrier) { return carrier.keySet(); @@ -54,8 +56,9 @@ public String get(Map> carrier, String key) { } @Override - public List getList(Map> carrier, String key) { - return carrier.getOrDefault(key, Collections.emptyList()); + public Iterator getAll(Map> carrier, String key) { + List values = carrier.get(key); + return values == null ? Collections.emptyIterator() : values.iterator(); } }; diff --git a/context/src/main/java/io/opentelemetry/context/internal/propagation/ExtendedTextMapGetter.java b/context/src/main/java/io/opentelemetry/context/internal/propagation/ExtendedTextMapGetter.java new file mode 100644 index 00000000000..ea84460e611 --- /dev/null +++ b/context/src/main/java/io/opentelemetry/context/internal/propagation/ExtendedTextMapGetter.java @@ -0,0 +1,40 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.context.internal.propagation; + +import io.opentelemetry.context.propagation.TextMapGetter; +import java.util.Collections; +import java.util.Iterator; +import javax.annotation.Nullable; + +/** + * Extends {@link TextMapGetter} to return possibly multiple values for a given key. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + * + * @param carrier of propagation fields, such as an http request. + */ +public interface ExtendedTextMapGetter extends TextMapGetter { + /** + * If implemented, returns all values for a given {@code key} in order, or returns an empty list. + * + *

The default method returns the first value of the given propagation {@code key} as a + * singleton list, or returns an empty list. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + * + * @param carrier carrier of propagation fields, such as an http request. + * @param key the key of the field. + * @return all values for a given {@code key} in order, or returns an empty list. Default method + * wraps {@code get()} as an {@link Iterator}. + */ + default Iterator getAll(@Nullable C carrier, String key) { + String first = get(carrier, key); + return Collections.singleton(first).iterator(); + } +} diff --git a/context/src/main/java/io/opentelemetry/context/propagation/TextMapGetter.java b/context/src/main/java/io/opentelemetry/context/propagation/TextMapGetter.java index de8012f00b9..f160b7857ab 100644 --- a/context/src/main/java/io/opentelemetry/context/propagation/TextMapGetter.java +++ b/context/src/main/java/io/opentelemetry/context/propagation/TextMapGetter.java @@ -5,8 +5,6 @@ package io.opentelemetry.context.propagation; -import java.util.Collections; -import java.util.List; import javax.annotation.Nullable; /** @@ -35,20 +33,4 @@ public interface TextMapGetter { */ @Nullable String get(@Nullable C carrier, String key); - - /** - * If implemented, returns all values for a given {@code key} in order, or returns an empty list. - * - *

The default method returns the first value of the given propagation {@code key} as a - * singleton list, or returns an empty list. - * - * @param carrier carrier of propagation fields, such as an http request. - * @param key the key of the field. - * @return the first value of the given propagation {@code key} as a singleton list, or returns an - * empty list. - */ - default List getList(@Nullable C carrier, String key) { - String first = get(carrier, key); - return first == null ? Collections.emptyList() : Collections.singletonList(first); - } }