Skip to content

Commit 9e1fc3e

Browse files
authored
Revert "status: fix/improve status handling (#6662)" (#6673)
1 parent 0772ed7 commit 9e1fc3e

File tree

9 files changed

+44
-270
lines changed

9 files changed

+44
-270
lines changed

internal/status/status.go

+1-37
Original file line numberDiff line numberDiff line change
@@ -43,45 +43,9 @@ type Status struct {
4343
s *spb.Status
4444
}
4545

46-
// NewWithProto returns a new status including details from statusProto. This
47-
// is meant to be used by the gRPC library only.
48-
func NewWithProto(code codes.Code, message string, statusProto []string) *Status {
49-
if len(statusProto) != 1 {
50-
// No grpc-status-details bin header, or multiple; just ignore.
51-
return &Status{s: &spb.Status{Code: normalizeCode(code), Message: message}}
52-
}
53-
st := &spb.Status{}
54-
if err := proto.Unmarshal([]byte(statusProto[0]), st); err != nil {
55-
// Probably not a google.rpc.Status proto; do not provide details.
56-
return &Status{s: &spb.Status{Code: normalizeCode(code), Message: message}}
57-
}
58-
if st.Code == int32(code) {
59-
// The codes match between the grpc-status header and the
60-
// grpc-status-details-bin header; use the full details proto.
61-
st.Code = normalizeCode(codes.Code(st.Code))
62-
return &Status{s: st}
63-
}
64-
return &Status{
65-
s: &spb.Status{
66-
Code: int32(codes.Internal),
67-
Message: fmt.Sprintf(
68-
"grpc-status-details-bin mismatch: grpc-status=%v, grpc-message=%q, grpc-status-details-bin=%+v",
69-
code, message, st,
70-
),
71-
},
72-
}
73-
}
74-
75-
func normalizeCode(c codes.Code) int32 {
76-
if c > 16 {
77-
return int32(codes.Unknown)
78-
}
79-
return int32(c)
80-
}
81-
8246
// New returns a Status representing c and msg.
8347
func New(c codes.Code, msg string) *Status {
84-
return &Status{s: &spb.Status{Code: normalizeCode(c), Message: msg}}
48+
return &Status{s: &spb.Status{Code: int32(c), Message: msg}}
8549
}
8650

8751
// Newf returns New(c, fmt.Sprintf(format, a...)).

internal/stubserver/stubserver.go

+10-45
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"testing"
2828
"time"
2929

30-
"golang.org/x/net/http2"
3130
"google.golang.org/grpc"
3231
"google.golang.org/grpc/connectivity"
3332
"google.golang.org/grpc/credentials/insecure"
@@ -111,7 +110,8 @@ func RegisterServiceServerOption(f func(*grpc.Server)) grpc.ServerOption {
111110
return &registerServiceServerOption{f: f}
112111
}
113112

114-
func (ss *StubServer) setupServer(sopts ...grpc.ServerOption) (net.Listener, error) {
113+
// StartServer only starts the server. It does not create a client to it.
114+
func (ss *StubServer) StartServer(sopts ...grpc.ServerOption) error {
115115
if ss.Network == "" {
116116
ss.Network = "tcp"
117117
}
@@ -127,59 +127,24 @@ func (ss *StubServer) setupServer(sopts ...grpc.ServerOption) (net.Listener, err
127127
var err error
128128
lis, err = net.Listen(ss.Network, ss.Address)
129129
if err != nil {
130-
return nil, fmt.Errorf("net.Listen(%q, %q) = %v", ss.Network, ss.Address, err)
130+
return fmt.Errorf("net.Listen(%q, %q) = %v", ss.Network, ss.Address, err)
131131
}
132132
}
133133
ss.Address = lis.Addr().String()
134+
ss.cleanups = append(ss.cleanups, func() { lis.Close() })
134135

135-
ss.S = grpc.NewServer(sopts...)
136+
s := grpc.NewServer(sopts...)
136137
for _, so := range sopts {
137138
switch x := so.(type) {
138139
case *registerServiceServerOption:
139-
x.f(ss.S)
140-
}
141-
}
142-
143-
testgrpc.RegisterTestServiceServer(ss.S, ss)
144-
ss.cleanups = append(ss.cleanups, ss.S.Stop)
145-
return lis, nil
146-
}
147-
148-
// StartHandlerServer only starts an HTTP server with a gRPC server as the
149-
// handler. It does not create a client to it. Cannot be used in a StubServer
150-
// that also used StartServer.
151-
func (ss *StubServer) StartHandlerServer(sopts ...grpc.ServerOption) error {
152-
lis, err := ss.setupServer(sopts...)
153-
if err != nil {
154-
return err
155-
}
156-
157-
go func() {
158-
hs := &http2.Server{}
159-
opts := &http2.ServeConnOpts{Handler: ss.S}
160-
for {
161-
conn, err := lis.Accept()
162-
if err != nil {
163-
return
164-
}
165-
hs.ServeConn(conn, opts)
140+
x.f(s)
166141
}
167-
}()
168-
ss.cleanups = append(ss.cleanups, func() { lis.Close() })
169-
170-
return nil
171-
}
172-
173-
// StartServer only starts the server. It does not create a client to it.
174-
// Cannot be used in a StubServer that also used StartHandlerServer.
175-
func (ss *StubServer) StartServer(sopts ...grpc.ServerOption) error {
176-
lis, err := ss.setupServer(sopts...)
177-
if err != nil {
178-
return err
179142
}
180143

181-
go ss.S.Serve(lis)
182-
144+
testgrpc.RegisterTestServiceServer(s, ss)
145+
go s.Serve(lis)
146+
ss.cleanups = append(ss.cleanups, s.Stop)
147+
ss.S = s
183148
return nil
184149
}
185150

internal/transport/handler_server.go

+4-7
Original file line numberDiff line numberDiff line change
@@ -220,20 +220,18 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro
220220
h.Set("Grpc-Message", encodeGrpcMessage(m))
221221
}
222222

223-
s.hdrMu.Lock()
224223
if p := st.Proto(); p != nil && len(p.Details) > 0 {
225-
delete(s.trailer, grpcStatusDetailsBinHeader)
226224
stBytes, err := proto.Marshal(p)
227225
if err != nil {
228226
// TODO: return error instead, when callers are able to handle it.
229227
panic(err)
230228
}
231229

232-
h.Set(grpcStatusDetailsBinHeader, encodeBinHeader(stBytes))
230+
h.Set("Grpc-Status-Details-Bin", encodeBinHeader(stBytes))
233231
}
234232

235-
if len(s.trailer) > 0 {
236-
for k, vv := range s.trailer {
233+
if md := s.Trailer(); len(md) > 0 {
234+
for k, vv := range md {
237235
// Clients don't tolerate reading restricted headers after some non restricted ones were sent.
238236
if isReservedHeader(k) {
239237
continue
@@ -245,7 +243,6 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro
245243
}
246244
}
247245
}
248-
s.hdrMu.Unlock()
249246
})
250247

251248
if err == nil { // transport has not been closed
@@ -290,7 +287,7 @@ func (ht *serverHandlerTransport) writeCommonHeaders(s *Stream) {
290287
}
291288

292289
// writeCustomHeaders sets custom headers set on the stream via SetHeader
293-
// on the first write call (Write, WriteHeader, or WriteStatus)
290+
// on the first write call (Write, WriteHeader, or WriteStatus).
294291
func (ht *serverHandlerTransport) writeCustomHeaders(s *Stream) {
295292
h := ht.rw.Header()
296293

internal/transport/http2_client.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,7 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
13991399
mdata = make(map[string][]string)
14001400
contentTypeErr = "malformed header: missing HTTP content-type"
14011401
grpcMessage string
1402+
statusGen *status.Status
14021403
recvCompress string
14031404
httpStatusCode *int
14041405
httpStatusErr string
@@ -1433,6 +1434,12 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
14331434
rawStatusCode = codes.Code(uint32(code))
14341435
case "grpc-message":
14351436
grpcMessage = decodeGrpcMessage(hf.Value)
1437+
case "grpc-status-details-bin":
1438+
var err error
1439+
statusGen, err = decodeGRPCStatusDetails(hf.Value)
1440+
if err != nil {
1441+
headerError = fmt.Sprintf("transport: malformed grpc-status-details-bin: %v", err)
1442+
}
14361443
case ":status":
14371444
if hf.Value == "200" {
14381445
httpStatusErr = ""
@@ -1541,12 +1548,14 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
15411548
return
15421549
}
15431550

1544-
status := istatus.NewWithProto(rawStatusCode, grpcMessage, mdata[grpcStatusDetailsBinHeader])
1551+
if statusGen == nil {
1552+
statusGen = status.New(rawStatusCode, grpcMessage)
1553+
}
15451554

15461555
// If client received END_STREAM from server while stream was still active,
15471556
// send RST_STREAM.
15481557
rstStream := s.getState() == streamActive
1549-
t.closeStream(s, io.EOF, rstStream, http2.ErrCodeNo, status, mdata, true)
1558+
t.closeStream(s, io.EOF, rstStream, http2.ErrCodeNo, statusGen, mdata, true)
15501559
}
15511560

15521561
// readServerPreface reads and handles the initial settings frame from the

internal/transport/http2_server.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -1057,15 +1057,12 @@ func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error {
10571057
headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-message", Value: encodeGrpcMessage(st.Message())})
10581058

10591059
if p := st.Proto(); p != nil && len(p.Details) > 0 {
1060-
// Do not use the user's grpc-status-details-bin (if present) if we are
1061-
// even attempting to set our own.
1062-
delete(s.trailer, grpcStatusDetailsBinHeader)
10631060
stBytes, err := proto.Marshal(p)
10641061
if err != nil {
10651062
// TODO: return error instead, when callers are able to handle it.
10661063
t.logger.Errorf("Failed to marshal rpc status: %s, error: %v", pretty.ToJSON(p), err)
10671064
} else {
1068-
headerFields = append(headerFields, hpack.HeaderField{Name: grpcStatusDetailsBinHeader, Value: encodeBinHeader(stBytes)})
1065+
headerFields = append(headerFields, hpack.HeaderField{Name: "grpc-status-details-bin", Value: encodeBinHeader(stBytes)})
10691066
}
10701067
}
10711068

internal/transport/http_util.go

+16-2
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ import (
3434
"time"
3535
"unicode/utf8"
3636

37+
"github.com/golang/protobuf/proto"
3738
"golang.org/x/net/http2"
3839
"golang.org/x/net/http2/hpack"
40+
spb "google.golang.org/genproto/googleapis/rpc/status"
3941
"google.golang.org/grpc/codes"
42+
"google.golang.org/grpc/status"
4043
)
4144

4245
const (
@@ -85,8 +88,6 @@ var (
8588
}
8689
)
8790

88-
var grpcStatusDetailsBinHeader = "grpc-status-details-bin"
89-
9091
// isReservedHeader checks whether hdr belongs to HTTP2 headers
9192
// reserved by gRPC protocol. Any other headers are classified as the
9293
// user-specified metadata.
@@ -102,6 +103,7 @@ func isReservedHeader(hdr string) bool {
102103
"grpc-message",
103104
"grpc-status",
104105
"grpc-timeout",
106+
"grpc-status-details-bin",
105107
// Intentionally exclude grpc-previous-rpc-attempts and
106108
// grpc-retry-pushback-ms, which are "reserved", but their API
107109
// intentionally works via metadata.
@@ -152,6 +154,18 @@ func decodeMetadataHeader(k, v string) (string, error) {
152154
return v, nil
153155
}
154156

157+
func decodeGRPCStatusDetails(rawDetails string) (*status.Status, error) {
158+
v, err := decodeBinHeader(rawDetails)
159+
if err != nil {
160+
return nil, err
161+
}
162+
st := &spb.Status{}
163+
if err = proto.Unmarshal(v, st); err != nil {
164+
return nil, err
165+
}
166+
return status.FromProto(st), nil
167+
}
168+
155169
type timeoutUnit uint8
156170

157171
const (

0 commit comments

Comments
 (0)