/* * * 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 ( "fmt" "strings" "google.golang.org/grpc/metadata" "google.golang.org/grpc/resolver" ) type mdKeyType string const mdKey = mdKeyType("grpc.internal.address.metadata") type mdValue metadata.MD func (m mdValue) Equal(o interface{}) bool { om, ok := o.(mdValue) if !ok { return false } if len(m) != len(om) { return false } for k, v := range m { ov := om[k] if len(ov) != len(v) { return false } for i, ve := range v { if ov[i] != ve { return false } } } return true } // Get returns the metadata of addr. func Get(addr resolver.Address) metadata.MD { attrs := addr.Attributes if attrs == nil { return nil } md, _ := attrs.Value(mdKey).(mdValue) return metadata.MD(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 Set(addr resolver.Address, md metadata.MD) resolver.Address { addr.Attributes = addr.Attributes.WithValue(mdKey, mdValue(md)) return addr } // Validate returns an error if the input md contains invalid keys or values. // // If the header is not a pseudo-header, the following items are checked: // - header names must contain one or more characters from this set [0-9 a-z _ - .]. // - if the header-name ends with a "-bin" suffix, no validation of the header value is performed. // - otherwise, the header value must contain one or more characters from the set [%x20-%x7E]. func Validate(md metadata.MD) error { for k, vals := range md { // pseudo-header will be ignored if k[0] == ':' { continue } // check key, for i that saving a conversion if not using for range for i := 0; i < len(k); i++ { r := k[i] if !(r >= 'a' && r <= 'z') && !(r >= '0' && r <= '9') && r != '.' && r != '-' && r != '_' { return fmt.Errorf("header key %q contains illegal characters not in [0-9a-z-_.]", k) } } if strings.HasSuffix(k, "-bin") { continue } // check value for _, val := range vals { if hasNotPrintable(val) { return fmt.Errorf("header key %q contains value with non-printable ASCII characters", k) } } } return nil } // hasNotPrintable return true if msg contains any characters which are not in %x20-%x7E func hasNotPrintable(msg string) bool { // for i that saving a conversion if not using for range for i := 0; i < len(msg); i++ { if msg[i] < 0x20 || msg[i] > 0x7E { return true } } return false }