mirror of https://github.com/grpc/grpc-node.git
Merge pull request #2772 from murgatroid99/grpc-js_cardinality_error_hang
grpc-js: Fix client hang when receiving extra messages for a unary response
This commit is contained in:
commit
52fe8e94e7
|
@ -330,7 +330,7 @@ export class Client {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
onReceiveMessage(message: any) {
|
onReceiveMessage(message: any) {
|
||||||
if (responseMessage !== null) {
|
if (responseMessage !== null) {
|
||||||
call.cancelWithStatus(Status.INTERNAL, 'Too many responses received');
|
call.cancelWithStatus(Status.UNIMPLEMENTED, 'Too many responses received');
|
||||||
}
|
}
|
||||||
responseMessage = message;
|
responseMessage = message;
|
||||||
},
|
},
|
||||||
|
@ -345,7 +345,7 @@ export class Client {
|
||||||
callProperties.callback!(
|
callProperties.callback!(
|
||||||
callErrorFromStatus(
|
callErrorFromStatus(
|
||||||
{
|
{
|
||||||
code: Status.INTERNAL,
|
code: Status.UNIMPLEMENTED,
|
||||||
details: 'No message received',
|
details: 'No message received',
|
||||||
metadata: status.metadata,
|
metadata: status.metadata,
|
||||||
},
|
},
|
||||||
|
@ -463,9 +463,10 @@ export class Client {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
onReceiveMessage(message: any) {
|
onReceiveMessage(message: any) {
|
||||||
if (responseMessage !== null) {
|
if (responseMessage !== null) {
|
||||||
call.cancelWithStatus(Status.INTERNAL, 'Too many responses received');
|
call.cancelWithStatus(Status.UNIMPLEMENTED, 'Too many responses received');
|
||||||
}
|
}
|
||||||
responseMessage = message;
|
responseMessage = message;
|
||||||
|
call.startRead();
|
||||||
},
|
},
|
||||||
onReceiveStatus(status: StatusObject) {
|
onReceiveStatus(status: StatusObject) {
|
||||||
if (receivedStatus) {
|
if (receivedStatus) {
|
||||||
|
@ -478,7 +479,7 @@ export class Client {
|
||||||
callProperties.callback!(
|
callProperties.callback!(
|
||||||
callErrorFromStatus(
|
callErrorFromStatus(
|
||||||
{
|
{
|
||||||
code: Status.INTERNAL,
|
code: Status.UNIMPLEMENTED,
|
||||||
details: 'No message received',
|
details: 'No message received',
|
||||||
metadata: status.metadata,
|
metadata: status.metadata,
|
||||||
},
|
},
|
||||||
|
|
|
@ -287,6 +287,98 @@ describe('Server serialization failure handling', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Cardinality violations', () => {
|
||||||
|
let client: ServiceClient;
|
||||||
|
let server: Server;
|
||||||
|
let responseCount: number = 1;
|
||||||
|
const testMessage = Buffer.from([]);
|
||||||
|
before(done => {
|
||||||
|
const serverServiceDefinition = {
|
||||||
|
testMethod: {
|
||||||
|
path: '/TestService/TestMethod/',
|
||||||
|
requestStream: false,
|
||||||
|
responseStream: true,
|
||||||
|
requestSerialize: identity,
|
||||||
|
requestDeserialize: identity,
|
||||||
|
responseDeserialize: identity,
|
||||||
|
responseSerialize: identity
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const clientServiceDefinition = {
|
||||||
|
testMethod: {
|
||||||
|
path: '/TestService/TestMethod/',
|
||||||
|
requestStream: true,
|
||||||
|
responseStream: false,
|
||||||
|
requestSerialize: identity,
|
||||||
|
requestDeserialize: identity,
|
||||||
|
responseDeserialize: identity,
|
||||||
|
responseSerialize: identity
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const TestClient = grpc.makeClientConstructor(clientServiceDefinition, 'TestService');
|
||||||
|
server = new grpc.Server();
|
||||||
|
server.addService(serverServiceDefinition, {
|
||||||
|
testMethod(stream: ServerWritableStream<any, any>) {
|
||||||
|
for (let i = 0; i < responseCount; i++) {
|
||||||
|
stream.write(testMessage);
|
||||||
|
}
|
||||||
|
stream.end();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
server.bindAsync('localhost:0', serverInsecureCreds, (error, port) => {
|
||||||
|
assert.ifError(error);
|
||||||
|
client = new TestClient(`localhost:${port}`, clientInsecureCreds);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
beforeEach(() => {
|
||||||
|
responseCount = 1;
|
||||||
|
});
|
||||||
|
after(done => {
|
||||||
|
client.close();
|
||||||
|
server.tryShutdown(done);
|
||||||
|
});
|
||||||
|
it('Should fail if the client sends too few messages', done => {
|
||||||
|
const call = client.testMethod((err: ServiceError, data: any) => {
|
||||||
|
assert(err);
|
||||||
|
assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
call.end();
|
||||||
|
});
|
||||||
|
it('Should fail if the client sends too many messages', done => {
|
||||||
|
const call = client.testMethod((err: ServiceError, data: any) => {
|
||||||
|
assert(err);
|
||||||
|
assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
call.write(testMessage);
|
||||||
|
call.write(testMessage);
|
||||||
|
call.end();
|
||||||
|
});
|
||||||
|
it('Should fail if the server sends too few messages', done => {
|
||||||
|
responseCount = 0;
|
||||||
|
const call = client.testMethod((err: ServiceError, data: any) => {
|
||||||
|
assert(err);
|
||||||
|
assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
call.write(testMessage);
|
||||||
|
call.end();
|
||||||
|
});
|
||||||
|
it('Should fail if the server sends too many messages', done => {
|
||||||
|
responseCount = 2;
|
||||||
|
const call = client.testMethod((err: ServiceError, data: any) => {
|
||||||
|
assert(err);
|
||||||
|
assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
call.write(testMessage);
|
||||||
|
call.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('Other conditions', () => {
|
describe('Other conditions', () => {
|
||||||
let client: ServiceClient;
|
let client: ServiceClient;
|
||||||
let server: Server;
|
let server: Server;
|
||||||
|
|
Loading…
Reference in New Issue