Rename headers to metadata
Signed-off-by: Maksym Pavlenko <makpav@amazon.com>
This commit is contained in:
parent
5926a92b70
commit
04523b9d2c
@ -99,8 +99,8 @@ func (c *Client) Call(ctx context.Context, service, method string, req, resp int
|
|||||||
cresp = &Response{}
|
cresp = &Response{}
|
||||||
)
|
)
|
||||||
|
|
||||||
if headers, ok := GetHeaders(ctx); ok {
|
if metadata, ok := GetMetadata(ctx); ok {
|
||||||
creq.Headers = headers
|
creq.Metadata = metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
if dl, ok := ctx.Deadline(); ok {
|
if dl, ok := ctx.Deadline(); ok {
|
||||||
|
86
header.go
86
header.go
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ttrpc
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
// Headers represents the key-value pairs (similar to http.Header) to be passed to ttrpc server from a client.
|
|
||||||
type Headers map[string]StringList
|
|
||||||
|
|
||||||
// Get returns the headers for a given key when they exist.
|
|
||||||
// If there are no headers, a nil slice and false are returned.
|
|
||||||
func (h Headers) Get(key string) ([]string, bool) {
|
|
||||||
list, ok := h[key]
|
|
||||||
if !ok || len(list.List) == 0 {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return list.List, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set sets the provided values for a given key.
|
|
||||||
// The values will overwrite any existing values.
|
|
||||||
// If no values provided, a key will be deleted.
|
|
||||||
func (h Headers) Set(key string, values ...string) {
|
|
||||||
if len(values) == 0 {
|
|
||||||
delete(h, key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
h[key] = StringList{List: values}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append appends additional values to the given key.
|
|
||||||
func (h Headers) Append(key string, values ...string) {
|
|
||||||
if len(values) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
list, ok := h[key]
|
|
||||||
if ok {
|
|
||||||
h.Set(key, append(list.List, values...)...)
|
|
||||||
} else {
|
|
||||||
h.Set(key, values...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type headerKey struct{}
|
|
||||||
|
|
||||||
// GetHeaders retrieves headers from context.Context (previously attached with WithHeaders)
|
|
||||||
func GetHeaders(ctx context.Context) (Headers, bool) {
|
|
||||||
headers, ok := ctx.Value(headerKey{}).(Headers)
|
|
||||||
return headers, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHeader gets a specific header value by name from context.Context
|
|
||||||
func GetHeader(ctx context.Context, name string) (string, bool) {
|
|
||||||
headers, ok := GetHeaders(ctx)
|
|
||||||
if !ok {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
if list, ok := headers.Get(name); ok {
|
|
||||||
return list[0], true
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithHeaders attaches headers map to a context.Context
|
|
||||||
func WithHeaders(ctx context.Context, headers Headers) context.Context {
|
|
||||||
return context.WithValue(ctx, headerKey{}, headers)
|
|
||||||
}
|
|
108
header_test.go
108
header_test.go
@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright The containerd Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ttrpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHeaders_Get(t *testing.T) {
|
|
||||||
hdr := make(Headers)
|
|
||||||
hdr.Set("foo", "1", "2")
|
|
||||||
|
|
||||||
if list, ok := hdr.Get("foo"); !ok {
|
|
||||||
t.Error("key not found")
|
|
||||||
} else if len(list) != 2 {
|
|
||||||
t.Errorf("unexpected number of values: %d", len(list))
|
|
||||||
} else if list[0] != "1" {
|
|
||||||
t.Errorf("invalid header value at 0: %s", list[0])
|
|
||||||
} else if list[1] != "2" {
|
|
||||||
t.Errorf("invalid header value at 1: %s", list[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHeaders_GetInvalidKey(t *testing.T) {
|
|
||||||
hdr := make(Headers)
|
|
||||||
hdr.Set("foo", "1", "2")
|
|
||||||
|
|
||||||
if _, ok := hdr.Get("invalid"); ok {
|
|
||||||
t.Error("found invalid key")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHeaders_Unset(t *testing.T) {
|
|
||||||
hdr := make(Headers)
|
|
||||||
hdr.Set("foo", "1", "2")
|
|
||||||
hdr.Set("foo")
|
|
||||||
|
|
||||||
if _, ok := hdr.Get("foo"); ok {
|
|
||||||
t.Error("key not deleted")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHeader_Replace(t *testing.T) {
|
|
||||||
hdr := make(Headers)
|
|
||||||
hdr.Set("foo", "1", "2")
|
|
||||||
hdr.Set("foo", "3", "4")
|
|
||||||
|
|
||||||
if list, ok := hdr.Get("foo"); !ok {
|
|
||||||
t.Error("key not found")
|
|
||||||
} else if len(list) != 2 {
|
|
||||||
t.Errorf("unexpected number of values: %d", len(list))
|
|
||||||
} else if list[0] != "3" {
|
|
||||||
t.Errorf("invalid header value at 0: %s", list[0])
|
|
||||||
} else if list[1] != "4" {
|
|
||||||
t.Errorf("invalid header value at 1: %s", list[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHeaders_Append(t *testing.T) {
|
|
||||||
hdr := make(Headers)
|
|
||||||
hdr.Set("foo", "1")
|
|
||||||
hdr.Append("foo", "2")
|
|
||||||
hdr.Append("bar", "3")
|
|
||||||
|
|
||||||
if list, ok := hdr.Get("foo"); !ok {
|
|
||||||
t.Error("key not found")
|
|
||||||
} else if len(list) != 2 {
|
|
||||||
t.Errorf("unexpected number of values: %d", len(list))
|
|
||||||
} else if list[0] != "1" {
|
|
||||||
t.Errorf("invalid header value at 0: %s", list[0])
|
|
||||||
} else if list[1] != "2" {
|
|
||||||
t.Errorf("invalid header value at 1: %s", list[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
if list, ok := hdr.Get("bar"); !ok {
|
|
||||||
t.Error("key not found")
|
|
||||||
} else if list[0] != "3" {
|
|
||||||
t.Errorf("invalid value: %s", list[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHeaders_Context(t *testing.T) {
|
|
||||||
hdr := make(Headers)
|
|
||||||
hdr.Set("foo", "bar")
|
|
||||||
|
|
||||||
ctx := WithHeaders(context.Background(), hdr)
|
|
||||||
|
|
||||||
if bar, ok := GetHeader(ctx, "foo"); !ok {
|
|
||||||
t.Error("header not found")
|
|
||||||
} else if bar != "bar" {
|
|
||||||
t.Errorf("invalid header value: %q", bar)
|
|
||||||
}
|
|
||||||
}
|
|
86
metadata.go
Normal file
86
metadata.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ttrpc
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// Metadata represents the key-value pairs (similar to http.Header) to be passed to ttrpc server from a client.
|
||||||
|
type Metadata map[string]StringList
|
||||||
|
|
||||||
|
// Get returns the metadata for a given key when they exist.
|
||||||
|
// If there is no metadata, a nil slice and false are returned.
|
||||||
|
func (m Metadata) Get(key string) ([]string, bool) {
|
||||||
|
list, ok := m[key]
|
||||||
|
if !ok || len(list.List) == 0 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.List, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the provided values for a given key.
|
||||||
|
// The values will overwrite any existing values.
|
||||||
|
// If no values provided, a key will be deleted.
|
||||||
|
func (m Metadata) Set(key string, values ...string) {
|
||||||
|
if len(values) == 0 {
|
||||||
|
delete(m, key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m[key] = StringList{List: values}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append appends additional values to the given key.
|
||||||
|
func (m Metadata) Append(key string, values ...string) {
|
||||||
|
if len(values) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
list, ok := m[key]
|
||||||
|
if ok {
|
||||||
|
m.Set(key, append(list.List, values...)...)
|
||||||
|
} else {
|
||||||
|
m.Set(key, values...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type metadataKey struct{}
|
||||||
|
|
||||||
|
// GetMetadata retrieves metadata from context.Context (previously attached with WithMetadata)
|
||||||
|
func GetMetadata(ctx context.Context) (Metadata, bool) {
|
||||||
|
metadata, ok := ctx.Value(metadataKey{}).(Metadata)
|
||||||
|
return metadata, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetadataValue gets a specific metadata value by name from context.Context
|
||||||
|
func GetMetadataValue(ctx context.Context, name string) (string, bool) {
|
||||||
|
metadata, ok := GetMetadata(ctx)
|
||||||
|
if !ok {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
if list, ok := metadata.Get(name); ok {
|
||||||
|
return list[0], true
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMetadata attaches metadata map to a context.Context
|
||||||
|
func WithMetadata(ctx context.Context, headers Metadata) context.Context {
|
||||||
|
return context.WithValue(ctx, metadataKey{}, headers)
|
||||||
|
}
|
108
metadata_test.go
Normal file
108
metadata_test.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
Copyright The containerd Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ttrpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMetadata_Get(t *testing.T) {
|
||||||
|
metadata := make(Metadata)
|
||||||
|
metadata.Set("foo", "1", "2")
|
||||||
|
|
||||||
|
if list, ok := metadata.Get("foo"); !ok {
|
||||||
|
t.Error("key not found")
|
||||||
|
} else if len(list) != 2 {
|
||||||
|
t.Errorf("unexpected number of values: %d", len(list))
|
||||||
|
} else if list[0] != "1" {
|
||||||
|
t.Errorf("invalid metadata value at 0: %s", list[0])
|
||||||
|
} else if list[1] != "2" {
|
||||||
|
t.Errorf("invalid metadata value at 1: %s", list[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMetadata_GetInvalidKey(t *testing.T) {
|
||||||
|
metadata := make(Metadata)
|
||||||
|
metadata.Set("foo", "1", "2")
|
||||||
|
|
||||||
|
if _, ok := metadata.Get("invalid"); ok {
|
||||||
|
t.Error("found invalid key")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMetadata_Unset(t *testing.T) {
|
||||||
|
metadata := make(Metadata)
|
||||||
|
metadata.Set("foo", "1", "2")
|
||||||
|
metadata.Set("foo")
|
||||||
|
|
||||||
|
if _, ok := metadata.Get("foo"); ok {
|
||||||
|
t.Error("key not deleted")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMetadata_Replace(t *testing.T) {
|
||||||
|
metadata := make(Metadata)
|
||||||
|
metadata.Set("foo", "1", "2")
|
||||||
|
metadata.Set("foo", "3", "4")
|
||||||
|
|
||||||
|
if list, ok := metadata.Get("foo"); !ok {
|
||||||
|
t.Error("key not found")
|
||||||
|
} else if len(list) != 2 {
|
||||||
|
t.Errorf("unexpected number of values: %d", len(list))
|
||||||
|
} else if list[0] != "3" {
|
||||||
|
t.Errorf("invalid metadata value at 0: %s", list[0])
|
||||||
|
} else if list[1] != "4" {
|
||||||
|
t.Errorf("invalid metadata value at 1: %s", list[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMetadata_Append(t *testing.T) {
|
||||||
|
metadata := make(Metadata)
|
||||||
|
metadata.Set("foo", "1")
|
||||||
|
metadata.Append("foo", "2")
|
||||||
|
metadata.Append("bar", "3")
|
||||||
|
|
||||||
|
if list, ok := metadata.Get("foo"); !ok {
|
||||||
|
t.Error("key not found")
|
||||||
|
} else if len(list) != 2 {
|
||||||
|
t.Errorf("unexpected number of values: %d", len(list))
|
||||||
|
} else if list[0] != "1" {
|
||||||
|
t.Errorf("invalid metadata value at 0: %s", list[0])
|
||||||
|
} else if list[1] != "2" {
|
||||||
|
t.Errorf("invalid metadata value at 1: %s", list[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if list, ok := metadata.Get("bar"); !ok {
|
||||||
|
t.Error("key not found")
|
||||||
|
} else if list[0] != "3" {
|
||||||
|
t.Errorf("invalid value: %s", list[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMetadata_Context(t *testing.T) {
|
||||||
|
metadata := make(Metadata)
|
||||||
|
metadata.Set("foo", "bar")
|
||||||
|
|
||||||
|
ctx := WithMetadata(context.Background(), metadata)
|
||||||
|
|
||||||
|
if bar, ok := GetMetadataValue(ctx, "foo"); !ok {
|
||||||
|
t.Error("metadata not found")
|
||||||
|
} else if bar != "bar" {
|
||||||
|
t.Errorf("invalid metadata value: %q", bar)
|
||||||
|
}
|
||||||
|
}
|
@ -466,8 +466,8 @@ func (c *serverConn) run(sctx context.Context) {
|
|||||||
var noopFunc = func() {}
|
var noopFunc = func() {}
|
||||||
|
|
||||||
func getRequestContext(ctx context.Context, req *Request) (retCtx context.Context, cancel func()) {
|
func getRequestContext(ctx context.Context, req *Request) (retCtx context.Context, cancel func()) {
|
||||||
if req.Headers != nil {
|
if req.Metadata != nil {
|
||||||
ctx = WithHeaders(ctx, req.Headers)
|
ctx = WithMetadata(ctx, req.Metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel = noopFunc
|
cancel = noopFunc
|
||||||
|
@ -61,7 +61,7 @@ func (tc *testingClient) Test(ctx context.Context, req *testPayload) (*testPaylo
|
|||||||
type testPayload struct {
|
type testPayload struct {
|
||||||
Foo string `protobuf:"bytes,1,opt,name=foo,proto3"`
|
Foo string `protobuf:"bytes,1,opt,name=foo,proto3"`
|
||||||
Deadline int64 `protobuf:"varint,2,opt,name=deadline,proto3"`
|
Deadline int64 `protobuf:"varint,2,opt,name=deadline,proto3"`
|
||||||
Hdr string `protobuf:"bytes,3,opt,name=hdr,proto3"`
|
Metadata string `protobuf:"bytes,3,opt,name=metadata,proto3"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *testPayload) Reset() { *r = testPayload{} }
|
func (r *testPayload) Reset() { *r = testPayload{} }
|
||||||
@ -77,8 +77,8 @@ func (s *testingServer) Test(ctx context.Context, req *testPayload) (*testPayloa
|
|||||||
tp.Deadline = dl.UnixNano()
|
tp.Deadline = dl.UnixNano()
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := GetHeader(ctx, "foo"); ok {
|
if v, ok := GetMetadataValue(ctx, "foo"); ok {
|
||||||
tp.Hdr = v
|
tp.Metadata = v
|
||||||
}
|
}
|
||||||
|
|
||||||
return tp, nil
|
return tp, nil
|
||||||
@ -546,7 +546,7 @@ func roundTrip(ctx context.Context, t *testing.T, client *testingClient, value s
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx = WithHeaders(ctx, Headers{"foo": makeStringList("bar")})
|
ctx = WithMetadata(ctx, Metadata{"foo": makeStringList("bar")})
|
||||||
|
|
||||||
resp, err := client.Test(ctx, tp)
|
resp, err := client.Test(ctx, tp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -555,7 +555,7 @@ func roundTrip(ctx context.Context, t *testing.T, client *testingClient, value s
|
|||||||
|
|
||||||
results <- callResult{
|
results <- callResult{
|
||||||
input: tp,
|
input: tp,
|
||||||
expected: &testPayload{Foo: strings.Repeat(tp.Foo, 2), Hdr: "bar"},
|
expected: &testPayload{Foo: strings.Repeat(tp.Foo, 2), Metadata: "bar"},
|
||||||
received: resp,
|
received: resp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
types.go
10
types.go
@ -23,11 +23,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Request struct {
|
type Request struct {
|
||||||
Service string `protobuf:"bytes,1,opt,name=service,proto3"`
|
Service string `protobuf:"bytes,1,opt,name=service,proto3"`
|
||||||
Method string `protobuf:"bytes,2,opt,name=method,proto3"`
|
Method string `protobuf:"bytes,2,opt,name=method,proto3"`
|
||||||
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3"`
|
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3"`
|
||||||
TimeoutNano int64 `protobuf:"varint,4,opt,name=timeout_nano,proto3"`
|
TimeoutNano int64 `protobuf:"varint,4,opt,name=timeout_nano,proto3"`
|
||||||
Headers Headers `protobuf:"bytes,5,opt,name=headers,proto3" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
Metadata Metadata `protobuf:"bytes,5,opt,name=metadata,proto3" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Request) Reset() { *r = Request{} }
|
func (r *Request) Reset() { *r = Request{} }
|
||||||
|
Loading…
Reference in New Issue
Block a user