Skip to content

Commit 15a3f1a

Browse files
authored
Merge pull request #2528 from murgatroid99/grpc-js_unimplemented_message_fix
grpc-js: Fix propagation of UNIMPLEMENTED error messages
2 parents 51d6163 + 4e111e7 commit 15a3f1a

File tree

3 files changed

+106
-24
lines changed

3 files changed

+106
-24
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.8.20",
3+
"version": "1.8.21",
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/server.ts

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ import {
6161
import { parseUri } from './uri-parser';
6262
import { ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzServer, registerChannelzSocket, ServerInfo, ServerRef, SocketInfo, SocketRef, TlsInfo, unregisterChannelzRef } from './channelz';
6363
import { CipherNameAndProtocol, TLSSocket } from 'tls';
64-
import { getErrorCode, getErrorMessage } from './error';
6564

6665
const UNLIMITED_CONNECTION_AGE_MS = ~(1<<31);
6766
const KEEPALIVE_MAX_TIME_MS = ~(1<<31);
@@ -765,9 +764,7 @@ export class Server {
765764
return true
766765
}
767766

768-
private _retrieveHandler(headers: http2.IncomingHttpHeaders): Handler<any, any> {
769-
const path = headers[HTTP2_HEADER_PATH] as string
770-
767+
private _retrieveHandler(path: string): Handler<any, any> | null {
771768
this.trace(
772769
'Received call to method ' +
773770
path +
@@ -783,7 +780,7 @@ export class Server {
783780
path +
784781
'. Sending UNIMPLEMENTED status.'
785782
);
786-
throw getUnimplementedStatusResponse(path);
783+
return null;
787784
}
788785

789786
return handler
@@ -820,15 +817,12 @@ export class Server {
820817
return
821818
}
822819

823-
let handler: Handler<any, any>
824-
try {
825-
handler = this._retrieveHandler(headers)
826-
} catch (err) {
827-
this._respondWithError({
828-
details: getErrorMessage(err),
829-
code: getErrorCode(err) ?? undefined
830-
}, stream, channelzSessionInfo)
831-
return
820+
const path = headers[HTTP2_HEADER_PATH] as string;
821+
822+
const handler = this._retrieveHandler(path);
823+
if (!handler) {
824+
this._respondWithError(getUnimplementedStatusResponse(path), stream, channelzSessionInfo);
825+
return;
832826
}
833827

834828
const call = new Http2ServerCallStream(stream, handler, this.options);
@@ -875,15 +869,13 @@ export class Server {
875869
return
876870
}
877871

878-
let handler: Handler<any, any>
879-
try {
880-
handler = this._retrieveHandler(headers)
881-
} catch (err) {
882-
this._respondWithError({
883-
details: getErrorMessage(err),
884-
code: getErrorCode(err) ?? undefined
885-
}, stream, null)
886-
return
872+
873+
const path = headers[HTTP2_HEADER_PATH] as string;
874+
875+
const handler = this._retrieveHandler(path);
876+
if (!handler) {
877+
this._respondWithError(getUnimplementedStatusResponse(path), stream, null);
878+
return;
887879
}
888880

889881
const call = new Http2ServerCallStream(stream, handler, this.options)

packages/grpc-js/test/test-server.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ describe('Server', () => {
408408
(error: ServiceError, response: any) => {
409409
assert(error);
410410
assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
411+
assert.match(error.details, /does not implement the method.*Div/);
411412
done();
412413
}
413414
);
@@ -417,6 +418,7 @@ describe('Server', () => {
417418
const call = client.sum((error: ServiceError, response: any) => {
418419
assert(error);
419420
assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
421+
assert.match(error.details, /does not implement the method.*Sum/);
420422
done();
421423
});
422424

@@ -433,6 +435,7 @@ describe('Server', () => {
433435
call.on('error', (err: ServiceError) => {
434436
assert(err);
435437
assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
438+
assert.match(err.details, /does not implement the method.*Fib/);
436439
done();
437440
});
438441
});
@@ -447,6 +450,93 @@ describe('Server', () => {
447450
call.on('error', (err: ServiceError) => {
448451
assert(err);
449452
assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
453+
assert.match(err.details, /does not implement the method.*DivMany/);
454+
done();
455+
});
456+
457+
call.end();
458+
});
459+
});
460+
461+
describe('Unregistered service', () => {
462+
let server: Server;
463+
let client: ServiceClient;
464+
465+
const mathProtoFile = path.join(__dirname, 'fixtures', 'math.proto');
466+
const mathClient = (loadProtoFile(mathProtoFile).math as any).Math;
467+
468+
before(done => {
469+
server = new Server();
470+
// Don't register a service at all
471+
server.bindAsync(
472+
'localhost:0',
473+
ServerCredentials.createInsecure(),
474+
(err, port) => {
475+
assert.ifError(err);
476+
client = new mathClient(
477+
`localhost:${port}`,
478+
grpc.credentials.createInsecure()
479+
);
480+
server.start();
481+
done();
482+
}
483+
);
484+
});
485+
486+
after(done => {
487+
client.close();
488+
server.tryShutdown(done);
489+
});
490+
491+
it('should respond to a unary call with UNIMPLEMENTED', done => {
492+
client.div(
493+
{ divisor: 4, dividend: 3 },
494+
(error: ServiceError, response: any) => {
495+
assert(error);
496+
assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
497+
assert.match(error.details, /does not implement the method.*Div/);
498+
done();
499+
}
500+
);
501+
});
502+
503+
it('should respond to a client stream with UNIMPLEMENTED', done => {
504+
const call = client.sum((error: ServiceError, response: any) => {
505+
assert(error);
506+
assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
507+
assert.match(error.details, /does not implement the method.*Sum/);
508+
done();
509+
});
510+
511+
call.end();
512+
});
513+
514+
it('should respond to a server stream with UNIMPLEMENTED', done => {
515+
const call = client.fib({ limit: 5 });
516+
517+
call.on('data', (value: any) => {
518+
assert.fail('No messages expected');
519+
});
520+
521+
call.on('error', (err: ServiceError) => {
522+
assert(err);
523+
assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
524+
assert.match(err.details, /does not implement the method.*Fib/);
525+
done();
526+
});
527+
});
528+
529+
it('should respond to a bidi call with UNIMPLEMENTED', done => {
530+
const call = client.divMany();
531+
532+
call.on('data', (value: any) => {
533+
assert.fail('No messages expected');
534+
});
535+
536+
call.on('error', (err: ServiceError) => {
537+
assert(err);
538+
assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
539+
assert.match(err.details, /does not implement the method.*DivMany/);
450540
done();
451541
});
452542

0 commit comments

Comments
 (0)