github.com/aaabigfish/gopkg@v1.1.0/cloud/metainfo/http.go (about) 1 // Copyright 2021 ByteDance Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package metainfo 16 17 import ( 18 "context" 19 "strings" 20 21 "golang.org/x/net/http/httpguts" 22 ) 23 24 // HTTP header prefixes. 25 const ( 26 HTTPPrefixTransient = "rpc-transit-" 27 HTTPPrefixPersistent = "rpc-persist-" 28 HTTPPrefixBackward = "rpc-backward-" 29 30 lenHPT = len(HTTPPrefixTransient) 31 lenHPP = len(HTTPPrefixPersistent) 32 lenHPB = len(HTTPPrefixBackward) 33 ) 34 35 // HTTPHeaderToCGIVariable performs an CGI variable conversion. 36 // For example, an HTTP header key `abc-def` will result in `ABC_DEF`. 37 func HTTPHeaderToCGIVariable(key string) string { 38 return strings.ToUpper(strings.ReplaceAll(key, "-", "_")) 39 } 40 41 // CGIVariableToHTTPHeader converts a CGI variable into an HTTP header key. 42 // For example, `ABC_DEF` will be converted to `abc-def`. 43 func CGIVariableToHTTPHeader(key string) string { 44 return strings.ToLower(strings.ReplaceAll(key, "_", "-")) 45 } 46 47 // HTTPHeaderSetter sets a key with a value into a HTTP header. 48 type HTTPHeaderSetter interface { 49 Set(key, value string) 50 } 51 52 // HTTPHeaderCarrier accepts a visitor to access all key value pairs in an HTTP header. 53 type HTTPHeaderCarrier interface { 54 Visit(func(k, v string)) 55 } 56 57 // HTTPHeader is provided to wrap an http.Header into an HTTPHeaderCarrier. 58 type HTTPHeader map[string][]string 59 60 // Visit implements the HTTPHeaderCarrier interface. 61 func (h HTTPHeader) Visit(v func(k, v string)) { 62 for k, vs := range h { 63 v(k, vs[0]) 64 } 65 } 66 67 // Set sets the header entries associated with key to the single element value. 68 // The key will converted into lowercase as the HTTP/2 protocol requires. 69 func (h HTTPHeader) Set(key, value string) { 70 h[strings.ToLower(key)] = []string{value} 71 } 72 73 // FromHTTPHeader reads metainfo from a given HTTP header and sets them into the context. 74 // Note that this function does not call TransferForward inside. 75 func FromHTTPHeader(ctx context.Context, h HTTPHeaderCarrier) context.Context { 76 if ctx == nil || h == nil { 77 return ctx 78 } 79 80 var m *mapView 81 if x := getNode(ctx); x != nil { 82 m = x.mapView() 83 } else { 84 m = newMapView() 85 } 86 h.Visit(func(k, v string) { 87 if len(v) == 0 { 88 return 89 } 90 91 kk := strings.ToLower(k) 92 ln := len(kk) 93 94 if ln > lenHPT && strings.HasPrefix(kk, HTTPPrefixTransient) { 95 kk = HTTPHeaderToCGIVariable(kk[lenHPT:]) 96 m.transient[kk] = v 97 } else if ln > lenHPP && strings.HasPrefix(kk, HTTPPrefixPersistent) { 98 kk = HTTPHeaderToCGIVariable(kk[lenHPP:]) 99 m.persistent[kk] = v 100 } 101 }) 102 103 if m.size() == 0 { 104 // TODO: remove this? 105 return ctx 106 } 107 return withNode(ctx, m.toNode()) 108 } 109 110 // ToHTTPHeader writes all metainfo into the given HTTP header. 111 // Note that this function does not call TransferForward inside. 112 // Any key or value that does not follow the HTTP specification 113 // will be discarded. 114 func ToHTTPHeader(ctx context.Context, h HTTPHeaderSetter) { 115 if ctx == nil || h == nil { 116 return 117 } 118 119 for k, v := range GetAllValues(ctx) { 120 if httpguts.ValidHeaderFieldName(k) && httpguts.ValidHeaderFieldValue(v) { 121 k := HTTPPrefixTransient + CGIVariableToHTTPHeader(k) 122 h.Set(k, v) 123 } 124 } 125 126 for k, v := range GetAllPersistentValues(ctx) { 127 if httpguts.ValidHeaderFieldName(k) && httpguts.ValidHeaderFieldValue(v) { 128 k := HTTPPrefixPersistent + CGIVariableToHTTPHeader(k) 129 h.Set(k, v) 130 } 131 } 132 }