go.temporal.io/server@v1.23.0/common/headers/headers.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package headers 26 27 import ( 28 "context" 29 30 "google.golang.org/grpc/metadata" 31 ) 32 33 const ( 34 ClientNameHeaderName = "client-name" 35 ClientVersionHeaderName = "client-version" 36 SupportedServerVersionsHeaderName = "supported-server-versions" 37 SupportedFeaturesHeaderName = "supported-features" 38 SupportedFeaturesHeaderDelim = "," 39 40 callerNameHeaderName = "caller-name" 41 CallerTypeHeaderName = "caller-type" 42 callOriginHeaderName = "call-initiation" 43 ) 44 45 var ( 46 // propagateHeaders are the headers to propagate from the frontend to other services. 47 propagateHeaders = []string{ 48 ClientNameHeaderName, 49 ClientVersionHeaderName, 50 SupportedServerVersionsHeaderName, 51 SupportedFeaturesHeaderName, 52 callerNameHeaderName, 53 CallerTypeHeaderName, 54 callOriginHeaderName, 55 } 56 ) 57 58 // GetValues returns header values for passed header names. 59 // It always returns slice of the same size as number of passed header names. 60 func GetValues(ctx context.Context, headerNames ...string) []string { 61 headerValues := make([]string, len(headerNames)) 62 63 if md, ok := metadata.FromIncomingContext(ctx); ok { 64 for i, headerName := range headerNames { 65 headerValues[i] = getSingleHeaderValue(md, headerName) 66 } 67 } 68 69 return headerValues 70 } 71 72 // Propagate propagates version headers from incoming context to outgoing context. 73 // It copies all headers to outgoing context only if they are exist in incoming context 74 // and doesn't exist in outgoing context already. 75 func Propagate(ctx context.Context) context.Context { 76 if mdIncoming, ok := metadata.FromIncomingContext(ctx); ok { 77 var headersToAppend []string 78 mdOutgoing, mdOutgoingExist := metadata.FromOutgoingContext(ctx) 79 for _, headerName := range propagateHeaders { 80 if incomingValue := mdIncoming.Get(headerName); len(incomingValue) > 0 { 81 if mdOutgoingExist { 82 if outgoingValue := mdOutgoing.Get(headerName); len(outgoingValue) > 0 { 83 continue 84 } 85 } 86 headersToAppend = append(headersToAppend, headerName, incomingValue[0]) 87 } 88 } 89 if headersToAppend != nil { 90 if mdOutgoingExist { 91 ctx = metadata.AppendToOutgoingContext(ctx, headersToAppend...) 92 } else { 93 ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(headersToAppend...)) 94 } 95 } 96 } 97 return ctx 98 } 99 100 func getSingleHeaderValue(md metadata.MD, headerName string) string { 101 values := md.Get(headerName) 102 if len(values) == 0 { 103 return "" 104 } 105 106 return values[0] 107 }