blob: 38f251d31a702ec4f50a89ef63c481e5c246fd18 [file] [log] [blame]
Takahiro Suzukid7bf8202020-12-17 20:21:59 +09001// Copyright 2017 Michal Witkowski. All Rights Reserved.
2// See LICENSE for licensing terms.
3
4package grpc_opentracing
5
6import (
7 "encoding/base64"
8 "strings"
9
10 "fmt"
11
12 "google.golang.org/grpc/metadata"
13)
14
15const (
16 binHdrSuffix = "-bin"
17)
18
19// metadataTextMap extends a metadata.MD to be an opentracing textmap
20type metadataTextMap metadata.MD
21
22// Set is a opentracing.TextMapReader interface that extracts values.
23func (m metadataTextMap) Set(key, val string) {
24 // gRPC allows for complex binary values to be written.
25 encodedKey, encodedVal := encodeKeyValue(key, val)
26 // The metadata object is a multimap, and previous values may exist, but for opentracing headers, we do not append
27 // we just override.
28 m[encodedKey] = []string{encodedVal}
29}
30
31// ForeachKey is a opentracing.TextMapReader interface that extracts values.
32func (m metadataTextMap) ForeachKey(callback func(key, val string) error) error {
33 for k, vv := range m {
34 for _, v := range vv {
35 if decodedKey, decodedVal, err := metadata.DecodeKeyValue(k, v); err == nil {
36 if err = callback(decodedKey, decodedVal); err != nil {
37 return err
38 }
39 } else {
40 return fmt.Errorf("failed decoding opentracing from gRPC metadata: %v", err)
41 }
42 }
43 }
44 return nil
45}
46
47// encodeKeyValue encodes key and value qualified for transmission via gRPC.
48// note: copy pasted from private values of grpc.metadata
49func encodeKeyValue(k, v string) (string, string) {
50 k = strings.ToLower(k)
51 if strings.HasSuffix(k, binHdrSuffix) {
52 val := base64.StdEncoding.EncodeToString([]byte(v))
53 v = string(val)
54 }
55 return k, v
56}