metadata: split context to incoming and outgoing

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2021-02-09 01:08:45 +03:00
parent 1de9911b73
commit 0e51a79bb6
9 changed files with 84 additions and 136 deletions

View File

@ -187,7 +187,7 @@ func (n *noopClient) Publish(ctx context.Context, p Message, opts ...PublishOpti
options := NewPublishOptions(opts...) options := NewPublishOptions(opts...)
md, ok := metadata.FromContext(ctx) md, ok := metadata.FromOutgoingContext(ctx)
if !ok { if !ok {
md = metadata.New(0) md = metadata.New(0)
} }

6
go.mod
View File

@ -7,15 +7,15 @@ require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/ef-ds/deque v1.0.4 github.com/ef-ds/deque v1.0.4
github.com/golang/protobuf v1.4.3 github.com/golang/protobuf v1.4.3
github.com/google/uuid v1.1.5 github.com/google/uuid v1.2.0
github.com/imdario/mergo v0.3.11 github.com/imdario/mergo v0.3.11
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/miekg/dns v1.1.35 github.com/miekg/dns v1.1.38
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
golang.org/x/net v0.0.0-20201224014010-6772e930b67b golang.org/x/net v0.0.0-20210119194325-5f4716e94777
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
google.golang.org/protobuf v1.25.0 google.golang.org/protobuf v1.25.0
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect

13
go.sum
View File

@ -31,16 +31,16 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs= github.com/miekg/dns v1.1.38 h1:MtIY+fmHUVVgv1AXzmKMWcwdCYxTRPG1EDjpqF4RCEw=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.38/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
@ -52,7 +52,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/unistack-org/micro v1.18.0 h1:EbFiII0bKV0Xcua7o6J30MFmm4/g0Hv3ECOKzsUBihU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
@ -69,8 +68,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

View File

@ -5,35 +5,64 @@ import (
"context" "context"
) )
type mdIncomingKey struct{}
type mdOutgoingKey struct{}
type mdKey struct{}
// FromIncomingContext returns metadata from incoming ctx
// returned metadata shoud not be modified or race condition happens
func FromIncomingContext(ctx context.Context) (Metadata, bool) {
if ctx == nil {
return nil, false
}
md, ok := ctx.Value(mdIncomingKey{}).(Metadata)
return md, ok
}
// FromOutgoingContext returns metadata from outgoing ctx
// returned metadata shoud not be modified or race condition happens
func FromOutgoingContext(ctx context.Context) (Metadata, bool) {
if ctx == nil {
return nil, false
}
md, ok := ctx.Value(mdOutgoingKey{}).(Metadata)
return md, ok
}
// FromContext returns metadata from the given context // FromContext returns metadata from the given context
// returned metadata shoud not be modified or race condition happens
//
// Deprecated: use FromIncomingContext or FromOutgoingContext
func FromContext(ctx context.Context) (Metadata, bool) { func FromContext(ctx context.Context) (Metadata, bool) {
if ctx == nil { if ctx == nil {
return nil, false return nil, false
} }
md, ok := ctx.Value(metadataKey{}).(Metadata) md, ok := ctx.Value(mdKey{}).(Metadata)
if !ok { return md, ok
return nil, ok
}
nmd := Copy(md)
return nmd, ok
} }
// NewContext creates a new context with the given metadata // NewContext creates a new context with the given metadata
//
// Deprecated: use NewIncomingContext or NewOutgoingContext
func NewContext(ctx context.Context, md Metadata) context.Context { func NewContext(ctx context.Context, md Metadata) context.Context {
if ctx == nil { if ctx == nil {
ctx = context.Background() ctx = context.Background()
} }
return context.WithValue(ctx, metadataKey{}, Copy(md)) return context.WithValue(ctx, mdKey{}, md)
} }
// MergeContext merges metadata to existing metadata, overwriting if specified // NewIncomingContext creates a new context with incoming metadata attached
func MergeContext(ctx context.Context, pmd Metadata, overwrite bool) context.Context { func NewIncomingContext(ctx context.Context, md Metadata) context.Context {
if ctx == nil { if ctx == nil {
ctx = context.Background() ctx = context.Background()
} }
md, ok := FromContext(ctx) return context.WithValue(ctx, mdIncomingKey{}, md)
if !ok { }
return context.WithValue(ctx, metadataKey{}, Copy(pmd))
} // NewOutgoingContext creates a new context with outcoming metadata attached
return context.WithValue(ctx, metadataKey{}, Merge(md, pmd, overwrite)) func NewOutgoingContext(ctx context.Context, md Metadata) context.Context {
if ctx == nil {
ctx = context.Background()
}
return context.WithValue(ctx, mdOutgoingKey{}, md)
} }

View File

@ -2,7 +2,6 @@
package metadata package metadata
import ( import (
"context"
"net/textproto" "net/textproto"
"sort" "sort"
) )
@ -12,16 +11,14 @@ var (
HeaderPrefix = "Micro-" HeaderPrefix = "Micro-"
) )
type metadataKey struct{}
// Metadata is our way of representing request headers internally. // Metadata is our way of representing request headers internally.
// They're used at the RPC level and translate back and forth // They're used at the RPC level and translate back and forth
// from Transport headers. // from Transport headers.
type Metadata map[string]string type Metadata map[string]string
var ( var (
// DefaultMetadataSize used when need to init new Metadata // defaultMetadataSize used when need to init new Metadata
DefaultMetadataSize = 6 defaultMetadataSize = 2
) )
type Iterator struct { type Iterator struct {
@ -72,12 +69,9 @@ func (md Metadata) Set(key, val string) {
// Del is used to remove value from metadata // Del is used to remove value from metadata
func (md Metadata) Del(key string) { func (md Metadata) Del(key string) {
// fast path // fast path
if _, ok := md[key]; ok {
delete(md, key) delete(md, key)
} else {
// slow path // slow path
delete(md, textproto.CanonicalMIMEHeaderKey(key)) delete(md, textproto.CanonicalMIMEHeaderKey(key))
}
} }
// Copy makes a copy of the metadata // Copy makes a copy of the metadata
@ -89,39 +83,10 @@ func Copy(md Metadata) Metadata {
return nmd return nmd
} }
// Del deletes key from metadata
func Del(ctx context.Context, key string) context.Context {
md, ok := FromContext(ctx)
if !ok {
md = New(0)
}
md.Del(key)
return context.WithValue(ctx, metadataKey{}, md)
}
// Set add key with val to metadata
func Set(ctx context.Context, key, val string) context.Context {
md, ok := FromContext(ctx)
if !ok {
md = New(0)
}
md.Set(key, val)
return context.WithValue(ctx, metadataKey{}, md)
}
// Get returns a single value from metadata in the context
func Get(ctx context.Context, key string) (string, bool) {
md, ok := FromContext(ctx)
if !ok {
return "", ok
}
return md.Get(key)
}
// New return new sized metadata // New return new sized metadata
func New(size int) Metadata { func New(size int) Metadata {
if size == 0 { if size == 0 {
size = DefaultMetadataSize size = defaultMetadataSize
} }
return make(Metadata, size) return make(Metadata, size)
} }

View File

@ -2,8 +2,6 @@ package metadata
import ( import (
"context" "context"
"fmt"
"reflect"
"testing" "testing"
) )
@ -32,26 +30,27 @@ func TestIterator(t *testing.T) {
var k, v string var k, v string
for iter.Next(&k, &v) { for iter.Next(&k, &v) {
fmt.Printf("k: %s, v: %s\n", k, v) //fmt.Printf("k: %s, v: %s\n", k, v)
} }
} }
func TestMedataCanonicalKey(t *testing.T) { func TestMedataCanonicalKey(t *testing.T) {
ctx := Set(context.TODO(), "x-request-id", "12345") md := New(1)
v, ok := Get(ctx, "x-request-id") md.Set("x-request-id", "12345")
v, ok := md.Get("x-request-id")
if !ok { if !ok {
t.Fatalf("failed to get x-request-id") t.Fatalf("failed to get x-request-id")
} else if v != "12345" { } else if v != "12345" {
t.Fatalf("invalid metadata value: %s != %s", "12345", v) t.Fatalf("invalid metadata value: %s != %s", "12345", v)
} }
v, ok = Get(ctx, "X-Request-Id") v, ok = md.Get("X-Request-Id")
if !ok { if !ok {
t.Fatalf("failed to get x-request-id") t.Fatalf("failed to get x-request-id")
} else if v != "12345" { } else if v != "12345" {
t.Fatalf("invalid metadata value: %s != %s", "12345", v) t.Fatalf("invalid metadata value: %s != %s", "12345", v)
} }
v, ok = Get(ctx, "X-Request-ID") v, ok = md.Get("X-Request-ID")
if !ok { if !ok {
t.Fatalf("failed to get x-request-id") t.Fatalf("failed to get x-request-id")
} else if v != "12345" { } else if v != "12345" {
@ -61,9 +60,11 @@ func TestMedataCanonicalKey(t *testing.T) {
} }
func TestMetadataSet(t *testing.T) { func TestMetadataSet(t *testing.T) {
ctx := Set(context.TODO(), "Key", "val") md := New(1)
val, ok := Get(ctx, "Key") md.Set("Key", "val")
val, ok := md.Get("Key")
if !ok { if !ok {
t.Fatal("key Key not found") t.Fatal("key Key not found")
} }
@ -78,15 +79,8 @@ func TestMetadataDelete(t *testing.T) {
"Baz": "empty", "Baz": "empty",
} }
ctx := NewContext(context.TODO(), md) md.Del("Baz")
ctx = Del(ctx, "Baz") _, ok := md.Get("Baz")
emd, ok := FromContext(ctx)
if !ok {
t.Fatal("key Key not found")
}
_, ok = emd["Baz"]
if ok { if ok {
t.Fatal("key Baz not deleted") t.Fatal("key Baz not deleted")
} }
@ -137,42 +131,3 @@ func TestMetadataContext(t *testing.T) {
t.Errorf("Expected metadata length 1 got %d", i) t.Errorf("Expected metadata length 1 got %d", i)
} }
} }
func TestMergeContext(t *testing.T) {
type args struct {
existing Metadata
append Metadata
overwrite bool
}
tests := []struct {
name string
args args
want Metadata
}{
{
name: "matching key, overwrite false",
args: args{
existing: Metadata{"Foo": "bar", "Sumo": "demo"},
append: Metadata{"Sumo": "demo2"},
overwrite: false,
},
want: Metadata{"Foo": "bar", "Sumo": "demo"},
},
{
name: "matching key, overwrite true",
args: args{
existing: Metadata{"Foo": "bar", "Sumo": "demo"},
append: Metadata{"Sumo": "demo2"},
overwrite: true,
},
want: Metadata{"Foo": "bar", "Sumo": "demo2"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got, _ := FromContext(MergeContext(NewContext(context.TODO(), tt.args.existing), tt.args.append, tt.args.overwrite)); !reflect.DeepEqual(got, tt.want) {
t.Errorf("MergeContext() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -14,11 +14,12 @@ const (
// FromContext returns a span from context // FromContext returns a span from context
func FromContext(ctx context.Context) (traceID string, parentSpanID string, isFound bool) { func FromContext(ctx context.Context) (traceID string, parentSpanID string, isFound bool) {
if ctx == nil { md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return "", "", false return "", "", false
} }
traceID, traceOk := metadata.Get(ctx, traceIDKey) traceID, traceOk := md.Get(traceIDKey)
microID, microOk := metadata.Get(ctx, "Micro-Id") microID, microOk := md.Get("Micro-Id")
if !traceOk && !microOk { if !traceOk && !microOk {
isFound = false isFound = false
return return
@ -26,17 +27,17 @@ func FromContext(ctx context.Context) (traceID string, parentSpanID string, isFo
if !traceOk { if !traceOk {
traceID = microID traceID = microID
} }
parentSpanID, ok := metadata.Get(ctx, spanIDKey) parentSpanID, ok = md.Get(spanIDKey)
return traceID, parentSpanID, ok return traceID, parentSpanID, ok
} }
// NewContext saves the trace and span ids in the context // NewContext saves the trace and span ids in the context
func NewContext(ctx context.Context, traceID, parentSpanID string) context.Context { func NewContext(ctx context.Context, traceID, parentSpanID string) context.Context {
if ctx == nil { md, ok := metadata.FromContext(ctx)
ctx = context.Background() if !ok {
md = metadata.New(2)
} }
md := metadata.New(2)
md.Set(traceIDKey, traceID) md.Set(traceIDKey, traceID)
md.Set(spanIDKey, parentSpanID) md.Set(spanIDKey, parentSpanID)
return metadata.MergeContext(ctx, md, true) return metadata.NewContext(ctx, md)
} }

View File

@ -10,10 +10,9 @@ import (
func FromRequest(r *http.Request) context.Context { func FromRequest(r *http.Request) context.Context {
ctx := r.Context() ctx := r.Context()
md, ok := metadata.FromContext(ctx) md, ok := metadata.FromIncomingContext(ctx)
if !ok { if !ok {
// create needed map with specific len md = metadata.New(len(r.Header) + 2)
md = make(metadata.Metadata, len(r.Header)+2)
} }
for key, val := range r.Header { for key, val := range r.Header {
md.Set(key, strings.Join(val, ",")) md.Set(key, strings.Join(val, ","))
@ -22,5 +21,5 @@ func FromRequest(r *http.Request) context.Context {
md["Host"] = r.Host md["Host"] = r.Host
// pass http method // pass http method
md["Method"] = r.Method md["Method"] = r.Method
return metadata.NewContext(ctx, md) return metadata.NewIncomingContext(ctx, md)
} }

View File

@ -28,7 +28,7 @@ func TestRequestToContext(t *testing.T) {
for _, d := range testData { for _, d := range testData {
ctx := FromRequest(d.request) ctx := FromRequest(d.request)
md, ok := metadata.FromContext(ctx) md, ok := metadata.FromIncomingContext(ctx)
if !ok { if !ok {
t.Fatalf("Expected metadata for request %+v", d.request) t.Fatalf("Expected metadata for request %+v", d.request)
} }