Skip to content

Commit c9659b5

Browse files
committed
persist server supported encoding header across compression filter instances
1 parent 53a2347 commit c9659b5

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

packages/grpc-js/src/compression-filter.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ const isCompressionAlgorithmKey = (key: number | undefined): key is keyof typeof
3434

3535
type CompressionAlgorithm = (typeof CompressionAlgorithms)[keyof typeof CompressionAlgorithms];
3636

37+
type SharedCompressionFilterConfig = {
38+
serverSupportedEncodingHeader?: string;
39+
};
40+
3741
abstract class CompressionHandler {
3842
protected abstract compressMessage(message: Buffer): Promise<Buffer>;
3943
protected abstract decompressMessage(data: Buffer): Promise<Buffer>;
@@ -181,14 +185,25 @@ export class CompressionFilter extends BaseFilter implements Filter {
181185
private receiveCompression: CompressionHandler = new IdentityHandler();
182186
private defaultCompressionAlgorithm: CompressionAlgorithm | undefined;
183187

184-
constructor(channelOptions: ChannelOptions) {
188+
constructor(channelOptions: ChannelOptions, private sharedFilterConfig: SharedCompressionFilterConfig) {
185189
super();
186190

191+
const serverSupportedEncodings = sharedFilterConfig.serverSupportedEncodingHeader?.split(',');
187192
const compressionAlgorithmKey = channelOptions['grpc.default_compression_algorithm'];
188193
if (compressionAlgorithmKey !== undefined) {
189194
if (isCompressionAlgorithmKey(compressionAlgorithmKey)) {
190-
this.defaultCompressionAlgorithm = CompressionAlgorithms[compressionAlgorithmKey];
191-
this.sendCompression = getCompressionHandler(this.defaultCompressionAlgorithm);
195+
const clientSelectedEncoding = CompressionAlgorithms[compressionAlgorithmKey];
196+
/**
197+
* There are two possible situations here:
198+
* 1) We don't have any info yet from the server about what compression it supports
199+
* In that case we should just use what the client tells us to use
200+
* 2) We've previously received a response from the server including a grpc-accept-encoding header
201+
* In that case we only want to use the encoding chosen by the client if the server supports it
202+
*/
203+
if (!serverSupportedEncodings || serverSupportedEncodings.includes(clientSelectedEncoding)) {
204+
this.defaultCompressionAlgorithm = clientSelectedEncoding;
205+
this.sendCompression = getCompressionHandler(this.defaultCompressionAlgorithm);
206+
}
192207
} else {
193208
logging.log(LogVerbosity.ERROR, `Invalid value provided for grpc.default_compression_algorithm option: ${compressionAlgorithmKey}`);
194209
}
@@ -223,6 +238,7 @@ export class CompressionFilter extends BaseFilter implements Filter {
223238
* If not, reset the sendCompression filter and have it use the default IdentityHandler */
224239
const serverSupportedEncodingsHeader = metadata.get('grpc-accept-encoding')[0] as string | undefined;
225240
if (serverSupportedEncodingsHeader) {
241+
this.sharedFilterConfig.serverSupportedEncodingHeader = serverSupportedEncodingsHeader;
226242
const serverSupportedEncodings = serverSupportedEncodingsHeader.split(',');
227243

228244
if ((this.sendCompression instanceof DeflateHandler && !serverSupportedEncodings.includes('deflate'))
@@ -263,8 +279,9 @@ export class CompressionFilter extends BaseFilter implements Filter {
263279

264280
export class CompressionFilterFactory
265281
implements FilterFactory<CompressionFilter> {
282+
private sharedFilterConfig: SharedCompressionFilterConfig = {};
266283
constructor(private readonly channel: Channel, private readonly options: ChannelOptions) {}
267284
createFilter(callStream: Call): CompressionFilter {
268-
return new CompressionFilter(this.options);
285+
return new CompressionFilter(this.options, this.sharedFilterConfig);
269286
}
270287
}

0 commit comments

Comments
 (0)