package com.baiyue.common.web; import java.security.SecureRandom; import java.util.HexFormat; import java.util.Optional; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Strict W3C {@code traceparent} version 00 value. * *

This type deliberately accepts only the currently frozen version-00 shape. Unsupported, * ambiguous or malformed input must start a new trace instead of being partially trusted.

*/ public record TraceParent(String traceId, String parentId, String traceFlags) { public static final String HEADER = "traceparent"; public static final int HEADER_LENGTH = 55; private static final Pattern VERSION_00 = Pattern.compile( "00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})"); private static final Pattern LEGACY_TRACE_ID = Pattern.compile("[0-9A-Fa-f]{32}"); private static final String ZERO_TRACE_ID = "0".repeat(32); private static final String ZERO_PARENT_ID = "0".repeat(16); private static final SecureRandom RANDOM = new SecureRandom(); private static final HexFormat HEX = HexFormat.of(); public TraceParent { if (!validTraceId(traceId) || !validParentId(parentId) || traceFlags == null || !traceFlags.matches("[0-9a-f]{2}")) { throw new IllegalArgumentException("Invalid W3C traceparent components"); } } /** Parses one exact, lowercase W3C version-00 header value. */ public static Optional parse(String value) { if (value == null || value.length() != HEADER_LENGTH) { return Optional.empty(); } Matcher matcher = VERSION_00.matcher(value); if (!matcher.matches() || !validTraceId(matcher.group(1)) || !validParentId(matcher.group(2))) { return Optional.empty(); } return Optional.of(new TraceParent(matcher.group(1), matcher.group(2), matcher.group(3))); } /** Creates the local inbound context for a valid remote parent. */ public static TraceParent childOf(TraceParent remoteParent) { return new TraceParent(remoteParent.traceId(), randomNonZero(8), remoteParent.traceFlags()); } /** Creates a new root context, optionally reusing a valid legacy trace ID. */ public static TraceParent newRoot(String legacyTraceId) { String traceId = validLegacyTraceId(legacyTraceId) ? legacyTraceId.toLowerCase(java.util.Locale.ROOT) : randomNonZero(16); return new TraceParent(traceId, randomNonZero(8), "00"); } /** Creates a sampled outbound child for a trusted current trace ID. */ public static TraceParent outboundChild(String currentTraceId) { if (!validLegacyTraceId(currentTraceId)) { throw new IllegalArgumentException("Current trace ID is invalid"); } return new TraceParent(currentTraceId.toLowerCase(java.util.Locale.ROOT), randomNonZero(8), "01"); } /** * Normalizes a trace ID from a trusted persisted/internal context. * *

Unlike an untrusted HTTP header, a canonical UUID is accepted and compacted because * existing event envelopes historically persisted UUID trace IDs.

*/ public static Optional normalizeTrustedTraceId(String value) { if (validLegacyTraceId(value)) { return Optional.of(value.toLowerCase(Locale.ROOT)); } if (value != null && value.matches( "[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}")) { String compact = value.replace("-", "").toLowerCase(Locale.ROOT); return validLegacyTraceId(compact) ? Optional.of(compact) : Optional.empty(); } return Optional.empty(); } public static boolean validLegacyTraceId(String value) { return value != null && LEGACY_TRACE_ID.matcher(value).matches() && !ZERO_TRACE_ID.equalsIgnoreCase(value); } public String value() { return "00-" + traceId + '-' + parentId + '-' + traceFlags; } private static boolean validTraceId(String value) { return value != null && value.matches("[0-9a-f]{32}") && !ZERO_TRACE_ID.equals(value); } private static boolean validParentId(String value) { return value != null && value.matches("[0-9a-f]{16}") && !ZERO_PARENT_ID.equals(value); } private static String randomNonZero(int byteCount) { byte[] bytes = new byte[byteCount]; String value; do { RANDOM.nextBytes(bytes); value = HEX.formatHex(bytes); } while (value.chars().allMatch(character -> character == '0')); return value; } }