/* * * Copyright 2014 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 grpcimport ()// Compressor defines the interface gRPC uses to compress a message.//// Deprecated: use package encoding.typeCompressorinterface {// Do compresses p into w.Do(w io.Writer, p []byte) error// Type returns the compression algorithm the Compressor uses.Type() string}type gzipCompressor struct { pool sync.Pool}// NewGZIPCompressor creates a Compressor based on GZIP.//// Deprecated: use package encoding/gzip.func () Compressor { , := NewGZIPCompressorWithLevel(gzip.DefaultCompression)return}// NewGZIPCompressorWithLevel is like NewGZIPCompressor but specifies the gzip compression level instead// of assuming DefaultCompression.//// The error returned will be nil if the level is valid.//// Deprecated: use package encoding/gzip.func ( int) (Compressor, error) {if < gzip.DefaultCompression || > gzip.BestCompression {returnnil, fmt.Errorf("grpc: invalid compression level: %d", ) }return &gzipCompressor{pool: sync.Pool{New: func() any { , := gzip.NewWriterLevel(io.Discard, )if != nil {panic() }return }, }, }, nil}func ( *gzipCompressor) ( io.Writer, []byte) error { := .pool.Get().(*gzip.Writer)defer .pool.Put() .Reset()if , := .Write(); != nil {return }return .Close()}func ( *gzipCompressor) () string {return"gzip"}// Decompressor defines the interface gRPC uses to decompress a message.//// Deprecated: use package encoding.typeDecompressorinterface {// Do reads the data from r and uncompress them.Do(r io.Reader) ([]byte, error)// Type returns the compression algorithm the Decompressor uses.Type() string}type gzipDecompressor struct { pool sync.Pool}// NewGZIPDecompressor creates a Decompressor based on GZIP.//// Deprecated: use package encoding/gzip.func () Decompressor {return &gzipDecompressor{}}func ( *gzipDecompressor) ( io.Reader) ([]byte, error) {var *gzip.Readerswitch maybeZ := .pool.Get().(type) {casenil: , := gzip.NewReader()if != nil {returnnil, } = case *gzip.Reader: = if := .Reset(); != nil { .pool.Put()returnnil, } }deferfunc() { .Close() .pool.Put() }()returnio.ReadAll()}func ( *gzipDecompressor) () string {return"gzip"}// callInfo contains all related configuration and information about an RPC.type callInfo struct { compressorName string failFast bool maxReceiveMessageSize *int maxSendMessageSize *int creds credentials.PerRPCCredentials contentSubtype string codec baseCodec maxRetryRPCBufferSize int onFinish []func(err error) authority string}func defaultCallInfo() *callInfo {return &callInfo{failFast: true,maxRetryRPCBufferSize: 256 * 1024, // 256KB }}// CallOption configures a Call before it starts or extracts information from// a Call after it completes.typeCallOptioninterface {// before is called before the call is sent to any server. If before // returns a non-nil error, the RPC fails with that error. before(*callInfo) error// after is called after the call has completed. after cannot return an // error, so any failures should be reported via output parameters. after(*callInfo, *csAttempt)}// EmptyCallOption does not alter the Call configuration.// It can be embedded in another structure to carry satellite data for use// by interceptors.typeEmptyCallOptionstruct{}func (EmptyCallOption) (*callInfo) error { returnnil }func (EmptyCallOption) (*callInfo, *csAttempt) {}// StaticMethod returns a CallOption which specifies that a call is being made// to a method that is static, which means the method is known at compile time// and doesn't change at runtime. This can be used as a signal to stats plugins// that this method is safe to include as a key to a measurement.func () CallOption {returnStaticMethodCallOption{}}// StaticMethodCallOption is a CallOption that specifies that a call comes// from a static method.typeStaticMethodCallOptionstruct {EmptyCallOption}// Header returns a CallOptions that retrieves the header metadata// for a unary RPC.func ( *metadata.MD) CallOption {returnHeaderCallOption{HeaderAddr: }}// HeaderCallOption is a CallOption for collecting response header metadata.// The metadata field will be populated *after* the RPC completes.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeHeaderCallOptionstruct { HeaderAddr *metadata.MD}func ( HeaderCallOption) (*callInfo) error { returnnil }func ( HeaderCallOption) ( *callInfo, *csAttempt) { *.HeaderAddr, _ = .transportStream.Header()}// Trailer returns a CallOptions that retrieves the trailer metadata// for a unary RPC.func ( *metadata.MD) CallOption {returnTrailerCallOption{TrailerAddr: }}// TrailerCallOption is a CallOption for collecting response trailer metadata.// The metadata field will be populated *after* the RPC completes.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeTrailerCallOptionstruct { TrailerAddr *metadata.MD}func ( TrailerCallOption) (*callInfo) error { returnnil }func ( TrailerCallOption) ( *callInfo, *csAttempt) { *.TrailerAddr = .transportStream.Trailer()}// Peer returns a CallOption that retrieves peer information for a unary RPC.// The peer field will be populated *after* the RPC completes.func ( *peer.Peer) CallOption {returnPeerCallOption{PeerAddr: }}// PeerCallOption is a CallOption for collecting the identity of the remote// peer. The peer field will be populated *after* the RPC completes.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typePeerCallOptionstruct { PeerAddr *peer.Peer}func ( PeerCallOption) (*callInfo) error { returnnil }func ( PeerCallOption) ( *callInfo, *csAttempt) {if , := peer.FromContext(.transportStream.Context()); { *.PeerAddr = * }}// WaitForReady configures the RPC's behavior when the client is in// TRANSIENT_FAILURE, which occurs when all addresses fail to connect. If// waitForReady is false, the RPC will fail immediately. Otherwise, the client// will wait until a connection becomes available or the RPC's deadline is// reached.//// By default, RPCs do not "wait for ready".func ( bool) CallOption {returnFailFastCallOption{FailFast: !}}// FailFast is the opposite of WaitForReady.//// Deprecated: use WaitForReady.func ( bool) CallOption {returnFailFastCallOption{FailFast: }}// FailFastCallOption is a CallOption for indicating whether an RPC should fail// fast or not.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeFailFastCallOptionstruct { FailFast bool}func ( FailFastCallOption) ( *callInfo) error { .failFast = .FailFastreturnnil}func ( FailFastCallOption) (*callInfo, *csAttempt) {}// OnFinish returns a CallOption that configures a callback to be called when// the call completes. The error passed to the callback is the status of the// RPC, and may be nil. The onFinish callback provided will only be called once// by gRPC. This is mainly used to be used by streaming interceptors, to be// notified when the RPC completes along with information about the status of// the RPC.//// # Experimental//// Notice: This API is EXPERIMENTAL and may be changed or removed in a// later release.func ( func( error)) CallOption {returnOnFinishCallOption{OnFinish: , }}// OnFinishCallOption is CallOption that indicates a callback to be called when// the call completes.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeOnFinishCallOptionstruct { OnFinish func(error)}func ( OnFinishCallOption) ( *callInfo) error { .onFinish = append(.onFinish, .OnFinish)returnnil}func ( OnFinishCallOption) (*callInfo, *csAttempt) {}// MaxCallRecvMsgSize returns a CallOption which sets the maximum message size// in bytes the client can receive. If this is not set, gRPC uses the default// 4MB.func ( int) CallOption {returnMaxRecvMsgSizeCallOption{MaxRecvMsgSize: }}// MaxRecvMsgSizeCallOption is a CallOption that indicates the maximum message// size in bytes the client can receive.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeMaxRecvMsgSizeCallOptionstruct { MaxRecvMsgSize int}func ( MaxRecvMsgSizeCallOption) ( *callInfo) error { .maxReceiveMessageSize = &.MaxRecvMsgSizereturnnil}func ( MaxRecvMsgSizeCallOption) (*callInfo, *csAttempt) {}// CallAuthority returns a CallOption that sets the HTTP/2 :authority header of// an RPC to the specified value. When using CallAuthority, the credentials in// use must implement the AuthorityValidator interface.//// # Experimental//// Notice: This API is EXPERIMENTAL and may be changed or removed in a later// release.func ( string) CallOption {returnAuthorityOverrideCallOption{Authority: }}// AuthorityOverrideCallOption is a CallOption that indicates the HTTP/2// :authority header value to use for the call.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a later// release.typeAuthorityOverrideCallOptionstruct { Authority string}func ( AuthorityOverrideCallOption) ( *callInfo) error { .authority = .Authorityreturnnil}func ( AuthorityOverrideCallOption) (*callInfo, *csAttempt) {}// MaxCallSendMsgSize returns a CallOption which sets the maximum message size// in bytes the client can send. If this is not set, gRPC uses the default// `math.MaxInt32`.func ( int) CallOption {returnMaxSendMsgSizeCallOption{MaxSendMsgSize: }}// MaxSendMsgSizeCallOption is a CallOption that indicates the maximum message// size in bytes the client can send.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeMaxSendMsgSizeCallOptionstruct { MaxSendMsgSize int}func ( MaxSendMsgSizeCallOption) ( *callInfo) error { .maxSendMessageSize = &.MaxSendMsgSizereturnnil}func ( MaxSendMsgSizeCallOption) (*callInfo, *csAttempt) {}// PerRPCCredentials returns a CallOption that sets credentials.PerRPCCredentials// for a call.func ( credentials.PerRPCCredentials) CallOption {returnPerRPCCredsCallOption{Creds: }}// PerRPCCredsCallOption is a CallOption that indicates the per-RPC// credentials to use for the call.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typePerRPCCredsCallOptionstruct { Creds credentials.PerRPCCredentials}func ( PerRPCCredsCallOption) ( *callInfo) error { .creds = .Credsreturnnil}func ( PerRPCCredsCallOption) (*callInfo, *csAttempt) {}// UseCompressor returns a CallOption which sets the compressor used when// sending the request. If WithCompressor is also set, UseCompressor has// higher priority.//// # Experimental//// Notice: This API is EXPERIMENTAL and may be changed or removed in a// later release.func ( string) CallOption {returnCompressorCallOption{CompressorType: }}// CompressorCallOption is a CallOption that indicates the compressor to use.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeCompressorCallOptionstruct { CompressorType string}func ( CompressorCallOption) ( *callInfo) error { .compressorName = .CompressorTypereturnnil}func ( CompressorCallOption) (*callInfo, *csAttempt) {}// CallContentSubtype returns a CallOption that will set the content-subtype// for a call. For example, if content-subtype is "json", the Content-Type over// the wire will be "application/grpc+json". The content-subtype is converted// to lowercase before being included in Content-Type. See Content-Type on// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for// more details.//// If ForceCodec is not also used, the content-subtype will be used to look up// the Codec to use in the registry controlled by RegisterCodec. See the// documentation on RegisterCodec for details on registration. The lookup of// content-subtype is case-insensitive. If no such Codec is found, the call// will result in an error with code codes.Internal.//// If ForceCodec is also used, that Codec will be used for all request and// response messages, with the content-subtype set to the given contentSubtype// here for requests.func ( string) CallOption {returnContentSubtypeCallOption{ContentSubtype: strings.ToLower()}}// ContentSubtypeCallOption is a CallOption that indicates the content-subtype// used for marshaling messages.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeContentSubtypeCallOptionstruct { ContentSubtype string}func ( ContentSubtypeCallOption) ( *callInfo) error { .contentSubtype = .ContentSubtypereturnnil}func ( ContentSubtypeCallOption) (*callInfo, *csAttempt) {}// ForceCodec returns a CallOption that will set codec to be used for all// request and response messages for a call. The result of calling Name() will// be used as the content-subtype after converting to lowercase, unless// CallContentSubtype is also used.//// See Content-Type on// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for// more details. Also see the documentation on RegisterCodec and// CallContentSubtype for more details on the interaction between Codec and// content-subtype.//// This function is provided for advanced users; prefer to use only// CallContentSubtype to select a registered codec instead.//// # Experimental//// Notice: This API is EXPERIMENTAL and may be changed or removed in a// later release.func ( encoding.Codec) CallOption {returnForceCodecCallOption{Codec: }}// ForceCodecCallOption is a CallOption that indicates the codec used for// marshaling messages.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeForceCodecCallOptionstruct { Codec encoding.Codec}func ( ForceCodecCallOption) ( *callInfo) error { .codec = newCodecV1Bridge(.Codec)returnnil}func ( ForceCodecCallOption) (*callInfo, *csAttempt) {}// ForceCodecV2 returns a CallOption that will set codec to be used for all// request and response messages for a call. The result of calling Name() will// be used as the content-subtype after converting to lowercase, unless// CallContentSubtype is also used.//// See Content-Type on// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for// more details. Also see the documentation on RegisterCodec and// CallContentSubtype for more details on the interaction between Codec and// content-subtype.//// This function is provided for advanced users; prefer to use only// CallContentSubtype to select a registered codec instead.//// # Experimental//// Notice: This API is EXPERIMENTAL and may be changed or removed in a// later release.func ( encoding.CodecV2) CallOption {returnForceCodecV2CallOption{CodecV2: }}// ForceCodecV2CallOption is a CallOption that indicates the codec used for// marshaling messages.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeForceCodecV2CallOptionstruct { CodecV2 encoding.CodecV2}func ( ForceCodecV2CallOption) ( *callInfo) error { .codec = .CodecV2returnnil}func ( ForceCodecV2CallOption) (*callInfo, *csAttempt) {}// CallCustomCodec behaves like ForceCodec, but accepts a grpc.Codec instead of// an encoding.Codec.//// Deprecated: use ForceCodec instead.func ( Codec) CallOption {returnCustomCodecCallOption{Codec: }}// CustomCodecCallOption is a CallOption that indicates the codec used for// marshaling messages.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeCustomCodecCallOptionstruct { Codec Codec}func ( CustomCodecCallOption) ( *callInfo) error { .codec = newCodecV0Bridge(.Codec)returnnil}func ( CustomCodecCallOption) (*callInfo, *csAttempt) {}// MaxRetryRPCBufferSize returns a CallOption that limits the amount of memory// used for buffering this RPC's requests for retry purposes.//// # Experimental//// Notice: This API is EXPERIMENTAL and may be changed or removed in a// later release.func ( int) CallOption {returnMaxRetryRPCBufferSizeCallOption{}}// MaxRetryRPCBufferSizeCallOption is a CallOption indicating the amount of// memory to be used for caching this RPC for retry purposes.//// # Experimental//// Notice: This type is EXPERIMENTAL and may be changed or removed in a// later release.typeMaxRetryRPCBufferSizeCallOptionstruct { MaxRetryRPCBufferSize int}func ( MaxRetryRPCBufferSizeCallOption) ( *callInfo) error { .maxRetryRPCBufferSize = .MaxRetryRPCBufferSizereturnnil}func ( MaxRetryRPCBufferSizeCallOption) (*callInfo, *csAttempt) {}// The format of the payload: compressed or not?type payloadFormat uint8const ( compressionNone payloadFormat = 0// no compression compressionMade payloadFormat = 1// compressed)func ( payloadFormat) () bool {return == compressionMade}type streamReader interface { ReadMessageHeader(header []byte) error Read(n int) (mem.BufferSlice, error)}// parser reads complete gRPC messages from the underlying reader.type parser struct {// r is the underlying reader. // See the comment on recvMsg for the permissible // error types. r streamReader// The header of a gRPC message. Find more detail at // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md header [5]byte// bufferPool is the pool of shared receive buffers. bufferPool mem.BufferPool}// recvMsg reads a complete gRPC message from the stream.//// It returns the message and its payload (compression/encoding)// format. The caller owns the returned msg memory.//// If there is an error, possible values are:// - io.EOF, when no messages remain// - io.ErrUnexpectedEOF// - of type transport.ConnectionError// - an error from the status package//// No other error values or types must be returned, which also means// that the underlying streamReader must not return an incompatible// error.func ( *parser) ( int) (payloadFormat, mem.BufferSlice, error) { := .r.ReadMessageHeader(.header[:])if != nil {return0, nil, } := payloadFormat(.header[0]) := binary.BigEndian.Uint32(.header[1:])ifint64() > int64(maxInt) {return0, nil, status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max length allowed on current machine (%d vs. %d)", , maxInt) }ifint() > {return0, nil, status.Errorf(codes.ResourceExhausted, "grpc: received message larger than max (%d vs. %d)", , ) } , := .r.Read(int())if != nil {if == io.EOF { = io.ErrUnexpectedEOF }return0, nil, }return , , nil}// encode serializes msg and returns a buffer containing the message, or an// error if it is too large to be transmitted by grpc. If msg is nil, it// generates an empty message.func encode( baseCodec, any) (mem.BufferSlice, error) {if == nil { // NOTE: typed nils will not be caught by this checkreturnnil, nil } , := .Marshal()if != nil {returnnil, status.Errorf(codes.Internal, "grpc: error while marshaling: %v", .Error()) }if := uint(.Len()); > math.MaxUint32 { .Free()returnnil, status.Errorf(codes.ResourceExhausted, "grpc: message too large (%d bytes)", ) }return , nil}// compress returns the input bytes compressed by compressor or cp.// If both compressors are nil, or if the message has zero length, returns nil,// indicating no compression was done.//// TODO(dfawley): eliminate cp parameter by wrapping Compressor in an encoding.Compressor.func compress( mem.BufferSlice, Compressor, encoding.Compressor, mem.BufferPool) (mem.BufferSlice, payloadFormat, error) {if ( == nil && == nil) || .Len() == 0 {returnnil, compressionNone, nil }varmem.BufferSlice := mem.NewWriter(&, ) := func( error) error { .Free()returnstatus.Errorf(codes.Internal, "grpc: error while compressing: %v", .Error()) }if != nil { , := .Compress()if != nil {returnnil, 0, () }for , := range {if , := .Write(.ReadOnlyData()); != nil {returnnil, 0, () } }if := .Close(); != nil {returnnil, 0, () } } else {// This is obviously really inefficient since it fully materializes the data, but // there is no way around this with the old Compressor API. At least it attempts // to return the buffer to the provider, in the hopes it can be reused (maybe // even by a subsequent call to this very function). := .MaterializeToBuffer()defer .Free()if := .Do(, .ReadOnlyData()); != nil {returnnil, 0, () } }return , compressionMade, nil}const ( payloadLen = 1 sizeLen = 4 headerLen = payloadLen + sizeLen)// msgHeader returns a 5-byte header for the message being transmitted and the// payload, which is compData if non-nil or data otherwise.func msgHeader(, mem.BufferSlice, payloadFormat) ( []byte, mem.BufferSlice) { = make([]byte, headerLen) [0] = byte()varuint32if .isCompressed() { = uint32(.Len()) = } else { = uint32(.Len()) = }// Write length of payload into bufbinary.BigEndian.PutUint32([payloadLen:], )return , }func outPayload( bool, any, , int, time.Time) *stats.OutPayload {return &stats.OutPayload{Client: ,Payload: ,Length: ,WireLength: + headerLen,CompressedLength: ,SentTime: , }}func checkRecvPayload( payloadFormat, string, bool, bool) *status.Status {switch {casecompressionNone:casecompressionMade:if == "" || == encoding.Identity {returnstatus.New(codes.Internal, "grpc: compressed flag set with identity or empty encoding") }if ! {if {returnstatus.Newf(codes.Unimplemented, "grpc: Decompressor is not installed for grpc-encoding %q", ) }returnstatus.Newf(codes.Internal, "grpc: Decompressor is not installed for grpc-encoding %q", ) }default:returnstatus.Newf(codes.Internal, "grpc: received unexpected payload format %d", ) }returnnil}type payloadInfo struct { compressedLength int// The compressed length got from wire. uncompressedBytes mem.BufferSlice}func ( *payloadInfo) () {if != nil && .uncompressedBytes != nil { .uncompressedBytes.Free() }}// recvAndDecompress reads a message from the stream, decompressing it if necessary.//// Cancelling the returned cancel function releases the buffer back to the pool. So the caller should cancel as soon as// the buffer is no longer needed.// TODO: Refactor this function to reduce the number of arguments.// See: https://google.github.io/styleguide/go/best-practices.html#function-argument-listsfunc recvAndDecompress( *parser, recvCompressor, Decompressor, int, *payloadInfo, encoding.Compressor, bool,) ( mem.BufferSlice, error) { , , := .recvMsg()if != nil {returnnil, } := .Len()if := checkRecvPayload(, .RecvCompress(), != nil || != nil, ); != nil { .Free()returnnil, .Err() }if .isCompressed() {defer .Free()// To match legacy behavior, if the decompressor is set by WithDecompressor or RPCDecompressor, // use this decompressor as the default. , = decompress(, , , , .bufferPool)if != nil {returnnil, } } else { = }if != nil { .compressedLength = .Ref() .uncompressedBytes = }return , nil}// decompress processes the given data by decompressing it using either a custom decompressor or a standard compressor.// If a custom decompressor is provided, it takes precedence. The function validates that the decompressed data// does not exceed the specified maximum size and returns an error if this limit is exceeded.// On success, it returns the decompressed data. Otherwise, it returns an error if decompression fails or the data exceeds the size limit.func decompress( encoding.Compressor, mem.BufferSlice, Decompressor, int, mem.BufferPool) (mem.BufferSlice, error) {if != nil { , := .Do(.Reader())if != nil {returnnil, status.Errorf(codes.Internal, "grpc: failed to decompress the received message: %v", ) }iflen() > {returnnil, status.Errorf(codes.ResourceExhausted, "grpc: message after decompression larger than max (%d vs. %d)", len(), ) }returnmem.BufferSlice{mem.SliceBuffer()}, nil }if != nil { , := .Decompress(.Reader())if != nil {returnnil, status.Errorf(codes.Internal, "grpc: failed to decompress the message: %v", ) }// Read at most one byte more than the limit from the decompressor. // Unless the limit is MaxInt64, in which case, that's impossible, so // apply no limit.if := int64(); < math.MaxInt64 { = io.LimitReader(, +1) } , := mem.ReadAll(, )if != nil { .Free()returnnil, status.Errorf(codes.Internal, "grpc: failed to read decompressed data: %v", ) }if .Len() > { .Free()returnnil, status.Errorf(codes.ResourceExhausted, "grpc: received message after decompression larger than max %d", ) }return , nil }returnnil, status.Errorf(codes.Internal, "grpc: no decompressor available for compressed payload")}type recvCompressor interface { RecvCompress() string}// For the two compressor parameters, both should not be set, but if they are,// dc takes precedence over compressor.// TODO(dfawley): wrap the old compressor/decompressor using the new API?func recv( *parser, baseCodec, recvCompressor, Decompressor, any, int, *payloadInfo, encoding.Compressor, bool) error { , := recvAndDecompress(, , , , , , )if != nil {return }// If the codec wants its own reference to the data, it can get it. Otherwise, always // free the buffers.defer .Free()if := .Unmarshal(, ); != nil {returnstatus.Errorf(codes.Internal, "grpc: failed to unmarshal the received message: %v", ) }returnnil}// Information about RPCtype rpcInfo struct { failfast bool preloaderInfo *compressorInfo}// Information about Preloader// Responsible for storing codec, and compressors// If stream (s) has context s.Context which stores rpcInfo that has non nil// pointers to codec, and compressors, then we can use preparedMsg for Async message prep// and reuse marshalled bytestype compressorInfo struct { codec baseCodec cp Compressor comp encoding.Compressor}type rpcInfoContextKey struct{}func newContextWithRPCInfo( context.Context, bool, baseCodec, Compressor, encoding.Compressor) context.Context {returncontext.WithValue(, rpcInfoContextKey{}, &rpcInfo{failfast: ,preloaderInfo: &compressorInfo{codec: ,cp: ,comp: , }, })}func rpcInfoFromContext( context.Context) ( *rpcInfo, bool) { , = .Value(rpcInfoContextKey{}).(*rpcInfo)return}// Code returns the error code for err if it was produced by the rpc system.// Otherwise, it returns codes.Unknown.//// Deprecated: use status.Code instead.func ( error) codes.Code {returnstatus.Code()}// ErrorDesc returns the error description of err if it was produced by the rpc system.// Otherwise, it returns err.Error() or empty string when err is nil.//// Deprecated: use status.Convert and Message method instead.func ( error) string {returnstatus.Convert().Message()}// Errorf returns an error containing an error code and a description;// Errorf returns nil if c is OK.//// Deprecated: use status.Errorf instead.func ( codes.Code, string, ...any) error {returnstatus.Errorf(, , ...)}var errContextCanceled = status.Error(codes.Canceled, context.Canceled.Error())var errContextDeadline = status.Error(codes.DeadlineExceeded, context.DeadlineExceeded.Error())// toRPCErr converts an error into an error from the status package.func toRPCErr( error) error {switch {casenil, io.EOF:returncasecontext.DeadlineExceeded:returnerrContextDeadlinecasecontext.Canceled:returnerrContextCanceledcaseio.ErrUnexpectedEOF:returnstatus.Error(codes.Internal, .Error()) }switch e := .(type) {casetransport.ConnectionError:returnstatus.Error(codes.Unavailable, .Desc)case *transport.NewStreamError:return (.Err) }if , := status.FromError(); {return }returnstatus.Error(codes.Unknown, .Error())}// setCallInfoCodec should only be called after CallOptions have been applied.func setCallInfoCodec( *callInfo) error {if .codec != nil {// codec was already set by a CallOption; use it, but set the content // subtype if it is not set.if .contentSubtype == "" {// c.codec is a baseCodec to hide the difference between grpc.Codec and // encoding.Codec (Name vs. String method name). We only support // setting content subtype from encoding.Codec to avoid a behavior // change with the deprecated version.if , := .codec.(encoding.CodecV2); { .contentSubtype = strings.ToLower(.Name()) } }returnnil }if .contentSubtype == "" {// No codec specified in CallOptions; use proto by default. .codec = getCodec(proto.Name)returnnil }// c.contentSubtype is already lowercased in CallContentSubtype .codec = getCodec(.contentSubtype)if .codec == nil {returnstatus.Errorf(codes.Internal, "no codec registered for content-subtype %s", .contentSubtype) }returnnil}// The SupportPackageIsVersion variables are referenced from generated protocol// buffer files to ensure compatibility with the gRPC version used. The latest// support package version is 9.//// Older versions are kept for compatibility.//// These constants should not be referenced from any other code.const (SupportPackageIsVersion3 = trueSupportPackageIsVersion4 = trueSupportPackageIsVersion5 = trueSupportPackageIsVersion6 = trueSupportPackageIsVersion7 = trueSupportPackageIsVersion8 = trueSupportPackageIsVersion9 = true)const grpcUA = "grpc-go/" + Version
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.