metadata.go (3443B)
1 /* 2 * 3 * Copyright 2020 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 // Package metadata contains functions to set and get metadata from addresses. 20 // 21 // This package is experimental. 22 package metadata 23 24 import ( 25 "fmt" 26 "strings" 27 28 "google.golang.org/grpc/metadata" 29 "google.golang.org/grpc/resolver" 30 ) 31 32 type mdKeyType string 33 34 const mdKey = mdKeyType("grpc.internal.address.metadata") 35 36 type mdValue metadata.MD 37 38 func (m mdValue) Equal(o interface{}) bool { 39 om, ok := o.(mdValue) 40 if !ok { 41 return false 42 } 43 if len(m) != len(om) { 44 return false 45 } 46 for k, v := range m { 47 ov := om[k] 48 if len(ov) != len(v) { 49 return false 50 } 51 for i, ve := range v { 52 if ov[i] != ve { 53 return false 54 } 55 } 56 } 57 return true 58 } 59 60 // Get returns the metadata of addr. 61 func Get(addr resolver.Address) metadata.MD { 62 attrs := addr.Attributes 63 if attrs == nil { 64 return nil 65 } 66 md, _ := attrs.Value(mdKey).(mdValue) 67 return metadata.MD(md) 68 } 69 70 // Set sets (overrides) the metadata in addr. 71 // 72 // When a SubConn is created with this address, the RPCs sent on it will all 73 // have this metadata. 74 func Set(addr resolver.Address, md metadata.MD) resolver.Address { 75 addr.Attributes = addr.Attributes.WithValue(mdKey, mdValue(md)) 76 return addr 77 } 78 79 // Validate validates every pair in md with ValidatePair. 80 func Validate(md metadata.MD) error { 81 for k, vals := range md { 82 if err := ValidatePair(k, vals...); err != nil { 83 return err 84 } 85 } 86 return nil 87 } 88 89 // hasNotPrintable return true if msg contains any characters which are not in %x20-%x7E 90 func hasNotPrintable(msg string) bool { 91 // for i that saving a conversion if not using for range 92 for i := 0; i < len(msg); i++ { 93 if msg[i] < 0x20 || msg[i] > 0x7E { 94 return true 95 } 96 } 97 return false 98 } 99 100 // ValidatePair validate a key-value pair with the following rules (the pseudo-header will be skipped) : 101 // 102 // - key must contain one or more characters. 103 // - the characters in the key must be contained in [0-9 a-z _ - .]. 104 // - if the key ends with a "-bin" suffix, no validation of the corresponding value is performed. 105 // - the characters in the every value must be printable (in [%x20-%x7E]). 106 func ValidatePair(key string, vals ...string) error { 107 // key should not be empty 108 if key == "" { 109 return fmt.Errorf("there is an empty key in the header") 110 } 111 // pseudo-header will be ignored 112 if key[0] == ':' { 113 return nil 114 } 115 // check key, for i that saving a conversion if not using for range 116 for i := 0; i < len(key); i++ { 117 r := key[i] 118 if !(r >= 'a' && r <= 'z') && !(r >= '0' && r <= '9') && r != '.' && r != '-' && r != '_' { 119 return fmt.Errorf("header key %q contains illegal characters not in [0-9a-z-_.]", key) 120 } 121 } 122 if strings.HasSuffix(key, "-bin") { 123 return nil 124 } 125 // check value 126 for _, val := range vals { 127 if hasNotPrintable(val) { 128 return fmt.Errorf("header key %q contains value with non-printable ASCII characters", key) 129 } 130 } 131 return nil 132 }