From bf99144ad4e4fa38120e896d70e9e5bcfaf27054 Mon Sep 17 00:00:00 2001
From: Marc Bachmann <marc.brookman@gmail.com>
Date: Mon, 25 Jan 2021 18:03:31 +0100
Subject: [PATCH] chore(http-propagation): reduce complexity of traceparent
 parsing (#1837)

Co-authored-by: Valentin Marchaud <contact@vmarchaud.fr>
Co-authored-by: Daniel Dyla <dyladan@users.noreply.github.com>
---
 .../context/propagation/HttpTraceContext.ts   | 46 +++++++------------
 1 file changed, 16 insertions(+), 30 deletions(-)

diff --git a/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts b/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts
index 5957b2228d8..735e8d2e443 100644
--- a/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts
+++ b/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts
@@ -30,12 +30,13 @@ export const TRACE_PARENT_HEADER = 'traceparent';
 export const TRACE_STATE_HEADER = 'tracestate';
 
 const VERSION = '00';
-const VERSION_PART_COUNT = 4; // Version 00 only allows the specific 4 fields.
-
-const VERSION_REGEX = /^(?!ff)[\da-f]{2}$/;
-const TRACE_ID_REGEX = /^(?![0]{32})[\da-f]{32}$/;
-const PARENT_ID_REGEX = /^(?![0]{16})[\da-f]{16}$/;
-const FLAGS_REGEX = /^[\da-f]{2}$/;
+const VERSION_PART = '(?!ff)[\\da-f]{2}';
+const TRACE_ID_PART = '(?![0]{32})[\\da-f]{32}';
+const PARENT_ID_PART = '(?![0]{16})[\\da-f]{16}';
+const FLAGS_PART = '[\\da-f]{2}';
+const TRACE_PARENT_REGEX = new RegExp(
+  `^\\s?(${VERSION_PART})-(${TRACE_ID_PART})-(${PARENT_ID_PART})-(${FLAGS_PART})(-.*)?\\s?$`
+);
 
 /**
  * Parses information from the [traceparent] span tag and converts it into {@link SpanContext}
@@ -48,33 +49,18 @@ const FLAGS_REGEX = /^[\da-f]{2}$/;
  *     For more information see {@link https://www.w3.org/TR/trace-context/}
  */
 export function parseTraceParent(traceParent: string): SpanContext | null {
-  const trimmed = traceParent.trim();
-  const traceParentParts = trimmed.split('-');
-
-  // Current version must be structured correctly.
-  // For future versions, we can grab just the parts we do support.
-  if (
-    traceParentParts[0] === VERSION &&
-    traceParentParts.length !== VERSION_PART_COUNT
-  ) {
-    return null;
-  }
+  const match = TRACE_PARENT_REGEX.exec(traceParent);
+  if (!match) return null;
 
-  const [version, traceId, parentId, flags] = traceParentParts;
-  const isValidParent =
-    VERSION_REGEX.test(version) &&
-    TRACE_ID_REGEX.test(traceId) &&
-    PARENT_ID_REGEX.test(parentId) &&
-    FLAGS_REGEX.test(flags);
-
-  if (!isValidParent) {
-    return null;
-  }
+  // According to the specification the implementation should be compatible
+  // with future versions. If there are more parts, we only reject it if it's using version 00
+  // See https://www.w3.org/TR/trace-context/#versioning-of-traceparent
+  if (match[1] === '00' && match[5]) return null;
 
   return {
-    traceId: traceId,
-    spanId: parentId,
-    traceFlags: parseInt(flags, 16),
+    traceId: match[2],
+    spanId: match[3],
+    traceFlags: parseInt(match[4], 16),
   };
 }