@ -304,8 +304,8 @@ func doServiceAccountCreds(tc testpb.TestServiceClient) {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
testMetadata = metadata.MD{
|
testMetadata = metadata.MD{
|
||||||
"key1": "value1",
|
"key1": []string{"value1"},
|
||||||
"key2": "value2",
|
"key2": []string{"value2"},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ func encodeKeyValue(k, v string) (string, string) {
|
|||||||
if isASCII(v) {
|
if isASCII(v) {
|
||||||
return k, v
|
return k, v
|
||||||
}
|
}
|
||||||
key := k + binHdrSuffix
|
key := strings.ToLower(k + binHdrSuffix)
|
||||||
val := base64.StdEncoding.EncodeToString([]byte(v))
|
val := base64.StdEncoding.EncodeToString([]byte(v))
|
||||||
return key, string(val)
|
return key, string(val)
|
||||||
}
|
}
|
||||||
@ -85,14 +85,14 @@ func DecodeKeyValue(k, v string) (string, string, error) {
|
|||||||
|
|
||||||
// MD is a mapping from metadata keys to values. Users should use the following
|
// MD is a mapping from metadata keys to values. Users should use the following
|
||||||
// two convenience functions New and Pairs to generate MD.
|
// two convenience functions New and Pairs to generate MD.
|
||||||
type MD map[string]string
|
type MD map[string][]string
|
||||||
|
|
||||||
// New creates a MD from given key-value map.
|
// New creates a MD from given key-value map.
|
||||||
func New(m map[string]string) MD {
|
func New(m map[string]string) MD {
|
||||||
md := MD{}
|
md := MD{}
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
key, val := encodeKeyValue(k, v)
|
key, val := encodeKeyValue(k, v)
|
||||||
md[key] = val
|
md[key] = append(md[key], val)
|
||||||
}
|
}
|
||||||
return md
|
return md
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ func Pairs(kv ...string) MD {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
key, val := encodeKeyValue(k, s)
|
key, val := encodeKeyValue(k, s)
|
||||||
md[key] = val
|
md[key] = append(md[key], val)
|
||||||
}
|
}
|
||||||
return md
|
return md
|
||||||
}
|
}
|
||||||
@ -125,7 +125,9 @@ func (md MD) Len() int {
|
|||||||
func (md MD) Copy() MD {
|
func (md MD) Copy() MD {
|
||||||
out := MD{}
|
out := MD{}
|
||||||
for k, v := range md {
|
for k, v := range md {
|
||||||
out[k] = v
|
for _, i := range v {
|
||||||
|
out[k] = append(out[k], i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -59,8 +59,8 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
testMetadata = metadata.MD{
|
testMetadata = metadata.MD{
|
||||||
"key1": "value1",
|
"key1": []string{"value1"},
|
||||||
"key2": "value2",
|
"key2": []string{"value2"},
|
||||||
}
|
}
|
||||||
testAppUA = "myApp1/1.0 myApp2/0.9"
|
testAppUA = "myApp1/1.0 myApp2/0.9"
|
||||||
)
|
)
|
||||||
@ -75,7 +75,11 @@ func (s *testServer) EmptyCall(ctx context.Context, in *testpb.Empty) (*testpb.E
|
|||||||
if _, ok := md["user-agent"]; !ok {
|
if _, ok := md["user-agent"]; !ok {
|
||||||
return nil, grpc.Errorf(codes.DataLoss, "got extra metadata")
|
return nil, grpc.Errorf(codes.DataLoss, "got extra metadata")
|
||||||
}
|
}
|
||||||
grpc.SendHeader(ctx, metadata.Pairs("ua", md["user-agent"]))
|
var str []string
|
||||||
|
for _, entry := range md["user-agent"] {
|
||||||
|
str = append(str, "ua", entry)
|
||||||
|
}
|
||||||
|
grpc.SendHeader(ctx, metadata.Pairs(str...))
|
||||||
}
|
}
|
||||||
return new(testpb.Empty), nil
|
return new(testpb.Empty), nil
|
||||||
}
|
}
|
||||||
@ -499,7 +503,7 @@ func testEmptyUnaryWithUserAgent(t *testing.T, e env) {
|
|||||||
if err != nil || !proto.Equal(&testpb.Empty{}, reply) {
|
if err != nil || !proto.Equal(&testpb.Empty{}, reply) {
|
||||||
t.Fatalf("TestService/EmptyCall(_, _) = %v, %v, want %v, <nil>", reply, err, &testpb.Empty{})
|
t.Fatalf("TestService/EmptyCall(_, _) = %v, %v, want %v, <nil>", reply, err, &testpb.Empty{})
|
||||||
}
|
}
|
||||||
if v, ok := header["ua"]; !ok || v != testAppUA {
|
if v, ok := header["ua"]; !ok || v[0] != testAppUA {
|
||||||
t.Fatalf("header[\"ua\"] = %q, %t, want %q, true", v, ok, testAppUA)
|
t.Fatalf("header[\"ua\"] = %q, %t, want %q, true", v, ok, testAppUA)
|
||||||
}
|
}
|
||||||
tearDown(s, cc)
|
tearDown(s, cc)
|
||||||
|
@ -298,7 +298,9 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (_ *Strea
|
|||||||
if md, ok := metadata.FromContext(ctx); ok {
|
if md, ok := metadata.FromContext(ctx); ok {
|
||||||
hasMD = true
|
hasMD = true
|
||||||
for k, v := range md {
|
for k, v := range md {
|
||||||
t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: v})
|
for _, entry := range v {
|
||||||
|
t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: entry})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
first := true
|
first := true
|
||||||
|
@ -440,7 +440,9 @@ func (t *http2Server) WriteHeader(s *Stream, md metadata.MD) error {
|
|||||||
t.hEnc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
|
t.hEnc.WriteField(hpack.HeaderField{Name: ":status", Value: "200"})
|
||||||
t.hEnc.WriteField(hpack.HeaderField{Name: "content-type", Value: "application/grpc"})
|
t.hEnc.WriteField(hpack.HeaderField{Name: "content-type", Value: "application/grpc"})
|
||||||
for k, v := range md {
|
for k, v := range md {
|
||||||
t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: v})
|
for _, entry := range v {
|
||||||
|
t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: entry})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := t.writeHeaders(s, t.hBuf, false); err != nil {
|
if err := t.writeHeaders(s, t.hBuf, false); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -473,7 +475,9 @@ func (t *http2Server) WriteStatus(s *Stream, statusCode codes.Code, statusDesc s
|
|||||||
t.hEnc.WriteField(hpack.HeaderField{Name: "grpc-message", Value: statusDesc})
|
t.hEnc.WriteField(hpack.HeaderField{Name: "grpc-message", Value: statusDesc})
|
||||||
// Attach the trailer metadata.
|
// Attach the trailer metadata.
|
||||||
for k, v := range s.trailer {
|
for k, v := range s.trailer {
|
||||||
t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: v})
|
for _, entry := range v {
|
||||||
|
t.hEnc.WriteField(hpack.HeaderField{Name: k, Value: entry})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := t.writeHeaders(s, t.hBuf, true); err != nil {
|
if err := t.writeHeaders(s, t.hBuf, true); err != nil {
|
||||||
t.Close()
|
t.Close()
|
||||||
|
@ -100,7 +100,7 @@ type decodeState struct {
|
|||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
method string
|
method string
|
||||||
// key-value metadata map from the peer.
|
// key-value metadata map from the peer.
|
||||||
mdata map[string]string
|
mdata map[string][]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// An hpackDecoder decodes HTTP2 headers which may span multiple frames.
|
// An hpackDecoder decodes HTTP2 headers which may span multiple frames.
|
||||||
@ -173,14 +173,14 @@ func newHPACKDecoder() *hpackDecoder {
|
|||||||
f.Value = f.Value[:i]
|
f.Value = f.Value[:i]
|
||||||
}
|
}
|
||||||
if d.state.mdata == nil {
|
if d.state.mdata == nil {
|
||||||
d.state.mdata = make(map[string]string)
|
d.state.mdata = make(map[string][]string)
|
||||||
}
|
}
|
||||||
k, v, err := metadata.DecodeKeyValue(f.Name, f.Value)
|
k, v, err := metadata.DecodeKeyValue(f.Name, f.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
grpclog.Printf("Failed to decode (%q, %q): %v", f.Name, f.Value, err)
|
grpclog.Printf("Failed to decode (%q, %q): %v", f.Name, f.Value, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
d.state.mdata[k] = v
|
d.state.mdata[k] = append(d.state.mdata[k], v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user