/*
 *
 * Copyright 2020 gRPC 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 metadata contains functions to set and get metadata from addresses. // // This package is experimental.
package metadata import ( ) type mdKeyType string const mdKey = mdKeyType("grpc.internal.address.metadata") type mdValue metadata.MD func ( mdValue) ( any) bool { , := .(mdValue) if ! { return false } if len() != len() { return false } for , := range { := [] if len() != len() { return false } for , := range { if [] != { return false } } } return true } // Get returns the metadata of addr. func ( resolver.Address) metadata.MD { := .Attributes if == nil { return nil } , := .Value(mdKey).(mdValue) return metadata.MD() } // Set sets (overrides) the metadata in addr. // // When a SubConn is created with this address, the RPCs sent on it will all // have this metadata. func ( resolver.Address, metadata.MD) resolver.Address { .Attributes = .Attributes.WithValue(mdKey, mdValue()) return } // Validate validates every pair in md with ValidatePair. func ( metadata.MD) error { for , := range { if := ValidatePair(, ...); != nil { return } } return nil } // hasNotPrintable return true if msg contains any characters which are not in %x20-%x7E func ( string) bool { // for i that saving a conversion if not using for range for := 0; < len(); ++ { if [] < 0x20 || [] > 0x7E { return true } } return false } // ValidateKey validates a key with the following rules (pseudo-headers are // skipped): // - the key must contain one or more characters. // - the characters in the key must be in [0-9 a-z _ - .]. func ( string) error { // key should not be empty if == "" { return fmt.Errorf("there is an empty key in the header") } // pseudo-header will be ignored if [0] == ':' { return nil } // check key, for i that saving a conversion if not using for range for := 0; < len(); ++ { := [] if !( >= 'a' && <= 'z') && !( >= '0' && <= '9') && != '.' && != '-' && != '_' { return fmt.Errorf("header key %q contains illegal characters not in [0-9a-z-_.]", ) } } return nil } // ValidatePair validates a key-value pair with the following rules // (pseudo-header are skipped): // - the key must contain one or more characters. // - the characters in the key must be in [0-9 a-z _ - .]. // - if the key ends with a "-bin" suffix, no validation of the corresponding // value is performed. // - the characters in every value must be printable (in [%x20-%x7E]). func ( string, ...string) error { if := ValidateKey(); != nil { return } if strings.HasSuffix(, "-bin") { return nil } // check value for , := range { if hasNotPrintable() { return fmt.Errorf("header key %q contains value with non-printable ASCII characters", ) } } return nil }