change the metadata datastructure

This commit is contained in:
yangzhouhan
2015-08-10 16:06:27 -07:00
parent 95389ca819
commit 484e2d96e5
5 changed files with 30 additions and 15 deletions

View File

@ -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
} }

View File

@ -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,12 @@ 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"])) // kv := []string{"ua"}
// for _, entry := range md["user-agent"]{
// kv = append(kv,entry)
// }
// grpc.SendHeader(ctx, metadata.Pairs(kv))
grpc.SendHeader(ctx, metadata.Pairs("ua", md["user-agent"][0]))
} }
return new(testpb.Empty), nil return new(testpb.Empty), nil
} }
@ -499,7 +504,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)

View File

@ -294,9 +294,12 @@ 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
// Sends the headers in a single batch even when they span multiple frames. // Sends the headers in a single batch even when they span multiple frames.
for !endHeaders { for !endHeaders {

View File

@ -440,8 +440,11 @@ 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,8 +476,10 @@ 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()
return err return err

View File

@ -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)
} }
} }
}) })