gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }