mirror of https://github.com/grpc/grpc-go.git
				
				
				
			client: fix ForceCodec to set content-type header appropriately (#4401)
This commit is contained in:
		
							parent
							
								
									81b8cca6a9
								
							
						
					
					
						commit
						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) {}
 | 
					func (o ContentSubtypeCallOption) after(c *callInfo, attempt *csAttempt) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ForceCodec returns a CallOption that will set codec to be
 | 
					// ForceCodec returns a CallOption that will set codec to be used for all
 | 
				
			||||||
// used for all request and response messages for a call. The result of calling
 | 
					// request and response messages for a call. The result of calling Name() will
 | 
				
			||||||
// Name() will be used as the content-subtype in a case-insensitive manner.
 | 
					// be used as the content-subtype after converting to lowercase, unless
 | 
				
			||||||
 | 
					// CallContentSubtype is also used.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// See Content-Type on
 | 
					// See Content-Type on
 | 
				
			||||||
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for
 | 
					// 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.
 | 
					// setCallInfoCodec should only be called after CallOptions have been applied.
 | 
				
			||||||
func setCallInfoCodec(c *callInfo) error {
 | 
					func setCallInfoCodec(c *callInfo) error {
 | 
				
			||||||
	if c.codec != nil {
 | 
						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
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5293,7 +5293,7 @@ func (s) TestGRPCMethod(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer ss.Stop()
 | 
						defer ss.Stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
 | 
						ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
 | 
				
			||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err := ss.Client.EmptyCall(ctx, &testpb.Empty{}); err != nil {
 | 
						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) {
 | 
					func (s) TestForceServerCodec(t *testing.T) {
 | 
				
			||||||
	ss := &stubserver.StubServer{
 | 
						ss := &stubserver.StubServer{
 | 
				
			||||||
		EmptyCallF: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) {
 | 
							EmptyCallF: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) {
 | 
				
			||||||
| 
						 | 
					@ -5317,7 +5366,7 @@ func (s) TestForceServerCodec(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer ss.Stop()
 | 
						defer ss.Stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
 | 
						ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
 | 
				
			||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if _, err := ss.Client.EmptyCall(ctx, &testpb.Empty{}); err != nil {
 | 
						if _, err := ss.Client.EmptyCall(ctx, &testpb.Empty{}); err != nil {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue