Use mcdsl/terminal for all password prompts
Replace direct golang.org/x/term calls with mcdsl/terminal.ReadPassword across mciasctl (6 sites), mciasgrpcctl (1 site), and mciasdb (1 site). Aligns with the new CLI security standard in engineering-standards.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
231
vendor/google.golang.org/grpc/stream.go
generated
vendored
231
vendor/google.golang.org/grpc/stream.go
generated
vendored
@@ -25,6 +25,7 @@ import (
|
||||
"math"
|
||||
rand "math/rand/v2"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -51,7 +52,8 @@ import (
|
||||
var metadataFromOutgoingContextRaw = internal.FromOutgoingContextRaw.(func(context.Context) (metadata.MD, [][]string, bool))
|
||||
|
||||
// StreamHandler defines the handler called by gRPC server to complete the
|
||||
// execution of a streaming RPC.
|
||||
// execution of a streaming RPC. srv is the service implementation on which the
|
||||
// RPC was invoked.
|
||||
//
|
||||
// If a StreamHandler returns an error, it should either be produced by the
|
||||
// status package, or be one of the context errors. Otherwise, gRPC will use
|
||||
@@ -177,13 +179,43 @@ func NewClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth
|
||||
return cc.NewStream(ctx, desc, method, opts...)
|
||||
}
|
||||
|
||||
var emptyMethodConfig = serviceconfig.MethodConfig{}
|
||||
|
||||
// endOfClientStream performs cleanup actions required for both successful and
|
||||
// failed streams. This includes incrementing channelz stats and invoking all
|
||||
// registered OnFinish call options.
|
||||
func endOfClientStream(cc *ClientConn, err error, opts ...CallOption) {
|
||||
if channelz.IsOn() {
|
||||
if err != nil {
|
||||
cc.incrCallsFailed()
|
||||
} else {
|
||||
cc.incrCallsSucceeded()
|
||||
}
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
if o, ok := o.(OnFinishCallOption); ok {
|
||||
o.OnFinish(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, opts ...CallOption) (_ ClientStream, err error) {
|
||||
if channelz.IsOn() {
|
||||
cc.incrCallsStarted()
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
// Ensure cleanup when stream creation fails.
|
||||
endOfClientStream(cc, err, opts...)
|
||||
}
|
||||
}()
|
||||
|
||||
// Start tracking the RPC for idleness purposes. This is where a stream is
|
||||
// created for both streaming and unary RPCs, and hence is a good place to
|
||||
// track active RPC count.
|
||||
if err := cc.idlenessMgr.OnCallBegin(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cc.idlenessMgr.OnCallBegin()
|
||||
|
||||
// Add a calloption, to decrement the active call count, that gets executed
|
||||
// when the RPC completes.
|
||||
opts = append([]CallOption{OnFinish(func(error) { cc.idlenessMgr.OnCallEnd() })}, opts...)
|
||||
@@ -202,14 +234,6 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth
|
||||
}
|
||||
}
|
||||
}
|
||||
if channelz.IsOn() {
|
||||
cc.incrCallsStarted()
|
||||
defer func() {
|
||||
if err != nil {
|
||||
cc.incrCallsFailed()
|
||||
}
|
||||
}()
|
||||
}
|
||||
// Provide an opportunity for the first RPC to see the first service config
|
||||
// provided by the resolver.
|
||||
nameResolutionDelayed, err := cc.waitForResolvedAddrs(ctx)
|
||||
@@ -217,7 +241,7 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var mc serviceconfig.MethodConfig
|
||||
mc := &emptyMethodConfig
|
||||
var onCommit func()
|
||||
newStream := func(ctx context.Context, done func()) (iresolver.ClientStream, error) {
|
||||
return newClientStreamWithParams(ctx, desc, cc, method, mc, onCommit, done, nameResolutionDelayed, opts...)
|
||||
@@ -240,7 +264,7 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth
|
||||
if rpcConfig.Context != nil {
|
||||
ctx = rpcConfig.Context
|
||||
}
|
||||
mc = rpcConfig.MethodConfig
|
||||
mc = &rpcConfig.MethodConfig
|
||||
onCommit = rpcConfig.OnCommitted
|
||||
if rpcConfig.Interceptor != nil {
|
||||
rpcInfo.Context = nil
|
||||
@@ -258,7 +282,7 @@ func newClientStream(ctx context.Context, desc *StreamDesc, cc *ClientConn, meth
|
||||
return newStream(ctx, func() {})
|
||||
}
|
||||
|
||||
func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc serviceconfig.MethodConfig, onCommit, doneFunc func(), nameResolutionDelayed bool, opts ...CallOption) (_ iresolver.ClientStream, err error) {
|
||||
func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc *serviceconfig.MethodConfig, onCommit, doneFunc func(), nameResolutionDelayed bool, opts ...CallOption) (_ iresolver.ClientStream, err error) {
|
||||
callInfo := defaultCallInfo()
|
||||
if mc.WaitForReady != nil {
|
||||
callInfo.failFast = !*mc.WaitForReady
|
||||
@@ -299,6 +323,10 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client
|
||||
DoneFunc: doneFunc,
|
||||
Authority: callInfo.authority,
|
||||
}
|
||||
if allowed := callInfo.acceptedResponseCompressors; len(allowed) > 0 {
|
||||
headerValue := strings.Join(allowed, ",")
|
||||
callHdr.AcceptedCompressors = &headerValue
|
||||
}
|
||||
|
||||
// Set our outgoing compression according to the UseCompressor CallOption, if
|
||||
// set. In that case, also find the compressor from the encoding package.
|
||||
@@ -325,7 +353,7 @@ func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *Client
|
||||
cs := &clientStream{
|
||||
callHdr: callHdr,
|
||||
ctx: ctx,
|
||||
methodConfig: &mc,
|
||||
methodConfig: mc,
|
||||
opts: opts,
|
||||
callInfo: callInfo,
|
||||
cc: cc,
|
||||
@@ -418,19 +446,21 @@ func (cs *clientStream) newAttemptLocked(isTransparent bool) (*csAttempt, error)
|
||||
ctx := newContextWithRPCInfo(cs.ctx, cs.callInfo.failFast, cs.callInfo.codec, cs.compressorV0, cs.compressorV1)
|
||||
method := cs.callHdr.Method
|
||||
var beginTime time.Time
|
||||
shs := cs.cc.dopts.copts.StatsHandlers
|
||||
for _, sh := range shs {
|
||||
ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method, FailFast: cs.callInfo.failFast, NameResolutionDelay: cs.nameResolutionDelay})
|
||||
sh := cs.cc.statsHandler
|
||||
if sh != nil {
|
||||
beginTime = time.Now()
|
||||
begin := &stats.Begin{
|
||||
ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{
|
||||
FullMethodName: method, FailFast: cs.callInfo.failFast,
|
||||
NameResolutionDelay: cs.nameResolutionDelay,
|
||||
})
|
||||
sh.HandleRPC(ctx, &stats.Begin{
|
||||
Client: true,
|
||||
BeginTime: beginTime,
|
||||
FailFast: cs.callInfo.failFast,
|
||||
IsClientStream: cs.desc.ClientStreams,
|
||||
IsServerStream: cs.desc.ServerStreams,
|
||||
IsTransparentRetryAttempt: isTransparent,
|
||||
}
|
||||
sh.HandleRPC(ctx, begin)
|
||||
})
|
||||
}
|
||||
|
||||
var trInfo *traceInfo
|
||||
@@ -461,7 +491,7 @@ func (cs *clientStream) newAttemptLocked(isTransparent bool) (*csAttempt, error)
|
||||
beginTime: beginTime,
|
||||
cs: cs,
|
||||
decompressorV0: cs.cc.dopts.dc,
|
||||
statsHandlers: shs,
|
||||
statsHandler: sh,
|
||||
trInfo: trInfo,
|
||||
}, nil
|
||||
}
|
||||
@@ -469,8 +499,9 @@ func (cs *clientStream) newAttemptLocked(isTransparent bool) (*csAttempt, error)
|
||||
func (a *csAttempt) getTransport() error {
|
||||
cs := a.cs
|
||||
|
||||
var err error
|
||||
a.transport, a.pickResult, err = cs.cc.getTransport(a.ctx, cs.callInfo.failFast, cs.callHdr.Method)
|
||||
pickInfo := balancer.PickInfo{Ctx: a.ctx, FullMethodName: cs.callHdr.Method}
|
||||
pick, err := cs.cc.pickerWrapper.pick(a.ctx, cs.callInfo.failFast, pickInfo)
|
||||
a.transport, a.pickResult = pick.transport, pick.result
|
||||
if err != nil {
|
||||
if de, ok := err.(dropError); ok {
|
||||
err = de.error
|
||||
@@ -479,7 +510,10 @@ func (a *csAttempt) getTransport() error {
|
||||
return err
|
||||
}
|
||||
if a.trInfo != nil {
|
||||
a.trInfo.firstLine.SetRemoteAddr(a.transport.RemoteAddr())
|
||||
a.trInfo.firstLine.SetRemoteAddr(a.transport.Peer().Addr)
|
||||
}
|
||||
if pick.blocked && a.statsHandler != nil {
|
||||
a.statsHandler.HandleRPC(a.ctx, &stats.DelayedPickComplete{})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -504,9 +538,17 @@ func (a *csAttempt) newStream() error {
|
||||
md, _ := metadata.FromOutgoingContext(a.ctx)
|
||||
md = metadata.Join(md, a.pickResult.Metadata)
|
||||
a.ctx = metadata.NewOutgoingContext(a.ctx, md)
|
||||
}
|
||||
|
||||
s, err := a.transport.NewStream(a.ctx, cs.callHdr)
|
||||
// If the `CallAuthority` CallOption is not set, check if the LB picker
|
||||
// has provided an authority override in the PickResult metadata and
|
||||
// apply it, as specified in gRFC A81.
|
||||
if cs.callInfo.authority == "" {
|
||||
if authMD := a.pickResult.Metadata.Get(":authority"); len(authMD) > 0 {
|
||||
cs.callHdr.Authority = authMD[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
s, err := a.transport.NewStream(a.ctx, cs.callHdr, a.statsHandler)
|
||||
if err != nil {
|
||||
nse, ok := err.(*transport.NewStreamError)
|
||||
if !ok {
|
||||
@@ -523,7 +565,7 @@ func (a *csAttempt) newStream() error {
|
||||
}
|
||||
a.transportStream = s
|
||||
a.ctx = s.Context()
|
||||
a.parser = &parser{r: s, bufferPool: a.cs.cc.dopts.copts.BufferPool}
|
||||
a.parser = parser{r: s, bufferPool: a.cs.cc.dopts.copts.BufferPool}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -543,6 +585,8 @@ type clientStream struct {
|
||||
|
||||
sentLast bool // sent an end stream
|
||||
|
||||
receivedFirstMsg bool // set after the first message is received
|
||||
|
||||
methodConfig *MethodConfig
|
||||
|
||||
ctx context.Context // the application's context, wrapped by stats/tracing
|
||||
@@ -593,7 +637,7 @@ type csAttempt struct {
|
||||
cs *clientStream
|
||||
transport transport.ClientTransport
|
||||
transportStream *transport.ClientStream
|
||||
parser *parser
|
||||
parser parser
|
||||
pickResult balancer.PickResult
|
||||
|
||||
finished bool
|
||||
@@ -607,8 +651,8 @@ type csAttempt struct {
|
||||
// and cleared when the finish method is called.
|
||||
trInfo *traceInfo
|
||||
|
||||
statsHandlers []stats.Handler
|
||||
beginTime time.Time
|
||||
statsHandler stats.Handler
|
||||
beginTime time.Time
|
||||
|
||||
// set for newStream errors that may be transparently retried
|
||||
allowTransparentRetry bool
|
||||
@@ -1032,9 +1076,6 @@ func (cs *clientStream) finish(err error) {
|
||||
return
|
||||
}
|
||||
cs.finished = true
|
||||
for _, onFinish := range cs.callInfo.onFinish {
|
||||
onFinish(err)
|
||||
}
|
||||
cs.commitAttemptLocked()
|
||||
if cs.attempt != nil {
|
||||
cs.attempt.finish(err)
|
||||
@@ -1074,13 +1115,7 @@ func (cs *clientStream) finish(err error) {
|
||||
if err == nil {
|
||||
cs.retryThrottler.successfulRPC()
|
||||
}
|
||||
if channelz.IsOn() {
|
||||
if err != nil {
|
||||
cs.cc.incrCallsFailed()
|
||||
} else {
|
||||
cs.cc.incrCallsSucceeded()
|
||||
}
|
||||
}
|
||||
endOfClientStream(cs.cc, err, cs.opts...)
|
||||
cs.cancel()
|
||||
}
|
||||
|
||||
@@ -1102,17 +1137,15 @@ func (a *csAttempt) sendMsg(m any, hdr []byte, payld mem.BufferSlice, dataLength
|
||||
}
|
||||
return io.EOF
|
||||
}
|
||||
if len(a.statsHandlers) != 0 {
|
||||
for _, sh := range a.statsHandlers {
|
||||
sh.HandleRPC(a.ctx, outPayload(true, m, dataLength, payloadLength, time.Now()))
|
||||
}
|
||||
if a.statsHandler != nil {
|
||||
a.statsHandler.HandleRPC(a.ctx, outPayload(true, m, dataLength, payloadLength, time.Now()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *csAttempt) recvMsg(m any, payInfo *payloadInfo) (err error) {
|
||||
cs := a.cs
|
||||
if len(a.statsHandlers) != 0 && payInfo == nil {
|
||||
if a.statsHandler != nil && payInfo == nil {
|
||||
payInfo = &payloadInfo{}
|
||||
defer payInfo.free()
|
||||
}
|
||||
@@ -1126,6 +1159,10 @@ func (a *csAttempt) recvMsg(m any, payInfo *payloadInfo) (err error) {
|
||||
a.decompressorV0 = nil
|
||||
a.decompressorV1 = encoding.GetCompressor(ct)
|
||||
}
|
||||
// Validate that the compression method is acceptable for this call.
|
||||
if !acceptedCompressorAllows(cs.callInfo.acceptedResponseCompressors, ct) {
|
||||
return status.Errorf(codes.Internal, "grpc: peer compressed the response with %q which is not allowed by AcceptCompressors", ct)
|
||||
}
|
||||
} else {
|
||||
// No compression is used; disable our decompressor.
|
||||
a.decompressorV0 = nil
|
||||
@@ -1133,16 +1170,21 @@ func (a *csAttempt) recvMsg(m any, payInfo *payloadInfo) (err error) {
|
||||
// Only initialize this state once per stream.
|
||||
a.decompressorSet = true
|
||||
}
|
||||
if err := recv(a.parser, cs.codec, a.transportStream, a.decompressorV0, m, *cs.callInfo.maxReceiveMessageSize, payInfo, a.decompressorV1, false); err != nil {
|
||||
if err := recv(&a.parser, cs.codec, a.transportStream, a.decompressorV0, m, *cs.callInfo.maxReceiveMessageSize, payInfo, a.decompressorV1, false); err != nil {
|
||||
if err == io.EOF {
|
||||
if statusErr := a.transportStream.Status().Err(); statusErr != nil {
|
||||
return statusErr
|
||||
}
|
||||
// Received no msg and status OK for non-server streaming rpcs.
|
||||
if !cs.desc.ServerStreams && !cs.receivedFirstMsg {
|
||||
return status.Error(codes.Internal, "cardinality violation: received no response message from non-server-streaming RPC")
|
||||
}
|
||||
return io.EOF // indicates successful end of stream.
|
||||
}
|
||||
|
||||
return toRPCErr(err)
|
||||
}
|
||||
cs.receivedFirstMsg = true
|
||||
if a.trInfo != nil {
|
||||
a.mu.Lock()
|
||||
if a.trInfo.tr != nil {
|
||||
@@ -1150,8 +1192,8 @@ func (a *csAttempt) recvMsg(m any, payInfo *payloadInfo) (err error) {
|
||||
}
|
||||
a.mu.Unlock()
|
||||
}
|
||||
for _, sh := range a.statsHandlers {
|
||||
sh.HandleRPC(a.ctx, &stats.InPayload{
|
||||
if a.statsHandler != nil {
|
||||
a.statsHandler.HandleRPC(a.ctx, &stats.InPayload{
|
||||
Client: true,
|
||||
RecvTime: time.Now(),
|
||||
Payload: m,
|
||||
@@ -1166,12 +1208,12 @@ func (a *csAttempt) recvMsg(m any, payInfo *payloadInfo) (err error) {
|
||||
}
|
||||
// Special handling for non-server-stream rpcs.
|
||||
// This recv expects EOF or errors, so we don't collect inPayload.
|
||||
if err := recv(a.parser, cs.codec, a.transportStream, a.decompressorV0, m, *cs.callInfo.maxReceiveMessageSize, nil, a.decompressorV1, false); err == io.EOF {
|
||||
if err := recv(&a.parser, cs.codec, a.transportStream, a.decompressorV0, m, *cs.callInfo.maxReceiveMessageSize, nil, a.decompressorV1, false); err == io.EOF {
|
||||
return a.transportStream.Status().Err() // non-server streaming Recv returns nil on success
|
||||
} else if err != nil {
|
||||
return toRPCErr(err)
|
||||
}
|
||||
return status.Errorf(codes.Internal, "cardinality violation: expected <EOF> for non server-streaming RPCs, but received another message")
|
||||
return status.Error(codes.Internal, "cardinality violation: expected <EOF> for non server-streaming RPCs, but received another message")
|
||||
}
|
||||
|
||||
func (a *csAttempt) finish(err error) {
|
||||
@@ -1204,15 +1246,14 @@ func (a *csAttempt) finish(err error) {
|
||||
ServerLoad: balancerload.Parse(tr),
|
||||
})
|
||||
}
|
||||
for _, sh := range a.statsHandlers {
|
||||
end := &stats.End{
|
||||
if a.statsHandler != nil {
|
||||
a.statsHandler.HandleRPC(a.ctx, &stats.End{
|
||||
Client: true,
|
||||
BeginTime: a.beginTime,
|
||||
EndTime: time.Now(),
|
||||
Trailer: tr,
|
||||
Error: err,
|
||||
}
|
||||
sh.HandleRPC(a.ctx, end)
|
||||
})
|
||||
}
|
||||
if a.trInfo != nil && a.trInfo.tr != nil {
|
||||
if err == nil {
|
||||
@@ -1309,16 +1350,18 @@ func newNonRetryClientStream(ctx context.Context, desc *StreamDesc, method strin
|
||||
codec: c.codec,
|
||||
sendCompressorV0: cp,
|
||||
sendCompressorV1: comp,
|
||||
decompressorV0: ac.cc.dopts.dc,
|
||||
transport: t,
|
||||
}
|
||||
|
||||
s, err := as.transport.NewStream(as.ctx, as.callHdr)
|
||||
// nil stats handler: internal streams like health and ORCA do not support telemetry.
|
||||
s, err := as.transport.NewStream(as.ctx, as.callHdr, nil)
|
||||
if err != nil {
|
||||
err = toRPCErr(err)
|
||||
return nil, err
|
||||
}
|
||||
as.transportStream = s
|
||||
as.parser = &parser{r: s, bufferPool: ac.dopts.copts.BufferPool}
|
||||
as.parser = parser{r: s, bufferPool: ac.dopts.copts.BufferPool}
|
||||
ac.incrCallsStarted()
|
||||
if desc != unaryStreamDesc {
|
||||
// Listen on stream context to cleanup when the stream context is
|
||||
@@ -1353,6 +1396,7 @@ type addrConnStream struct {
|
||||
transport transport.ClientTransport
|
||||
ctx context.Context
|
||||
sentLast bool
|
||||
receivedFirstMsg bool
|
||||
desc *StreamDesc
|
||||
codec baseCodec
|
||||
sendCompressorV0 Compressor
|
||||
@@ -1360,7 +1404,7 @@ type addrConnStream struct {
|
||||
decompressorSet bool
|
||||
decompressorV0 Decompressor
|
||||
decompressorV1 encoding.Compressor
|
||||
parser *parser
|
||||
parser parser
|
||||
|
||||
// mu guards finished and is held for the entire finish method.
|
||||
mu sync.Mutex
|
||||
@@ -1466,6 +1510,10 @@ func (as *addrConnStream) RecvMsg(m any) (err error) {
|
||||
as.decompressorV0 = nil
|
||||
as.decompressorV1 = encoding.GetCompressor(ct)
|
||||
}
|
||||
// Validate that the compression method is acceptable for this call.
|
||||
if !acceptedCompressorAllows(as.callInfo.acceptedResponseCompressors, ct) {
|
||||
return status.Errorf(codes.Internal, "grpc: peer compressed the response with %q which is not allowed by AcceptCompressors", ct)
|
||||
}
|
||||
} else {
|
||||
// No compression is used; disable our decompressor.
|
||||
as.decompressorV0 = nil
|
||||
@@ -1473,15 +1521,20 @@ func (as *addrConnStream) RecvMsg(m any) (err error) {
|
||||
// Only initialize this state once per stream.
|
||||
as.decompressorSet = true
|
||||
}
|
||||
if err := recv(as.parser, as.codec, as.transportStream, as.decompressorV0, m, *as.callInfo.maxReceiveMessageSize, nil, as.decompressorV1, false); err != nil {
|
||||
if err := recv(&as.parser, as.codec, as.transportStream, as.decompressorV0, m, *as.callInfo.maxReceiveMessageSize, nil, as.decompressorV1, false); err != nil {
|
||||
if err == io.EOF {
|
||||
if statusErr := as.transportStream.Status().Err(); statusErr != nil {
|
||||
return statusErr
|
||||
}
|
||||
// Received no msg and status OK for non-server streaming rpcs.
|
||||
if !as.desc.ServerStreams && !as.receivedFirstMsg {
|
||||
return status.Error(codes.Internal, "cardinality violation: received no response message from non-server-streaming RPC")
|
||||
}
|
||||
return io.EOF // indicates successful end of stream.
|
||||
}
|
||||
return toRPCErr(err)
|
||||
}
|
||||
as.receivedFirstMsg = true
|
||||
|
||||
if as.desc.ServerStreams {
|
||||
// Subsequent messages should be received by subsequent RecvMsg calls.
|
||||
@@ -1490,12 +1543,12 @@ func (as *addrConnStream) RecvMsg(m any) (err error) {
|
||||
|
||||
// Special handling for non-server-stream rpcs.
|
||||
// This recv expects EOF or errors, so we don't collect inPayload.
|
||||
if err := recv(as.parser, as.codec, as.transportStream, as.decompressorV0, m, *as.callInfo.maxReceiveMessageSize, nil, as.decompressorV1, false); err == io.EOF {
|
||||
if err := recv(&as.parser, as.codec, as.transportStream, as.decompressorV0, m, *as.callInfo.maxReceiveMessageSize, nil, as.decompressorV1, false); err == io.EOF {
|
||||
return as.transportStream.Status().Err() // non-server streaming Recv returns nil on success
|
||||
} else if err != nil {
|
||||
return toRPCErr(err)
|
||||
}
|
||||
return status.Errorf(codes.Internal, "cardinality violation: expected <EOF> for non server-streaming RPCs, but received another message")
|
||||
return status.Error(codes.Internal, "cardinality violation: expected <EOF> for non server-streaming RPCs, but received another message")
|
||||
}
|
||||
|
||||
func (as *addrConnStream) finish(err error) {
|
||||
@@ -1578,8 +1631,9 @@ type ServerStream interface {
|
||||
type serverStream struct {
|
||||
ctx context.Context
|
||||
s *transport.ServerStream
|
||||
p *parser
|
||||
p parser
|
||||
codec baseCodec
|
||||
desc *StreamDesc
|
||||
|
||||
compressorV0 Compressor
|
||||
compressorV1 encoding.Compressor
|
||||
@@ -1588,11 +1642,13 @@ type serverStream struct {
|
||||
|
||||
sendCompressorName string
|
||||
|
||||
recvFirstMsg bool // set after the first message is received
|
||||
|
||||
maxReceiveMessageSize int
|
||||
maxSendMessageSize int
|
||||
trInfo *traceInfo
|
||||
|
||||
statsHandler []stats.Handler
|
||||
statsHandler stats.Handler
|
||||
|
||||
binlogs []binarylog.MethodLogger
|
||||
// serverHeaderBinlogged indicates whether server header has been logged. It
|
||||
@@ -1728,10 +1784,8 @@ func (ss *serverStream) SendMsg(m any) (err error) {
|
||||
binlog.Log(ss.ctx, sm)
|
||||
}
|
||||
}
|
||||
if len(ss.statsHandler) != 0 {
|
||||
for _, sh := range ss.statsHandler {
|
||||
sh.HandleRPC(ss.s.Context(), outPayload(false, m, dataLen, payloadLen, time.Now()))
|
||||
}
|
||||
if ss.statsHandler != nil {
|
||||
ss.statsHandler.HandleRPC(ss.s.Context(), outPayload(false, m, dataLen, payloadLen, time.Now()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1762,11 +1816,11 @@ func (ss *serverStream) RecvMsg(m any) (err error) {
|
||||
}
|
||||
}()
|
||||
var payInfo *payloadInfo
|
||||
if len(ss.statsHandler) != 0 || len(ss.binlogs) != 0 {
|
||||
if ss.statsHandler != nil || len(ss.binlogs) != 0 {
|
||||
payInfo = &payloadInfo{}
|
||||
defer payInfo.free()
|
||||
}
|
||||
if err := recv(ss.p, ss.codec, ss.s, ss.decompressorV0, m, ss.maxReceiveMessageSize, payInfo, ss.decompressorV1, true); err != nil {
|
||||
if err := recv(&ss.p, ss.codec, ss.s, ss.decompressorV0, m, ss.maxReceiveMessageSize, payInfo, ss.decompressorV1, true); err != nil {
|
||||
if err == io.EOF {
|
||||
if len(ss.binlogs) != 0 {
|
||||
chc := &binarylog.ClientHalfClose{}
|
||||
@@ -1774,6 +1828,10 @@ func (ss *serverStream) RecvMsg(m any) (err error) {
|
||||
binlog.Log(ss.ctx, chc)
|
||||
}
|
||||
}
|
||||
// Received no request msg for non-client streaming rpcs.
|
||||
if !ss.desc.ClientStreams && !ss.recvFirstMsg {
|
||||
return status.Error(codes.Internal, "cardinality violation: received no request message from non-client-streaming RPC")
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
@@ -1781,16 +1839,15 @@ func (ss *serverStream) RecvMsg(m any) (err error) {
|
||||
}
|
||||
return toRPCErr(err)
|
||||
}
|
||||
if len(ss.statsHandler) != 0 {
|
||||
for _, sh := range ss.statsHandler {
|
||||
sh.HandleRPC(ss.s.Context(), &stats.InPayload{
|
||||
RecvTime: time.Now(),
|
||||
Payload: m,
|
||||
Length: payInfo.uncompressedBytes.Len(),
|
||||
WireLength: payInfo.compressedLength + headerLen,
|
||||
CompressedLength: payInfo.compressedLength,
|
||||
})
|
||||
}
|
||||
ss.recvFirstMsg = true
|
||||
if ss.statsHandler != nil {
|
||||
ss.statsHandler.HandleRPC(ss.s.Context(), &stats.InPayload{
|
||||
RecvTime: time.Now(),
|
||||
Payload: m,
|
||||
Length: payInfo.uncompressedBytes.Len(),
|
||||
WireLength: payInfo.compressedLength + headerLen,
|
||||
CompressedLength: payInfo.compressedLength,
|
||||
})
|
||||
}
|
||||
if len(ss.binlogs) != 0 {
|
||||
cm := &binarylog.ClientMessage{
|
||||
@@ -1800,7 +1857,19 @@ func (ss *serverStream) RecvMsg(m any) (err error) {
|
||||
binlog.Log(ss.ctx, cm)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
if ss.desc.ClientStreams {
|
||||
// Subsequent messages should be received by subsequent RecvMsg calls.
|
||||
return nil
|
||||
}
|
||||
// Special handling for non-client-stream rpcs.
|
||||
// This recv expects EOF or errors, so we don't collect inPayload.
|
||||
if err := recv(&ss.p, ss.codec, ss.s, ss.decompressorV0, m, ss.maxReceiveMessageSize, nil, ss.decompressorV1, true); err == io.EOF {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
return status.Error(codes.Internal, "cardinality violation: received multiple request messages for non-client-streaming RPC")
|
||||
}
|
||||
|
||||
// MethodFromServerStream returns the method string for the input stream.
|
||||
|
||||
Reference in New Issue
Block a user