Skip to content

Commit 7346a18

Browse files
authored
Merge pull request #2877 from grpc/@grpc/[email protected]
Merge grpc-js 1.12.x into master
2 parents 263c478 + bae98b3 commit 7346a18

File tree

4 files changed

+54
-20
lines changed

4 files changed

+54
-20
lines changed

packages/grpc-js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@grpc/grpc-js",
3-
"version": "1.12.1",
3+
"version": "1.12.5",
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/certificate-provider.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
*
1616
*/
1717

18-
import * as fs from 'fs/promises';
18+
import * as fs from 'fs';
1919
import * as logging from './logging';
2020
import { LogVerbosity } from './constants';
21+
import { promisify } from 'util';
2122

2223
const TRACER_NAME = 'certificate_provider';
2324

@@ -56,6 +57,8 @@ export interface FileWatcherCertificateProviderConfig {
5657
refreshIntervalMs: number;
5758
}
5859

60+
const readFilePromise = promisify(fs.readFile);
61+
5962
export class FileWatcherCertificateProvider implements CertificateProvider {
6063
private refreshTimer: NodeJS.Timeout | null = null;
6164
private fileResultPromise: Promise<[PromiseSettledResult<Buffer>, PromiseSettledResult<Buffer>, PromiseSettledResult<Buffer>]> | null = null;
@@ -82,9 +85,9 @@ export class FileWatcherCertificateProvider implements CertificateProvider {
8285
return;
8386
}
8487
this.fileResultPromise = Promise.allSettled([
85-
this.config.certificateFile ? fs.readFile(this.config.certificateFile) : Promise.reject<Buffer>(),
86-
this.config.privateKeyFile ? fs.readFile(this.config.privateKeyFile) : Promise.reject<Buffer>(),
87-
this.config.caCertificateFile ? fs.readFile(this.config.caCertificateFile) : Promise.reject<Buffer>()
88+
this.config.certificateFile ? readFilePromise(this.config.certificateFile) : Promise.reject<Buffer>(),
89+
this.config.privateKeyFile ? readFilePromise(this.config.privateKeyFile) : Promise.reject<Buffer>(),
90+
this.config.caCertificateFile ? readFilePromise(this.config.caCertificateFile) : Promise.reject<Buffer>()
8891
]);
8992
this.fileResultPromise.then(([certificateResult, privateKeyResult, caCertificateResult]) => {
9093
if (!this.refreshTimer) {

packages/grpc-js/src/subchannel-call.ts

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ export class Http2SubchannelCall implements SubchannelCall {
140140

141141
private serverEndedCall = false;
142142

143+
private connectionDropped = false;
144+
143145
constructor(
144146
private readonly http2Stream: http2.ClientHttp2Stream,
145147
private readonly callEventTracker: CallEventTracker,
@@ -188,7 +190,22 @@ export class Http2SubchannelCall implements SubchannelCall {
188190
try {
189191
messages = this.decoder.write(data);
190192
} catch (e) {
191-
this.cancelWithStatus(Status.RESOURCE_EXHAUSTED, (e as Error).message);
193+
/* Some servers send HTML error pages along with HTTP status codes.
194+
* When the client attempts to parse this as a length-delimited
195+
* message, the parsed message size is greater than the default limit,
196+
* resulting in a message decoding error. In that situation, the HTTP
197+
* error code information is more useful to the user than the
198+
* RESOURCE_EXHAUSTED error is, so we report that instead. Normally,
199+
* we delay processing the HTTP status until after the stream ends, to
200+
* prioritize reporting the gRPC status from trailers if it is present,
201+
* but when there is a message parsing error we end the stream early
202+
* before processing trailers. */
203+
if (this.httpStatusCode !== undefined && this.httpStatusCode !== 200) {
204+
const mappedStatus = mapHttpStatusCode(this.httpStatusCode);
205+
this.cancelWithStatus(mappedStatus.code, mappedStatus.details);
206+
} else {
207+
this.cancelWithStatus(Status.RESOURCE_EXHAUSTED, (e as Error).message);
208+
}
192209
return;
193210
}
194211

@@ -240,8 +257,16 @@ export class Http2SubchannelCall implements SubchannelCall {
240257
details = 'Stream refused by server';
241258
break;
242259
case http2.constants.NGHTTP2_CANCEL:
243-
code = Status.CANCELLED;
244-
details = 'Call cancelled';
260+
/* Bug reports indicate that Node synthesizes a NGHTTP2_CANCEL
261+
* code from connection drops. We want to prioritize reporting
262+
* an unavailable status when that happens. */
263+
if (this.connectionDropped) {
264+
code = Status.UNAVAILABLE;
265+
details = 'Connection dropped';
266+
} else {
267+
code = Status.CANCELLED;
268+
details = 'Call cancelled';
269+
}
245270
break;
246271
case http2.constants.NGHTTP2_ENHANCE_YOUR_CALM:
247272
code = Status.RESOURCE_EXHAUSTED;
@@ -321,10 +346,15 @@ export class Http2SubchannelCall implements SubchannelCall {
321346
}
322347

323348
public onDisconnect() {
324-
this.endCall({
325-
code: Status.UNAVAILABLE,
326-
details: 'Connection dropped',
327-
metadata: new Metadata(),
349+
this.connectionDropped = true;
350+
/* Give the call an event loop cycle to finish naturally before reporting
351+
* the disconnection as an error. */
352+
setImmediate(() => {
353+
this.endCall({
354+
code: Status.UNAVAILABLE,
355+
details: 'Connection dropped',
356+
metadata: new Metadata(),
357+
});
328358
});
329359
}
330360

packages/grpc-js/src/transport.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ class Http2Transport implements Transport {
225225
this.handleDisconnect();
226226
});
227227

228+
session.socket.once('close', () => {
229+
this.trace('connection closed');
230+
this.handleDisconnect();
231+
});
232+
228233
if (logging.isTracerEnabled(TRACER_NAME)) {
229234
session.on('remoteSettings', (settings: http2.Settings) => {
230235
this.trace(
@@ -380,17 +385,13 @@ class Http2Transport implements Transport {
380385
* Handle connection drops, but not GOAWAYs.
381386
*/
382387
private handleDisconnect() {
383-
if (this.disconnectHandled) {
384-
return;
385-
}
386388
this.clearKeepaliveTimeout();
387389
this.reportDisconnectToOwner(false);
388-
/* Give calls an event loop cycle to finish naturally before reporting the
389-
* disconnnection to them. */
390+
for (const call of this.activeCalls) {
391+
call.onDisconnect();
392+
}
393+
// Wait an event loop cycle before destroying the connection
390394
setImmediate(() => {
391-
for (const call of this.activeCalls) {
392-
call.onDisconnect();
393-
}
394395
this.session.destroy();
395396
});
396397
}

0 commit comments

Comments
 (0)