@@ -33,6 +33,8 @@ import (
3333 "google.golang.org/grpc/credentials"
3434 "google.golang.org/grpc/encoding"
3535 "google.golang.org/grpc/encoding/proto"
36+ "google.golang.org/grpc/internal"
37+ "google.golang.org/grpc/internal/grpcutil"
3638 "google.golang.org/grpc/internal/transport"
3739 "google.golang.org/grpc/mem"
3840 "google.golang.org/grpc/metadata"
@@ -41,6 +43,10 @@ import (
4143 "google.golang.org/grpc/status"
4244)
4345
46+ func init () {
47+ internal .AcceptCompressors = acceptCompressors
48+ }
49+
4450// Compressor defines the interface gRPC uses to compress a message.
4551//
4652// Deprecated: use package encoding.
@@ -151,16 +157,32 @@ func (d *gzipDecompressor) Type() string {
151157
152158// callInfo contains all related configuration and information about an RPC.
153159type callInfo struct {
154- compressorName string
155- failFast bool
156- maxReceiveMessageSize * int
157- maxSendMessageSize * int
158- creds credentials.PerRPCCredentials
159- contentSubtype string
160- codec baseCodec
161- maxRetryRPCBufferSize int
162- onFinish []func (err error )
163- authority string
160+ compressorName string
161+ failFast bool
162+ maxReceiveMessageSize * int
163+ maxSendMessageSize * int
164+ creds credentials.PerRPCCredentials
165+ contentSubtype string
166+ codec baseCodec
167+ maxRetryRPCBufferSize int
168+ onFinish []func (err error )
169+ authority string
170+ acceptedResponseCompressors []string
171+ }
172+
173+ func acceptedCompressorAllows (allowed []string , name string ) bool {
174+ if allowed == nil {
175+ return true
176+ }
177+ if name == "" || name == encoding .Identity {
178+ return true
179+ }
180+ for _ , a := range allowed {
181+ if a == name {
182+ return true
183+ }
184+ }
185+ return false
164186}
165187
166188func defaultCallInfo () * callInfo {
@@ -170,6 +192,29 @@ func defaultCallInfo() *callInfo {
170192 }
171193}
172194
195+ func newAcceptedCompressionConfig (names []string ) ([]string , error ) {
196+ if len (names ) == 0 {
197+ return nil , nil
198+ }
199+ var allowed []string
200+ seen := make (map [string ]struct {}, len (names ))
201+ for _ , name := range names {
202+ name = strings .TrimSpace (name )
203+ if name == "" || name == encoding .Identity {
204+ continue
205+ }
206+ if ! grpcutil .IsCompressorNameRegistered (name ) {
207+ return nil , status .Errorf (codes .InvalidArgument , "grpc: compressor %q is not registered" , name )
208+ }
209+ if _ , dup := seen [name ]; dup {
210+ continue
211+ }
212+ seen [name ] = struct {}{}
213+ allowed = append (allowed , name )
214+ }
215+ return allowed , nil
216+ }
217+
173218// CallOption configures a Call before it starts or extracts information from
174219// a Call after it completes.
175220type CallOption interface {
@@ -471,6 +516,31 @@ func (o CompressorCallOption) before(c *callInfo) error {
471516}
472517func (o CompressorCallOption ) after (* callInfo , * csAttempt ) {}
473518
519+ // acceptCompressors returns a CallOption that limits the compression algorithms
520+ // advertised in the grpc-accept-encoding header for response messages.
521+ // Compression algorithms not in the provided list will not be advertised, and
522+ // responses compressed with non-listed algorithms will be rejected.
523+ func acceptCompressors (names ... string ) CallOption {
524+ cp := append ([]string (nil ), names ... )
525+ return acceptCompressorsCallOption {names : cp }
526+ }
527+
528+ // acceptCompressorsCallOption is a CallOption that limits response compression.
529+ type acceptCompressorsCallOption struct {
530+ names []string
531+ }
532+
533+ func (o acceptCompressorsCallOption ) before (c * callInfo ) error {
534+ allowed , err := newAcceptedCompressionConfig (o .names )
535+ if err != nil {
536+ return err
537+ }
538+ c .acceptedResponseCompressors = allowed
539+ return nil
540+ }
541+
542+ func (acceptCompressorsCallOption ) after (* callInfo , * csAttempt ) {}
543+
474544// CallContentSubtype returns a CallOption that will set the content-subtype
475545// for a call. For example, if content-subtype is "json", the Content-Type over
476546// the wire will be "application/grpc+json". The content-subtype is converted
@@ -857,8 +927,7 @@ func (p *payloadInfo) free() {
857927// the buffer is no longer needed.
858928// TODO: Refactor this function to reduce the number of arguments.
859929// See: https://google.github.io/styleguide/go/best-practices.html#function-argument-lists
860- func recvAndDecompress (p * parser , s recvCompressor , dc Decompressor , maxReceiveMessageSize int , payInfo * payloadInfo , compressor encoding.Compressor , isServer bool ,
861- ) (out mem.BufferSlice , err error ) {
930+ func recvAndDecompress (p * parser , s recvCompressor , dc Decompressor , maxReceiveMessageSize int , payInfo * payloadInfo , compressor encoding.Compressor , isServer bool ) (out mem.BufferSlice , err error ) {
862931 pf , compressed , err := p .recvMsg (maxReceiveMessageSize )
863932 if err != nil {
864933 return nil , err
0 commit comments