Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions internal/status/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,11 @@ func IsRestrictedControlPlaneCode(s *Status) bool {
}
return false
}

// RawStatusProto returns the internal protobuf message for use by gRPC itself.
func RawStatusProto(s *Status) *spb.Status {
if s == nil {
return nil
}
return s.s
}
37 changes: 37 additions & 0 deletions internal/status/status_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
*
* Copyright 2025 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package status

import (
"testing"

"google.golang.org/grpc/codes"
)

func TestRawStatusProto(t *testing.T) {
spb := RawStatusProto(nil)
if spb != nil {
t.Errorf("RawStatusProto(nil) must return nil (was %v)", spb)
}
s := New(codes.Internal, "test internal error")
spb = RawStatusProto(s)
if spb != s.s {
t.Errorf("RawStatusProto(s) must return s.s=%p (was %p)", s.s, spb)
}
}
5 changes: 3 additions & 2 deletions internal/transport/http2_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"google.golang.org/grpc/internal/grpclog"
"google.golang.org/grpc/internal/grpcutil"
"google.golang.org/grpc/internal/pretty"
istatus "google.golang.org/grpc/internal/status"
"google.golang.org/grpc/internal/syscall"
"google.golang.org/grpc/mem"
"google.golang.org/protobuf/proto"
Expand Down Expand Up @@ -1055,7 +1056,7 @@ func (t *http2Server) writeHeaderLocked(s *ServerStream) error {
return nil
}

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

if p := st.Proto(); p != nil && len(p.Details) > 0 {
if p := istatus.RawStatusProto(st); len(p.GetDetails()) > 0 {
// Do not use the user's grpc-status-details-bin (if present) if we are
// even attempting to set our own.
delete(s.trailer, grpcStatusDetailsBinHeader)
Expand Down
3 changes: 3 additions & 0 deletions status/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ func (s) TestStatus_ErrorDetails(t *testing.T) {
t.Fatalf("(%v).WithDetails(%+v) failed: %v", str(s), tc.details, err)
}
details := s.Details()
if len(details) != len(tc.details) {
t.Fatalf("len(s.Details()) = %v, want = %v.", len(details), len(tc.details))
}
for i := range details {
if !proto.Equal(details[i].(protoreflect.ProtoMessage), tc.details[i].(protoreflect.ProtoMessage)) {
t.Fatalf("(%v).Details()[%d] = %+v, want %+v", str(s), i, details[i], tc.details[i])
Expand Down