client: fix ForceCodec to set content-type header appropriately (#4401)
This commit is contained in:
Родитель
81b8cca6a9
Коммит
62adda2ece
19
rpc_util.go
19
rpc_util.go
|
@ -429,9 +429,10 @@ func (o ContentSubtypeCallOption) before(c *callInfo) error {
|
|||
}
|
||||
func (o ContentSubtypeCallOption) after(c *callInfo, attempt *csAttempt) {}
|
||||
|
||||
// ForceCodec returns a CallOption that will set codec to be
|
||||
// used for all request and response messages for a call. The result of calling
|
||||
// Name() will be used as the content-subtype in a case-insensitive manner.
|
||||
// ForceCodec returns a CallOption that will set codec to be used for all
|
||||
// request and response messages for a call. The result of calling Name() will
|
||||
// be used as the content-subtype after converting to lowercase, unless
|
||||
// CallContentSubtype is also used.
|
||||
//
|
||||
// See Content-Type on
|
||||
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for
|
||||
|
@ -853,7 +854,17 @@ func toRPCErr(err error) error {
|
|||
// setCallInfoCodec should only be called after CallOptions have been applied.
|
||||
func setCallInfoCodec(c *callInfo) error {
|
||||
if c.codec != nil {
|
||||
// codec was already set by a CallOption; use it.
|
||||
// codec was already set by a CallOption; use it, but set the content
|
||||
// subtype if it is not set.
|
||||
if c.contentSubtype == "" {
|
||||
// c.codec is a baseCodec to hide the difference between grpc.Codec and
|
||||
// encoding.Codec (Name vs. String method name). We only support
|
||||
// setting content subtype from encoding.Codec to avoid a behavior
|
||||
// change with the deprecated version.
|
||||
if ec, ok := c.codec.(encoding.Codec); ok {
|
||||
c.contentSubtype = strings.ToLower(ec.Name())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -5293,7 +5293,7 @@ func (s) TestGRPCMethod(t *testing.T) {
|
|||
}
|
||||
defer ss.Stop()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
|
||||
if _, err := ss.Client.EmptyCall(ctx, &testpb.Empty{}); err != nil {
|
||||
|
@ -5305,6 +5305,55 @@ func (s) TestGRPCMethod(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// renameProtoCodec is an encoding.Codec wrapper that allows customizing the
|
||||
// Name() of another codec.
|
||||
type renameProtoCodec struct {
|
||||
encoding.Codec
|
||||
name string
|
||||
}
|
||||
|
||||
func (r *renameProtoCodec) Name() string { return r.name }
|
||||
|
||||
// TestForceCodecName confirms that the ForceCodec call option sets the subtype
|
||||
// in the content-type header according to the Name() of the codec provided.
|
||||
func (s) TestForceCodecName(t *testing.T) {
|
||||
wantContentTypeCh := make(chan []string, 1)
|
||||
defer close(wantContentTypeCh)
|
||||
|
||||
ss := &stubserver.StubServer{
|
||||
EmptyCallF: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) {
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
return nil, status.Errorf(codes.Internal, "no metadata in context")
|
||||
}
|
||||
if got, want := md["content-type"], <-wantContentTypeCh; !reflect.DeepEqual(got, want) {
|
||||
return nil, status.Errorf(codes.Internal, "got content-type=%q; want [%q]", got, want)
|
||||
}
|
||||
return &testpb.Empty{}, nil
|
||||
},
|
||||
}
|
||||
if err := ss.Start([]grpc.ServerOption{grpc.ForceServerCodec(encoding.GetCodec("proto"))}); err != nil {
|
||||
t.Fatalf("Error starting endpoint server: %v", err)
|
||||
}
|
||||
defer ss.Stop()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
|
||||
codec := &renameProtoCodec{Codec: encoding.GetCodec("proto"), name: "some-test-name"}
|
||||
wantContentTypeCh <- []string{"application/grpc+some-test-name"}
|
||||
if _, err := ss.Client.EmptyCall(ctx, &testpb.Empty{}, grpc.ForceCodec(codec)); err != nil {
|
||||
t.Fatalf("ss.Client.EmptyCall(_, _) = _, %v; want _, nil", err)
|
||||
}
|
||||
|
||||
// Confirm the name is converted to lowercase before transmitting.
|
||||
codec.name = "aNoTHeRNaME"
|
||||
wantContentTypeCh <- []string{"application/grpc+anothername"}
|
||||
if _, err := ss.Client.EmptyCall(ctx, &testpb.Empty{}, grpc.ForceCodec(codec)); err != nil {
|
||||
t.Fatalf("ss.Client.EmptyCall(_, _) = _, %v; want _, nil", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s) TestForceServerCodec(t *testing.T) {
|
||||
ss := &stubserver.StubServer{
|
||||
EmptyCallF: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) {
|
||||
|
@ -5317,7 +5366,7 @@ func (s) TestForceServerCodec(t *testing.T) {
|
|||
}
|
||||
defer ss.Stop()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
|
||||
defer cancel()
|
||||
|
||||
if _, err := ss.Client.EmptyCall(ctx, &testpb.Empty{}); err != nil {
|
||||
|
|
Загрузка…
Ссылка в новой задаче