Copyright The OpenTelemetry Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

package trace

import (
	
	
	
	

	
)

const (
	supportedVersion  = 0
	maxVersion        = 254
	traceparentHeader = "traceparent"
	tracestateHeader  = "tracestate"
)

type traceContextPropagatorKeyType uint

const (
	tracestateKey traceContextPropagatorKeyType = 0
)
TraceContext propagates SpanContext in W3C TraceContext format.nolint:golint
type TraceContext struct{}

var _ propagation.HTTPPropagator = TraceContext{}
var traceCtxRegExp = regexp.MustCompile("^(?P<version>[0-9a-f]{2})-(?P<traceID>[a-f0-9]{32})-(?P<spanID>[a-f0-9]{16})-(?P<traceFlags>[a-f0-9]{2})(?:-.*)?$")
DefaultHTTPPropagator returns the default trace HTTP propagator.
func () propagation.HTTPPropagator {
	return TraceContext{}
}

func (TraceContext) ( context.Context,  propagation.HTTPSupplier) {
	 := .Value(tracestateKey)
	if ,  := .(string);  != nil &&  {
		.Set(tracestateHeader, )
	}

	 := SpanFromContext().SpanContext()
	if !.IsValid() {
		return
	}
	 := fmt.Sprintf("%.2x-%s-%s-%.2x",
		supportedVersion,
		.TraceID,
		.SpanID,
		.TraceFlags&FlagsSampled)
	.Set(traceparentHeader, )
}

func ( TraceContext) ( context.Context,  propagation.HTTPSupplier) context.Context {
	 := .Get(tracestateHeader)
	if  != "" {
		 = context.WithValue(, tracestateKey, )
	}

	 := .extract()
	if !.IsValid() {
		return 
	}
	return ContextWithRemoteSpanContext(, )
}

func (TraceContext) ( propagation.HTTPSupplier) SpanContext {
	 := .Get(traceparentHeader)
	if  == "" {
		return EmptySpanContext()
	}

	 := traceCtxRegExp.FindStringSubmatch()

	if len() == 0 {
		return EmptySpanContext()
	}

	if len() < 5 { // four subgroups plus the overall match
		return EmptySpanContext()
	}

	if len([1]) != 2 {
		return EmptySpanContext()
	}
	,  := hex.DecodeString([1])
	if  != nil {
		return EmptySpanContext()
	}
	 := int([0])
	if  > maxVersion {
		return EmptySpanContext()
	}

	if  == 0 && len() != 5 { // four subgroups plus the overall match
		return EmptySpanContext()
	}

	if len([2]) != 32 {
		return EmptySpanContext()
	}

	var  SpanContext

	.TraceID,  = IDFromHex([2][:32])
	if  != nil {
		return EmptySpanContext()
	}

	if len([3]) != 16 {
		return EmptySpanContext()
	}
	.SpanID,  = SpanIDFromHex([3])
	if  != nil {
		return EmptySpanContext()
	}

	if len([4]) != 2 {
		return EmptySpanContext()
	}
	,  := hex.DecodeString([4])
	if  != nil || len() < 1 || ( == 0 && [0] > 2) {
		return EmptySpanContext()
Clear all flags other than the trace-context supported sampling bit.
	.TraceFlags = [0] & FlagsSampled

	if !.IsValid() {
		return EmptySpanContext()
	}

	return 
}

func (TraceContext) () []string {
	return []string{traceparentHeader, tracestateHeader}