// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package baggage // import "go.opentelemetry.io/otel/baggage"

import (
	
	
	
	
	

	
)

const (
	maxMembers               = 180
	maxBytesPerMembers       = 4096
	maxBytesPerBaggageString = 8192

	listDelimiter     = ","
	keyValueDelimiter = "="
	propertyDelimiter = ";"
)

var (
	errInvalidKey      = errors.New("invalid key")
	errInvalidValue    = errors.New("invalid value")
	errInvalidProperty = errors.New("invalid baggage list-member property")
	errInvalidMember   = errors.New("invalid baggage list-member")
	errMemberNumber    = errors.New("too many list-members in baggage-string")
	errMemberBytes     = errors.New("list-member too large")
	errBaggageBytes    = errors.New("baggage-string too large")
)

// Property is an additional metadata entry for a baggage list-member.
type Property struct {
	key, value string

	// hasValue indicates if a zero-value value means the property does not
	// have a value or if it was the zero-value.
	hasValue bool
}

// NewKeyProperty returns a new Property for key.
//
// The passed key must be valid, non-empty UTF-8 string.
// If key is invalid, an error will be returned.
// However, the specific Propagators that are used to transmit baggage entries across
// component boundaries may impose their own restrictions on Property key.
// For example, the W3C Baggage specification restricts the Property keys to strings that
// satisfy the token definition from RFC7230, Section 3.2.6.
// For maximum compatibility, alphanumeric value are strongly recommended to be used as Property key.
func ( string) (Property, error) {
	if !validateBaggageName() {
		return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, )
	}

	 := Property{key: }
	return , nil
}

// NewKeyValueProperty returns a new Property for key with value.
//
// The passed key must be compliant with W3C Baggage specification.
// The passed value must be percent-encoded as defined in W3C Baggage specification.
//
// Notice: Consider using [NewKeyValuePropertyRaw] instead
// that does not require percent-encoding of the value.
func (,  string) (Property, error) {
	if !validateKey() {
		return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, )
	}

	if !validateValue() {
		return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidValue, )
	}
	,  := url.PathUnescape()
	if  != nil {
		return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidValue, )
	}
	return NewKeyValuePropertyRaw(, )
}

// NewKeyValuePropertyRaw returns a new Property for key with value.
//
// The passed key must be valid, non-empty UTF-8 string.
// The passed value must be valid UTF-8 string.
// However, the specific Propagators that are used to transmit baggage entries across
// component boundaries may impose their own restrictions on Property key.
// For example, the W3C Baggage specification restricts the Property keys to strings that
// satisfy the token definition from RFC7230, Section 3.2.6.
// For maximum compatibility, alphanumeric value are strongly recommended to be used as Property key.
func (,  string) (Property, error) {
	if !validateBaggageName() {
		return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidKey, )
	}
	if !validateBaggageValue() {
		return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidValue, )
	}

	 := Property{
		key:      ,
		value:    ,
		hasValue: true,
	}
	return , nil
}

func newInvalidProperty() Property {
	return Property{}
}

// parseProperty attempts to decode a Property from the passed string. It
// returns an error if the input is invalid according to the W3C Baggage
// specification.
func parseProperty( string) (Property, error) {
	if  == "" {
		return newInvalidProperty(), nil
	}

	,  := parsePropertyInternal()
	if ! {
		return newInvalidProperty(), fmt.Errorf("%w: %q", errInvalidProperty, )
	}

	return , nil
}

// validate ensures p conforms to the W3C Baggage specification, returning an
// error otherwise.
func ( Property) () error {
	 := func( error) error {
		return fmt.Errorf("invalid property: %w", )
	}

	if !validateBaggageName(.key) {
		return (fmt.Errorf("%w: %q", errInvalidKey, .key))
	}
	if !.hasValue && .value != "" {
		return (errors.New("inconsistent value"))
	}
	if .hasValue && !validateBaggageValue(.value) {
		return (fmt.Errorf("%w: %q", errInvalidValue, .value))
	}
	return nil
}

// Key returns the Property key.
func ( Property) () string {
	return .key
}

// Value returns the Property value. Additionally, a boolean value is returned
// indicating if the returned value is the empty if the Property has a value
// that is empty or if the value is not set.
func ( Property) () (string, bool) {
	return .value, .hasValue
}

// String encodes Property into a header string compliant with the W3C Baggage
// specification.
// It would return empty string if the key is invalid with the W3C Baggage
// specification. This could happen for a UTF-8 key, as it may contain
// invalid characters.
func ( Property) () string {
	//  W3C Baggage specification does not allow percent-encoded keys.
	if !validateKey(.key) {
		return ""
	}

	if .hasValue {
		return fmt.Sprintf("%s%s%v", .key, keyValueDelimiter, valueEscape(.value))
	}
	return .key
}

type properties []Property

func fromInternalProperties( []baggage.Property) properties {
	if len() == 0 {
		return nil
	}

	 := make(properties, len())
	for ,  := range  {
		[] = Property{
			key:      .Key,
			value:    .Value,
			hasValue: .HasValue,
		}
	}
	return 
}

func ( properties) () []baggage.Property {
	if len() == 0 {
		return nil
	}

	 := make([]baggage.Property, len())
	for ,  := range  {
		[] = baggage.Property{
			Key:      .key,
			Value:    .value,
			HasValue: .hasValue,
		}
	}
	return 
}

func ( properties) () properties {
	if len() == 0 {
		return nil
	}

	 := make(properties, len())
	copy(, )
	return 
}

// validate ensures each Property in p conforms to the W3C Baggage
// specification, returning an error otherwise.
func ( properties) () error {
	for ,  := range  {
		if  := .validate();  != nil {
			return 
		}
	}
	return nil
}

// String encodes properties into a header string compliant with the W3C Baggage
// specification.
func ( properties) () string {
	 := make([]string, 0, len())
	for ,  := range  {
		 := .String()

		// Ignored empty properties.
		if  != "" {
			 = append(, )
		}
	}
	return strings.Join(, propertyDelimiter)
}

// Member is a list-member of a baggage-string as defined by the W3C Baggage
// specification.
type Member struct {
	key, value string
	properties properties

	// hasData indicates whether the created property contains data or not.
	// Properties that do not contain data are invalid with no other check
	// required.
	hasData bool
}

// NewMember returns a new Member from the passed arguments.
//
// The passed key must be compliant with W3C Baggage specification.
// The passed value must be percent-encoded as defined in W3C Baggage specification.
//
// Notice: Consider using [NewMemberRaw] instead
// that does not require percent-encoding of the value.
func (,  string,  ...Property) (Member, error) {
	if !validateKey() {
		return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidKey, )
	}

	if !validateValue() {
		return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, )
	}
	,  := url.PathUnescape()
	if  != nil {
		return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, )
	}
	return NewMemberRaw(, , ...)
}

// NewMemberRaw returns a new Member from the passed arguments.
//
// The passed key must be valid, non-empty UTF-8 string.
// The passed value must be valid UTF-8 string.
// However, the specific Propagators that are used to transmit baggage entries across
// component boundaries may impose their own restrictions on baggage key.
// For example, the W3C Baggage specification restricts the baggage keys to strings that
// satisfy the token definition from RFC7230, Section 3.2.6.
// For maximum compatibility, alphanumeric value are strongly recommended to be used as baggage key.
func (,  string,  ...Property) (Member, error) {
	 := Member{
		key:        ,
		value:      ,
		properties: properties().Copy(),
		hasData:    true,
	}
	if  := .validate();  != nil {
		return newInvalidMember(), 
	}
	return , nil
}

func newInvalidMember() Member {
	return Member{}
}

// parseMember attempts to decode a Member from the passed string. It returns
// an error if the input is invalid according to the W3C Baggage
// specification.
func parseMember( string) (Member, error) {
	if  := len();  > maxBytesPerMembers {
		return newInvalidMember(), fmt.Errorf("%w: %d", errMemberBytes, )
	}

	var  properties
	, ,  := strings.Cut(, propertyDelimiter)
	if  {
		// Parse the member properties.
		for ,  := range strings.Split(, propertyDelimiter) {
			,  := parseProperty()
			if  != nil {
				return newInvalidMember(), 
			}
			 = append(, )
		}
	}
	// Parse the member key/value pair.

	// Take into account a value can contain equal signs (=).
	, ,  := strings.Cut(, keyValueDelimiter)
	if ! {
		return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidMember, )
	}
	// "Leading and trailing whitespaces are allowed but MUST be trimmed
	// when converting the header into a data structure."
	 := strings.TrimSpace()
	if !validateKey() {
		return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidKey, )
	}

	 := strings.TrimSpace()
	if !validateValue() {
		return newInvalidMember(), fmt.Errorf("%w: %q", errInvalidValue, )
	}

	// Decode a percent-encoded value.
	,  := url.PathUnescape()
	if  != nil {
		return newInvalidMember(), fmt.Errorf("%w: %w", errInvalidValue, )
	}

	 := replaceInvalidUTF8Sequences(len(), )
	return Member{key: , value: , properties: , hasData: true}, nil
}

// replaceInvalidUTF8Sequences replaces invalid UTF-8 sequences with '�'.
func replaceInvalidUTF8Sequences( int,  string) string {
	if utf8.ValidString() {
		return 
	}
	// W3C baggage spec:
	// https://github.com/w3c/baggage/blob/8c215efbeebd3fa4b1aceb937a747e56444f22f3/baggage/HTTP_HEADER_FORMAT.md?plain=1#L69

	var  strings.Builder
	.Grow()
	for  := 0;  < len(); {
		,  := utf8.DecodeRuneInString([:])
		if  == utf8.RuneError &&  == 1 {
			// Invalid UTF-8 sequence found, replace it with '�'
			_, _ = .WriteString("�")
		} else {
			_, _ = .WriteRune()
		}
		 += 
	}

	return .String()
}

// validate ensures m conforms to the W3C Baggage specification.
// A key must be an ASCII string, returning an error otherwise.
func ( Member) () error {
	if !.hasData {
		return fmt.Errorf("%w: %q", errInvalidMember, )
	}

	if !validateBaggageName(.key) {
		return fmt.Errorf("%w: %q", errInvalidKey, .key)
	}
	if !validateBaggageValue(.value) {
		return fmt.Errorf("%w: %q", errInvalidValue, .value)
	}
	return .properties.validate()
}

// Key returns the Member key.
func ( Member) () string { return .key }

// Value returns the Member value.
func ( Member) () string { return .value }

// Properties returns a copy of the Member properties.
func ( Member) () []Property { return .properties.Copy() }

// String encodes Member into a header string compliant with the W3C Baggage
// specification.
// It would return empty string if the key is invalid with the W3C Baggage
// specification. This could happen for a UTF-8 key, as it may contain
// invalid characters.
func ( Member) () string {
	//  W3C Baggage specification does not allow percent-encoded keys.
	if !validateKey(.key) {
		return ""
	}

	 := .key + keyValueDelimiter + valueEscape(.value)
	if len(.properties) > 0 {
		 += propertyDelimiter + .properties.String()
	}
	return 
}

// Baggage is a list of baggage members representing the baggage-string as
// defined by the W3C Baggage specification.
type Baggage struct { //nolint:golint
	list baggage.List
}

// New returns a new valid Baggage. It returns an error if it results in a
// Baggage exceeding limits set in that specification.
//
// It expects all the provided members to have already been validated.
func ( ...Member) (Baggage, error) {
	if len() == 0 {
		return Baggage{}, nil
	}

	 := make(baggage.List)
	for ,  := range  {
		if !.hasData {
			return Baggage{}, errInvalidMember
		}

		// OpenTelemetry resolves duplicates by last-one-wins.
		[.key] = baggage.Item{
			Value:      .value,
			Properties: .properties.asInternal(),
		}
	}

	// Check member numbers after deduplication.
	if len() > maxMembers {
		return Baggage{}, errMemberNumber
	}

	 := Baggage{}
	if  := len(.String());  > maxBytesPerBaggageString {
		return Baggage{}, fmt.Errorf("%w: %d", errBaggageBytes, )
	}

	return , nil
}

// Parse attempts to decode a baggage-string from the passed string. It
// returns an error if the input is invalid according to the W3C Baggage
// specification.
//
// If there are duplicate list-members contained in baggage, the last one
// defined (reading left-to-right) will be the only one kept. This diverges
// from the W3C Baggage specification which allows duplicate list-members, but
// conforms to the OpenTelemetry Baggage specification.
func ( string) (Baggage, error) {
	if  == "" {
		return Baggage{}, nil
	}

	if  := len();  > maxBytesPerBaggageString {
		return Baggage{}, fmt.Errorf("%w: %d", errBaggageBytes, )
	}

	 := make(baggage.List)
	for ,  := range strings.Split(, listDelimiter) {
		,  := parseMember()
		if  != nil {
			return Baggage{}, 
		}
		// OpenTelemetry resolves duplicates by last-one-wins.
		[.key] = baggage.Item{
			Value:      .value,
			Properties: .properties.asInternal(),
		}
	}

	// OpenTelemetry does not allow for duplicate list-members, but the W3C
	// specification does. Now that we have deduplicated, ensure the baggage
	// does not exceed list-member limits.
	if len() > maxMembers {
		return Baggage{}, errMemberNumber
	}

	return Baggage{}, nil
}

// Member returns the baggage list-member identified by key.
//
// If there is no list-member matching the passed key the returned Member will
// be a zero-value Member.
// The returned member is not validated, as we assume the validation happened
// when it was added to the Baggage.
func ( Baggage) ( string) Member {
	,  := .list[]
	if ! {
		// We do not need to worry about distinguishing between the situation
		// where a zero-valued Member is included in the Baggage because a
		// zero-valued Member is invalid according to the W3C Baggage
		// specification (it has an empty key).
		return newInvalidMember()
	}

	return Member{
		key:        ,
		value:      .Value,
		properties: fromInternalProperties(.Properties),
		hasData:    true,
	}
}

// Members returns all the baggage list-members.
// The order of the returned list-members is not significant.
//
// The returned members are not validated, as we assume the validation happened
// when they were added to the Baggage.
func ( Baggage) () []Member {
	if len(.list) == 0 {
		return nil
	}

	 := make([]Member, 0, len(.list))
	for ,  := range .list {
		 = append(, Member{
			key:        ,
			value:      .Value,
			properties: fromInternalProperties(.Properties),
			hasData:    true,
		})
	}
	return 
}

// SetMember returns a copy of the Baggage with the member included. If the
// baggage contains a Member with the same key, the existing Member is
// replaced.
//
// If member is invalid according to the W3C Baggage specification, an error
// is returned with the original Baggage.
func ( Baggage) ( Member) (Baggage, error) {
	if !.hasData {
		return , errInvalidMember
	}

	 := len(.list)
	if ,  := .list[.key]; ! {
		++
	}
	 := make(baggage.List, )

	for ,  := range .list {
		// Do not copy if we are just going to overwrite.
		if  == .key {
			continue
		}
		[] = 
	}

	[.key] = baggage.Item{
		Value:      .value,
		Properties: .properties.asInternal(),
	}

	return Baggage{list: }, nil
}

// DeleteMember returns a copy of the Baggage with the list-member identified
// by key removed.
func ( Baggage) ( string) Baggage {
	 := len(.list)
	if ,  := .list[];  {
		--
	}
	 := make(baggage.List, )

	for ,  := range .list {
		if  ==  {
			continue
		}
		[] = 
	}

	return Baggage{list: }
}

// Len returns the number of list-members in the Baggage.
func ( Baggage) () int {
	return len(.list)
}

// String encodes Baggage into a header string compliant with the W3C Baggage
// specification.
// It would ignore members where the member key is invalid with the W3C Baggage
// specification. This could happen for a UTF-8 key, as it may contain
// invalid characters.
func ( Baggage) () string {
	 := make([]string, 0, len(.list))
	for ,  := range .list {
		 := Member{
			key:        ,
			value:      .Value,
			properties: fromInternalProperties(.Properties),
		}.String()

		// Ignored empty members.
		if  != "" {
			 = append(, )
		}
	}
	return strings.Join(, listDelimiter)
}

// parsePropertyInternal attempts to decode a Property from the passed string.
// It follows the spec at https://www.w3.org/TR/baggage/#definition.
func parsePropertyInternal( string) ( Property,  bool) {
	// For the entire function we will use "   key    =    value  " as an example.
	// Attempting to parse the key.
	// First skip spaces at the beginning "<   >key    =    value  " (they could be empty).
	 := skipSpace(, 0)

	// Parse the key: "   <key>    =    value  ".
	 := 
	 := 
	for ,  := range [:] {
		if !validateKeyChar() {
			break
		}
		++
	}

	// If we couldn't find any valid key character,
	// it means the key is either empty or invalid.
	if  ==  {
		return
	}

	// Skip spaces after the key: "   key<    >=    value  ".
	 = skipSpace(, )

	if  == len() {
		// A key can have no value, like: "   key    ".
		 = true
		.key = [:]
		return
	}

	// If we have not reached the end and we can't find the '=' delimiter,
	// it means the property is invalid.
	if [] != keyValueDelimiter[0] {
		return
	}

	// Attempting to parse the value.
	// Match: "   key    =<    >value  ".
	 = skipSpace(, +1)

	// Match the value string: "   key    =    <value>  ".
	// A valid property can be: "   key    =".
	// Therefore, we don't have to check if the value is empty.
	 := 
	 := 
	for ,  := range [:] {
		if !validateValueChar() {
			break
		}
		++
	}

	// Skip all trailing whitespaces: "   key    =    value<  >".
	 = skipSpace(, )

	// If after looking for the value and skipping whitespaces
	// we have not reached the end, it means the property is
	// invalid, something like: "   key    =    value  value1".
	if  != len() {
		return
	}

	// Decode a percent-encoded value.
	 := [:]
	,  := url.PathUnescape()
	if  != nil {
		return
	}
	 := replaceInvalidUTF8Sequences(len(), )

	 = true
	.key = [:]
	.hasValue = true

	.value = 
	return
}

func skipSpace( string,  int) int {
	 := 
	for ;  < len(); ++ {
		 := []
		if  != ' ' &&  != '\t' {
			break
		}
	}
	return 
}

var safeKeyCharset = [utf8.RuneSelf]bool{
	// 0x23 to 0x27
	'#':  true,
	'$':  true,
	'%':  true,
	'&':  true,
	'\'': true,

	// 0x30 to 0x39
	'0': true,
	'1': true,
	'2': true,
	'3': true,
	'4': true,
	'5': true,
	'6': true,
	'7': true,
	'8': true,
	'9': true,

	// 0x41 to 0x5a
	'A': true,
	'B': true,
	'C': true,
	'D': true,
	'E': true,
	'F': true,
	'G': true,
	'H': true,
	'I': true,
	'J': true,
	'K': true,
	'L': true,
	'M': true,
	'N': true,
	'O': true,
	'P': true,
	'Q': true,
	'R': true,
	'S': true,
	'T': true,
	'U': true,
	'V': true,
	'W': true,
	'X': true,
	'Y': true,
	'Z': true,

	// 0x5e to 0x7a
	'^': true,
	'_': true,
	'`': true,
	'a': true,
	'b': true,
	'c': true,
	'd': true,
	'e': true,
	'f': true,
	'g': true,
	'h': true,
	'i': true,
	'j': true,
	'k': true,
	'l': true,
	'm': true,
	'n': true,
	'o': true,
	'p': true,
	'q': true,
	'r': true,
	's': true,
	't': true,
	'u': true,
	'v': true,
	'w': true,
	'x': true,
	'y': true,
	'z': true,

	// remainder
	'!': true,
	'*': true,
	'+': true,
	'-': true,
	'.': true,
	'|': true,
	'~': true,
}

// validateBaggageName checks if the string is a valid OpenTelemetry Baggage name.
// Baggage name is a valid, non-empty UTF-8 string.
func validateBaggageName( string) bool {
	if  == "" {
		return false
	}

	return utf8.ValidString()
}

// validateBaggageValue checks if the string is a valid OpenTelemetry Baggage value.
// Baggage value is a valid UTF-8 strings.
// Empty string is also a valid UTF-8 string.
func validateBaggageValue( string) bool {
	return utf8.ValidString()
}

// validateKey checks if the string is a valid W3C Baggage key.
func validateKey( string) bool {
	if  == "" {
		return false
	}

	for ,  := range  {
		if !validateKeyChar() {
			return false
		}
	}

	return true
}

func validateKeyChar( int32) bool {
	return  >= 0 &&  < int32(utf8.RuneSelf) && safeKeyCharset[]
}

// validateValue checks if the string is a valid W3C Baggage value.
func validateValue( string) bool {
	for ,  := range  {
		if !validateValueChar() {
			return false
		}
	}

	return true
}

var safeValueCharset = [utf8.RuneSelf]bool{
	'!': true, // 0x21

	// 0x23 to 0x2b
	'#':  true,
	'$':  true,
	'%':  true,
	'&':  true,
	'\'': true,
	'(':  true,
	')':  true,
	'*':  true,
	'+':  true,

	// 0x2d to 0x3a
	'-': true,
	'.': true,
	'/': true,
	'0': true,
	'1': true,
	'2': true,
	'3': true,
	'4': true,
	'5': true,
	'6': true,
	'7': true,
	'8': true,
	'9': true,
	':': true,

	// 0x3c to 0x5b
	'<': true, // 0x3C
	'=': true, // 0x3D
	'>': true, // 0x3E
	'?': true, // 0x3F
	'@': true, // 0x40
	'A': true, // 0x41
	'B': true, // 0x42
	'C': true, // 0x43
	'D': true, // 0x44
	'E': true, // 0x45
	'F': true, // 0x46
	'G': true, // 0x47
	'H': true, // 0x48
	'I': true, // 0x49
	'J': true, // 0x4A
	'K': true, // 0x4B
	'L': true, // 0x4C
	'M': true, // 0x4D
	'N': true, // 0x4E
	'O': true, // 0x4F
	'P': true, // 0x50
	'Q': true, // 0x51
	'R': true, // 0x52
	'S': true, // 0x53
	'T': true, // 0x54
	'U': true, // 0x55
	'V': true, // 0x56
	'W': true, // 0x57
	'X': true, // 0x58
	'Y': true, // 0x59
	'Z': true, // 0x5A
	'[': true, // 0x5B

	// 0x5d to 0x7e
	']': true, // 0x5D
	'^': true, // 0x5E
	'_': true, // 0x5F
	'`': true, // 0x60
	'a': true, // 0x61
	'b': true, // 0x62
	'c': true, // 0x63
	'd': true, // 0x64
	'e': true, // 0x65
	'f': true, // 0x66
	'g': true, // 0x67
	'h': true, // 0x68
	'i': true, // 0x69
	'j': true, // 0x6A
	'k': true, // 0x6B
	'l': true, // 0x6C
	'm': true, // 0x6D
	'n': true, // 0x6E
	'o': true, // 0x6F
	'p': true, // 0x70
	'q': true, // 0x71
	'r': true, // 0x72
	's': true, // 0x73
	't': true, // 0x74
	'u': true, // 0x75
	'v': true, // 0x76
	'w': true, // 0x77
	'x': true, // 0x78
	'y': true, // 0x79
	'z': true, // 0x7A
	'{': true, // 0x7B
	'|': true, // 0x7C
	'}': true, // 0x7D
	'~': true, // 0x7E
}

func validateValueChar( int32) bool {
	return  >= 0 &&  < int32(utf8.RuneSelf) && safeValueCharset[]
}

// valueEscape escapes the string so it can be safely placed inside a baggage value,
// replacing special characters with %XX sequences as needed.
//
// The implementation is based on:
// https://github.com/golang/go/blob/f6509cf5cdbb5787061b784973782933c47f1782/src/net/url/url.go#L285.
func valueEscape( string) string {
	 := 0
	for  := 0;  < len(); ++ {
		 := []
		if shouldEscape() {
			++
		}
	}

	if  == 0 {
		return 
	}

	var  [64]byte
	var  []byte

	 := len() + 2*
	if  <= len() {
		 = [:]
	} else {
		 = make([]byte, )
	}

	 := 0
	for  := 0;  < len(); ++ {
		 := []
		if shouldEscape([]) {
			const  = "0123456789ABCDEF"
			[] = '%'
			[+1] = [>>4]
			[+2] = [&15]
			 += 3
		} else {
			[] = 
			++
		}
	}

	return string()
}

// shouldEscape returns true if the specified byte should be escaped when
// appearing in a baggage value string.
func shouldEscape( byte) bool {
	if  == '%' {
		// The percent character must be encoded so that percent-encoding can work.
		return true
	}
	return !validateValueChar(int32())
}