Skip to content

Commit 2d3f20d

Browse files
evanjvinothkumarr227
authored andcommitted
transport: skip Status.Proto() without details in writeStatus (grpc#8282)
1 parent 22cf9e1 commit 2d3f20d

File tree

4 files changed

+55
-3
lines changed

4 files changed

+55
-3
lines changed

internal/status/status.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,11 @@ func IsRestrictedControlPlaneCode(s *Status) bool {
236236
}
237237
return false
238238
}
239+
240+
// RawStatusProto returns the internal protobuf message for use by gRPC itself.
241+
func RawStatusProto(s *Status) *spb.Status {
242+
if s == nil {
243+
return nil
244+
}
245+
return s.s
246+
}

internal/status/status_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
*
3+
* Copyright 2025 gRPC authors.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package status_test
20+
21+
import (
22+
"testing"
23+
24+
"google.golang.org/grpc/codes"
25+
"google.golang.org/grpc/internal/status"
26+
)
27+
28+
func TestRawStatusProto(t *testing.T) {
29+
spb := status.RawStatusProto(nil)
30+
if spb != nil {
31+
t.Errorf("RawStatusProto(nil) = %v; must return nil", spb)
32+
}
33+
s := status.New(codes.Internal, "test internal error")
34+
spb1 := status.RawStatusProto(s)
35+
spb2 := status.RawStatusProto(s)
36+
// spb1 and spb2 should be the same pointer: no copies
37+
if spb1 != spb2 {
38+
t.Errorf("RawStatusProto(s)=%p then %p; must return the same pointer", spb1, spb2)
39+
}
40+
}

internal/transport/http2_server.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"google.golang.org/grpc/internal/grpclog"
4040
"google.golang.org/grpc/internal/grpcutil"
4141
"google.golang.org/grpc/internal/pretty"
42+
istatus "google.golang.org/grpc/internal/status"
4243
"google.golang.org/grpc/internal/syscall"
4344
"google.golang.org/grpc/mem"
4445
"google.golang.org/protobuf/proto"
@@ -1059,7 +1060,7 @@ func (t *http2Server) writeHeaderLocked(s *ServerStream) error {
10591060
return nil
10601061
}
10611062

1062-
// WriteStatus sends stream status to the client and terminates the stream.
1063+
// writeStatus sends stream status to the client and terminates the stream.
10631064
// There is no further I/O operations being able to perform on this stream.
10641065
// TODO(zhaoq): Now it indicates the end of entire stream. Revisit if early
10651066
// OK is adopted.
@@ -1087,7 +1088,7 @@ func (t *http2Server) writeStatus(s *ServerStream, st *status.Status) error {
10871088
headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-status", Value: strconv.Itoa(int(st.Code()))})
10881089
headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-message", Value: encodeGrpcMessage(st.Message())})
10891090

1090-
if p := st.Proto(); p != nil && len(p.Details) > 0 {
1091+
if p := istatus.RawStatusProto(st); len(p.GetDetails()) > 0 {
10911092
// Do not use the user's grpc-status-details-bin (if present) if we are
10921093
// even attempting to set our own.
10931094
delete(s.trailer, grpcStatusDetailsBinHeader)

status/status_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,9 @@ func (s) TestStatus_ErrorDetails(t *testing.T) {
354354
t.Fatalf("(%v).WithDetails(%+v) failed: %v", str(s), tc.details, err)
355355
}
356356
details := s.Details()
357+
if len(details) != len(tc.details) {
358+
t.Fatalf("len(s.Details()) = %d, want = %d.", len(details), len(tc.details))
359+
}
357360
for i := range details {
358361
if !proto.Equal(details[i].(protoreflect.ProtoMessage), tc.details[i].(protoreflect.ProtoMessage)) {
359362
t.Fatalf("(%v).Details()[%d] = %+v, want %+v", str(s), i, details[i], tc.details[i])
@@ -420,7 +423,7 @@ func (s) TestStatus_ErrorDetails_Fail(t *testing.T) {
420423
for _, tc := range tests {
421424
details := tc.s.Details()
422425
if len(details) != len(tc.want) {
423-
t.Fatalf("len(s.Details()) = %v, want = %v.", len(details), len(tc.want))
426+
t.Fatalf("len(s.Details()) = %d, want = %d.", len(details), len(tc.want))
424427
}
425428
for i, d := range details {
426429
// s.Details can either contain an error or a proto message. We

0 commit comments

Comments
 (0)