Skip to content

Commit b35896b

Browse files
authored
Merge pull request #2792 from murgatroid99/grpc-js_1.10.11_upmerge
grpc-js: Merge 1.10.x branch into master
2 parents f867643 + 9ea4187 commit b35896b

15 files changed

+603
-314
lines changed

packages/grpc-js/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@grpc/grpc-js",
3-
"version": "1.10.8",
3+
"version": "1.10.11",
44
"description": "gRPC Library for Node - pure JS implementation",
55
"homepage": "https://grpc.io/",
66
"repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js",

packages/grpc-js/src/client.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ export class Client {
330330
// eslint-disable-next-line @typescript-eslint/no-explicit-any
331331
onReceiveMessage(message: any) {
332332
if (responseMessage !== null) {
333-
call.cancelWithStatus(Status.INTERNAL, 'Too many responses received');
333+
call.cancelWithStatus(Status.UNIMPLEMENTED, 'Too many responses received');
334334
}
335335
responseMessage = message;
336336
},
@@ -345,7 +345,7 @@ export class Client {
345345
callProperties.callback!(
346346
callErrorFromStatus(
347347
{
348-
code: Status.INTERNAL,
348+
code: Status.UNIMPLEMENTED,
349349
details: 'No message received',
350350
metadata: status.metadata,
351351
},
@@ -463,9 +463,10 @@ export class Client {
463463
// eslint-disable-next-line @typescript-eslint/no-explicit-any
464464
onReceiveMessage(message: any) {
465465
if (responseMessage !== null) {
466-
call.cancelWithStatus(Status.INTERNAL, 'Too many responses received');
466+
call.cancelWithStatus(Status.UNIMPLEMENTED, 'Too many responses received');
467467
}
468468
responseMessage = message;
469+
call.startRead();
469470
},
470471
onReceiveStatus(status: StatusObject) {
471472
if (receivedStatus) {
@@ -478,7 +479,7 @@ export class Client {
478479
callProperties.callback!(
479480
callErrorFromStatus(
480481
{
481-
code: Status.INTERNAL,
482+
code: Status.UNIMPLEMENTED,
482483
details: 'No message received',
483484
metadata: status.metadata,
484485
},

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

+59-16
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { WriteObject, WriteFlags } from './call-interface';
2121
import { Channel } from './channel';
2222
import { ChannelOptions } from './channel-options';
2323
import { CompressionAlgorithms } from './compression-algorithms';
24-
import { LogVerbosity } from './constants';
24+
import { DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, DEFAULT_MAX_SEND_MESSAGE_LENGTH, LogVerbosity, Status } from './constants';
2525
import { BaseFilter, Filter, FilterFactory } from './filter';
2626
import * as logging from './logging';
2727
import { Metadata, MetadataValue } from './metadata';
@@ -98,6 +98,10 @@ class IdentityHandler extends CompressionHandler {
9898
}
9999

100100
class DeflateHandler extends CompressionHandler {
101+
constructor(private maxRecvMessageLength: number) {
102+
super();
103+
}
104+
101105
compressMessage(message: Buffer) {
102106
return new Promise<Buffer>((resolve, reject) => {
103107
zlib.deflate(message, (err, output) => {
@@ -112,18 +116,34 @@ class DeflateHandler extends CompressionHandler {
112116

113117
decompressMessage(message: Buffer) {
114118
return new Promise<Buffer>((resolve, reject) => {
115-
zlib.inflate(message, (err, output) => {
116-
if (err) {
117-
reject(err);
118-
} else {
119-
resolve(output);
119+
let totalLength = 0;
120+
const messageParts: Buffer[] = [];
121+
const decompresser = zlib.createInflate();
122+
decompresser.on('data', (chunk: Buffer) => {
123+
messageParts.push(chunk);
124+
totalLength += chunk.byteLength;
125+
if (this.maxRecvMessageLength !== -1 && totalLength > this.maxRecvMessageLength) {
126+
decompresser.destroy();
127+
reject({
128+
code: Status.RESOURCE_EXHAUSTED,
129+
details: `Received message that decompresses to a size larger than ${this.maxRecvMessageLength}`
130+
});
120131
}
121132
});
133+
decompresser.on('end', () => {
134+
resolve(Buffer.concat(messageParts));
135+
});
136+
decompresser.write(message);
137+
decompresser.end();
122138
});
123139
}
124140
}
125141

126142
class GzipHandler extends CompressionHandler {
143+
constructor(private maxRecvMessageLength: number) {
144+
super();
145+
}
146+
127147
compressMessage(message: Buffer) {
128148
return new Promise<Buffer>((resolve, reject) => {
129149
zlib.gzip(message, (err, output) => {
@@ -138,13 +158,25 @@ class GzipHandler extends CompressionHandler {
138158

139159
decompressMessage(message: Buffer) {
140160
return new Promise<Buffer>((resolve, reject) => {
141-
zlib.unzip(message, (err, output) => {
142-
if (err) {
143-
reject(err);
144-
} else {
145-
resolve(output);
161+
let totalLength = 0;
162+
const messageParts: Buffer[] = [];
163+
const decompresser = zlib.createGunzip();
164+
decompresser.on('data', (chunk: Buffer) => {
165+
messageParts.push(chunk);
166+
totalLength += chunk.byteLength;
167+
if (this.maxRecvMessageLength !== -1 && totalLength > this.maxRecvMessageLength) {
168+
decompresser.destroy();
169+
reject({
170+
code: Status.RESOURCE_EXHAUSTED,
171+
details: `Received message that decompresses to a size larger than ${this.maxRecvMessageLength}`
172+
});
146173
}
147174
});
175+
decompresser.on('end', () => {
176+
resolve(Buffer.concat(messageParts));
177+
});
178+
decompresser.write(message);
179+
decompresser.end();
148180
});
149181
}
150182
}
@@ -169,14 +201,14 @@ class UnknownHandler extends CompressionHandler {
169201
}
170202
}
171203

172-
function getCompressionHandler(compressionName: string): CompressionHandler {
204+
function getCompressionHandler(compressionName: string, maxReceiveMessageSize: number): CompressionHandler {
173205
switch (compressionName) {
174206
case 'identity':
175207
return new IdentityHandler();
176208
case 'deflate':
177-
return new DeflateHandler();
209+
return new DeflateHandler(maxReceiveMessageSize);
178210
case 'gzip':
179-
return new GzipHandler();
211+
return new GzipHandler(maxReceiveMessageSize);
180212
default:
181213
return new UnknownHandler(compressionName);
182214
}
@@ -186,6 +218,8 @@ export class CompressionFilter extends BaseFilter implements Filter {
186218
private sendCompression: CompressionHandler = new IdentityHandler();
187219
private receiveCompression: CompressionHandler = new IdentityHandler();
188220
private currentCompressionAlgorithm: CompressionAlgorithm = 'identity';
221+
private maxReceiveMessageLength: number;
222+
private maxSendMessageLength: number;
189223

190224
constructor(
191225
channelOptions: ChannelOptions,
@@ -195,6 +229,8 @@ export class CompressionFilter extends BaseFilter implements Filter {
195229

196230
const compressionAlgorithmKey =
197231
channelOptions['grpc.default_compression_algorithm'];
232+
this.maxReceiveMessageLength = channelOptions['grpc.max_receive_message_length'] ?? DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH;
233+
this.maxSendMessageLength = channelOptions['grpc.max_send_message_length'] ?? DEFAULT_MAX_SEND_MESSAGE_LENGTH;
198234
if (compressionAlgorithmKey !== undefined) {
199235
if (isCompressionAlgorithmKey(compressionAlgorithmKey)) {
200236
const clientSelectedEncoding = CompressionAlgorithms[
@@ -215,7 +251,8 @@ export class CompressionFilter extends BaseFilter implements Filter {
215251
) {
216252
this.currentCompressionAlgorithm = clientSelectedEncoding;
217253
this.sendCompression = getCompressionHandler(
218-
this.currentCompressionAlgorithm
254+
this.currentCompressionAlgorithm,
255+
-1
219256
);
220257
}
221258
} else {
@@ -247,7 +284,7 @@ export class CompressionFilter extends BaseFilter implements Filter {
247284
if (receiveEncoding.length > 0) {
248285
const encoding: MetadataValue = receiveEncoding[0];
249286
if (typeof encoding === 'string') {
250-
this.receiveCompression = getCompressionHandler(encoding);
287+
this.receiveCompression = getCompressionHandler(encoding, this.maxReceiveMessageLength);
251288
}
252289
}
253290
metadata.remove('grpc-encoding');
@@ -279,6 +316,12 @@ export class CompressionFilter extends BaseFilter implements Filter {
279316
* and the output is a framed and possibly compressed message. For this
280317
* reason, this filter should be at the bottom of the filter stack */
281318
const resolvedMessage: WriteObject = await message;
319+
if (this.maxSendMessageLength !== -1 && resolvedMessage.message.length > this.maxSendMessageLength) {
320+
throw {
321+
code: Status.RESOURCE_EXHAUSTED,
322+
details: `Attempted to send message with a size larger than ${this.maxSendMessageLength}`
323+
};
324+
}
282325
let compress: boolean;
283326
if (this.sendCompression instanceof IdentityHandler) {
284327
compress = false;

packages/grpc-js/src/internal-channel.ts

+29-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { ChannelOptions } from './channel-options';
2020
import { ResolvingLoadBalancer } from './resolving-load-balancer';
2121
import { SubchannelPool, getSubchannelPool } from './subchannel-pool';
2222
import { ChannelControlHelper } from './load-balancer';
23-
import { UnavailablePicker, Picker, QueuePicker } from './picker';
23+
import { UnavailablePicker, Picker, QueuePicker, PickArgs, PickResult, PickResultType } from './picker';
2424
import { Metadata } from './metadata';
2525
import { Status, LogVerbosity, Propagate } from './constants';
2626
import { FilterStackFactory } from './filter-stack';
@@ -33,7 +33,6 @@ import {
3333
} from './resolver';
3434
import { trace } from './logging';
3535
import { SubchannelAddress } from './subchannel-address';
36-
import { MaxMessageSizeFilterFactory } from './max-message-size-filter';
3736
import { mapProxyName } from './http_proxy';
3837
import { GrpcUri, parseUri, uriToString } from './uri-parser';
3938
import { ServerSurfaceCall } from './server-call';
@@ -144,6 +143,22 @@ class ChannelSubchannelWrapper
144143
}
145144
}
146145

146+
class ShutdownPicker implements Picker {
147+
pick(pickArgs: PickArgs): PickResult {
148+
return {
149+
pickResultType: PickResultType.DROP,
150+
status: {
151+
code: Status.UNAVAILABLE,
152+
details: 'Channel closed before call started',
153+
metadata: new Metadata()
154+
},
155+
subchannel: null,
156+
onCallStarted: null,
157+
onCallEnded: null
158+
}
159+
}
160+
}
161+
147162
export class InternalChannel {
148163
private readonly resolvingLoadBalancer: ResolvingLoadBalancer;
149164
private readonly subchannelPool: SubchannelPool;
@@ -402,7 +417,6 @@ export class InternalChannel {
402417
}
403418
);
404419
this.filterStackFactory = new FilterStackFactory([
405-
new MaxMessageSizeFilterFactory(this.options),
406420
new CompressionFilterFactory(this, this.options),
407421
]);
408422
this.trace(
@@ -538,7 +552,9 @@ export class InternalChannel {
538552
}
539553

540554
getConfig(method: string, metadata: Metadata): GetConfigResult {
541-
this.resolvingLoadBalancer.exitIdle();
555+
if (this.connectivityState !== ConnectivityState.SHUTDOWN) {
556+
this.resolvingLoadBalancer.exitIdle();
557+
}
542558
if (this.configSelector) {
543559
return {
544560
type: 'SUCCESS',
@@ -747,6 +763,15 @@ export class InternalChannel {
747763
close() {
748764
this.resolvingLoadBalancer.destroy();
749765
this.updateState(ConnectivityState.SHUTDOWN);
766+
this.currentPicker = new ShutdownPicker();
767+
for (const call of this.configSelectionQueue) {
768+
call.cancelWithStatus(Status.UNAVAILABLE, 'Channel closed before call started');
769+
}
770+
this.configSelectionQueue = [];
771+
for (const call of this.pickQueue) {
772+
call.cancelWithStatus(Status.UNAVAILABLE, 'Channel closed before call started');
773+
}
774+
this.pickQueue = [];
750775
clearInterval(this.callRefTimer);
751776
if (this.idleTimer) {
752777
clearTimeout(this.idleTimer);

packages/grpc-js/src/load-balancer-pick-first.ts

+11-6
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
PickResultType,
3333
UnavailablePicker,
3434
} from './picker';
35-
import { Endpoint, SubchannelAddress } from './subchannel-address';
35+
import { Endpoint, SubchannelAddress, subchannelAddressToString } from './subchannel-address';
3636
import * as logging from './logging';
3737
import { LogVerbosity } from './constants';
3838
import {
@@ -348,7 +348,6 @@ export class PickFirstLoadBalancer implements LoadBalancer {
348348
if (newState !== ConnectivityState.READY) {
349349
this.removeCurrentPick();
350350
this.calculateAndReportNewState();
351-
this.requestReresolution();
352351
}
353352
return;
354353
}
@@ -483,6 +482,15 @@ export class PickFirstLoadBalancer implements LoadBalancer {
483482
subchannel: this.channelControlHelper.createSubchannel(address, {}),
484483
hasReportedTransientFailure: false,
485484
}));
485+
trace('connectToAddressList([' + addressList.map(address => subchannelAddressToString(address)) + '])');
486+
for (const { subchannel } of newChildrenList) {
487+
if (subchannel.getConnectivityState() === ConnectivityState.READY) {
488+
this.channelControlHelper.addChannelzChild(subchannel.getChannelzRef());
489+
subchannel.addConnectivityStateListener(this.subchannelStateListener);
490+
this.pickSubchannel(subchannel);
491+
return;
492+
}
493+
}
486494
/* Ref each subchannel before resetting the list, to ensure that
487495
* subchannels shared between the list don't drop to 0 refs during the
488496
* transition. */
@@ -494,10 +502,6 @@ export class PickFirstLoadBalancer implements LoadBalancer {
494502
this.children = newChildrenList;
495503
for (const { subchannel } of this.children) {
496504
subchannel.addConnectivityStateListener(this.subchannelStateListener);
497-
if (subchannel.getConnectivityState() === ConnectivityState.READY) {
498-
this.pickSubchannel(subchannel);
499-
return;
500-
}
501505
}
502506
for (const child of this.children) {
503507
if (
@@ -527,6 +531,7 @@ export class PickFirstLoadBalancer implements LoadBalancer {
527531
const rawAddressList = ([] as SubchannelAddress[]).concat(
528532
...endpointList.map(endpoint => endpoint.addresses)
529533
);
534+
trace('updateAddressList([' + rawAddressList.map(address => subchannelAddressToString(address)) + '])');
530535
if (rawAddressList.length === 0) {
531536
throw new Error('No addresses in endpoint list passed to pick_first');
532537
}

0 commit comments

Comments
 (0)