-
Notifications
You must be signed in to change notification settings - Fork 958
Update Env var getter / setter to reflect spec changes #8233
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
base: main
Are you sure you want to change the base?
Changes from all commits
9dd9717
222c4f3
d05e9db
ff9c5bd
f829e51
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 |
|---|---|---|
|
|
@@ -9,8 +9,8 @@ | |
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Locale; | ||
| import java.util.Map; | ||
| import java.util.concurrent.atomic.AtomicBoolean; | ||
| import java.util.logging.Level; | ||
| import java.util.logging.Logger; | ||
| import javax.annotation.Nullable; | ||
|
|
@@ -46,7 +46,8 @@ | |
| */ | ||
| public final class EnvironmentGetter implements TextMapGetter<Map<String, String>> { | ||
|
|
||
| private static final Logger logger = Logger.getLogger(EnvironmentGetter.class.getName()); | ||
| private static final AtomicBoolean LOG_KEYS_CALLED = new AtomicBoolean(false); | ||
| private static final Logger LOGGER = Logger.getLogger(EnvironmentGetter.class.getName()); | ||
| private static final EnvironmentGetter INSTANCE = new EnvironmentGetter(); | ||
|
|
||
| private EnvironmentGetter() {} | ||
|
|
@@ -58,14 +59,21 @@ public static EnvironmentGetter getInstance() { | |
|
|
||
| @Override | ||
| public Iterable<String> keys(Map<String, String> carrier) { | ||
| if (LOG_KEYS_CALLED.compareAndSet(false, true)) { | ||
| LOGGER.log( | ||
| Level.WARNING, | ||
| "keys() called on EnvironmentGetter. " | ||
| + "This may produce unexpected results with propagators which depend on case sensitivity or special characters in keys.", | ||
| new Throwable()); | ||
| } | ||
| if (carrier == null) { | ||
| return Collections.emptyList(); | ||
| } | ||
| List<String> result = new ArrayList<>(carrier.size()); | ||
| for (String key : carrier.keySet()) { | ||
| result.add(key.toLowerCase(Locale.ROOT)); | ||
| result.add(EnvironmentSetter.normalizeKey(key)); | ||
| } | ||
| return result; | ||
| return Collections.unmodifiableList(result); | ||
| } | ||
|
|
||
| @Nullable | ||
|
|
@@ -74,20 +82,15 @@ public String get(@Nullable Map<String, String> carrier, String key) { | |
| if (carrier == null || key == null) { | ||
| return null; | ||
| } | ||
| // Spec recommends using uppercase and underscores for environment variable | ||
| // names for maximum | ||
| // cross-platform compatibility. | ||
| String sanitizedKey = key.replace('.', '_').replace('-', '_').toUpperCase(Locale.ROOT); | ||
| String value = carrier.get(sanitizedKey); | ||
| if (value != null && !EnvironmentSetter.isValidHttpHeaderValue(value)) { | ||
| logger.log( | ||
| Level.FINE, | ||
| "Ignoring environment variable '{0}': " | ||
| + "value contains characters not valid in HTTP header fields per RFC 9110.", | ||
| sanitizedKey); | ||
| return null; | ||
| } | ||
| return value; | ||
| String normalizedKey = EnvironmentSetter.normalizeKey(key); | ||
| String[] result = new String[] {null}; | ||
| carrier.forEach( | ||
| (entryKey, entryValue) -> { | ||
| if (EnvironmentSetter.normalizeKey(entryKey).equals(normalizedKey)) { | ||
| result[0] = entryValue; | ||
| } | ||
| }); | ||
|
Member
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. Not great that evertime we read a key, we have to normalize potentially all the keys in the carrier. Go gets around this by computing the normalized keys once and using the carrier as a cache. In java, its not safe to assume that the map is mutable. I imagine this isn't a real problem though because env var propagation implies your going to start a new process and pass the context to it via env vars, which is much heavier weight than what we're doing here.
Member
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.
Agreed and at least it is a robust implementation 😁 |
||
| return result[0]; | ||
| } | ||
|
|
||
| @Override | ||
|
|
||
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.
I guess that thus can be done a little more efficient.
We could
breakwhen we find a matching key instead of iterating over all env vars.I guess iterating over
carrier.entrySet()and early return the value when normalized key matches.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.
Yup meant to do that
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.
Oh yeah can't exit early from for each. So it's either use a traditional loop which allocated but can exit early, or use forEach which doesn't allocate but which can't exit early
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.
Given that strings are being allocated for every key, trying to avoid allocating for map iteration is silly optimization. Will switch to tradition for loop and exit early