@@ -191,6 +191,7 @@ pub fn grpc_error_response(status: GrpcStatus) -> http::Response<GrpcBody> {
191191 . status ( 200 )
192192 . header ( "content-type" , "application/grpc+proto" )
193193 . header ( "grpc-accept-encoding" , "identity" )
194+ . header ( "content-length" , "0" )
194195 . header ( "grpc-status" , status. code . to_string ( ) ) ;
195196 if !status. message . is_empty ( ) {
196197 let encoded = percent_encode ( & status. message ) ;
@@ -203,12 +204,15 @@ pub fn grpc_error_response(status: GrpcStatus) -> http::Response<GrpcBody> {
203204
204205/// Build an HTTP 200 response with gRPC content-type and the given body.
205206pub fn grpc_response ( body : GrpcBody ) -> http:: Response < GrpcBody > {
206- http:: Response :: builder ( )
207+ let mut builder = http:: Response :: builder ( )
207208 . status ( 200 )
208209 . header ( "content-type" , "application/grpc+proto" )
209- . header ( "grpc-accept-encoding" , "identity" )
210- . body ( body)
211- . unwrap ( )
210+ . header ( "grpc-accept-encoding" , "identity" ) ;
211+ if let GrpcBody :: Unary { data, .. } = & body {
212+ let len = data. as_ref ( ) . map_or ( 0 , Bytes :: len) ;
213+ builder = builder. header ( "content-length" , len. to_string ( ) ) ;
214+ }
215+ builder. body ( body) . unwrap ( )
212216}
213217
214218/// Validate that the request looks like a gRPC call.
@@ -322,6 +326,30 @@ mod tests {
322326 assert ! ( decoded. is_empty( ) ) ;
323327 }
324328
329+ #[ test]
330+ fn test_grpc_response_sets_unary_content_length ( ) {
331+ let data = encode_grpc_frame ( b"hello" ) ;
332+ let expected_len = data. len ( ) . to_string ( ) ;
333+ let response = grpc_response ( GrpcBody :: Unary { data : Some ( data) , trailers_sent : false } ) ;
334+
335+ assert_eq ! ( response. headers( ) . get( "content-length" ) . unwrap( ) , expected_len. as_str( ) ) ;
336+ }
337+
338+ #[ test]
339+ fn test_grpc_response_omits_stream_content_length ( ) {
340+ let ( _tx, rx) = tokio:: sync:: mpsc:: channel ( 1 ) ;
341+ let response = grpc_response ( GrpcBody :: Stream { rx, done : false } ) ;
342+
343+ assert ! ( response. headers( ) . get( "content-length" ) . is_none( ) ) ;
344+ }
345+
346+ #[ test]
347+ fn test_grpc_error_response_sets_zero_content_length ( ) {
348+ let response = grpc_error_response ( GrpcStatus :: new ( GRPC_STATUS_INVALID_ARGUMENT , "bad" ) ) ;
349+
350+ assert_eq ! ( response. headers( ) . get( "content-length" ) . unwrap( ) , "0" ) ;
351+ }
352+
325353 #[ test]
326354 fn test_decode_too_short ( ) {
327355 assert ! ( decode_grpc_body( & [ 0 , 0 , 0 ] ) . is_err( ) ) ;
0 commit comments