aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Michael Lumish <mlumish@google.com>2017-02-03 09:48:03 -0800
committerGravatar GitHub <noreply@github.com>2017-02-03 09:48:03 -0800
commitf35c449239d059afa42126b698421140609b4b2b (patch)
tree86a86626edf88db2bf8243fcb01fb68f3cd67b28
parentbb3edafea245a9780cc4c10f0b58da21e8193f38 (diff)
parent98673fa34981fd1ae1b532fb3e27f1596c223090 (diff)
Merge pull request #9567 from murgatroid99/node_serialization_error_handling_fix
Node: fix handling/propagation of server-side serialization errors
-rw-r--r--src/node/src/server.js24
-rw-r--r--src/node/test/surface_test.js107
2 files changed, 119 insertions, 12 deletions
diff --git a/src/node/src/server.js b/src/node/src/server.js
index d501e76c67..8a7eff507d 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -121,20 +121,20 @@ function sendUnaryResponse(call, value, serialize, metadata, flags) {
if (metadata) {
statusMetadata = metadata;
}
- status.metadata = statusMetadata._getCoreRepresentation();
- if (!call.metadataSent) {
- end_batch[grpc.opType.SEND_INITIAL_METADATA] =
- (new Metadata())._getCoreRepresentation();
- call.metadataSent = true;
- }
var message;
try {
message = serialize(value);
} catch (e) {
e.code = grpc.status.INTERNAL;
- handleError(e);
+ handleError(call, e);
return;
}
+ status.metadata = statusMetadata._getCoreRepresentation();
+ if (!call.metadataSent) {
+ end_batch[grpc.opType.SEND_INITIAL_METADATA] =
+ (new Metadata())._getCoreRepresentation();
+ call.metadataSent = true;
+ }
message.grpcWriteFlags = flags;
end_batch[grpc.opType.SEND_MESSAGE] = message;
end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
@@ -280,11 +280,6 @@ function _write(chunk, encoding, callback) {
/* jshint validthis: true */
var batch = {};
var self = this;
- if (!this.call.metadataSent) {
- batch[grpc.opType.SEND_INITIAL_METADATA] =
- (new Metadata())._getCoreRepresentation();
- this.call.metadataSent = true;
- }
var message;
try {
message = this.serialize(chunk);
@@ -293,6 +288,11 @@ function _write(chunk, encoding, callback) {
callback(e);
return;
}
+ if (!this.call.metadataSent) {
+ batch[grpc.opType.SEND_INITIAL_METADATA] =
+ (new Metadata())._getCoreRepresentation();
+ this.call.metadataSent = true;
+ }
if (_.isFinite(encoding)) {
/* Attach the encoding if it is a finite number. This is the closest we
* can get to checking that it is valid flags */
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index e429a3648b..2636ea85ac 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -607,6 +607,113 @@ describe('Client malformed response handling', function() {
call.end();
});
});
+describe('Server serialization failure handling', function() {
+ function serializeFail(obj) {
+ throw new Error('Serialization failed');
+ }
+ var client;
+ var server;
+ before(function() {
+ var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+ var test_service = test_proto.lookup('TestService');
+ var malformed_test_service = {
+ unary: {
+ path: '/TestService/Unary',
+ requestStream: false,
+ responseStream: false,
+ requestDeserialize: _.identity,
+ responseSerialize: serializeFail
+ },
+ clientStream: {
+ path: '/TestService/ClientStream',
+ requestStream: true,
+ responseStream: false,
+ requestDeserialize: _.identity,
+ responseSerialize: serializeFail
+ },
+ serverStream: {
+ path: '/TestService/ServerStream',
+ requestStream: false,
+ responseStream: true,
+ requestDeserialize: _.identity,
+ responseSerialize: serializeFail
+ },
+ bidiStream: {
+ path: '/TestService/BidiStream',
+ requestStream: true,
+ responseStream: true,
+ requestDeserialize: _.identity,
+ responseSerialize: serializeFail
+ }
+ };
+ server = new grpc.Server();
+ server.addService(malformed_test_service, {
+ unary: function(call, cb) {
+ cb(null, {});
+ },
+ clientStream: function(stream, cb) {
+ stream.on('data', function() {/* Ignore requests */});
+ stream.on('end', function() {
+ cb(null, {});
+ });
+ },
+ serverStream: function(stream) {
+ stream.write({});
+ stream.end();
+ },
+ bidiStream: function(stream) {
+ stream.on('data', function() {
+ // Ignore requests
+ stream.write({});
+ });
+ stream.on('end', function() {
+ stream.end();
+ });
+ }
+ });
+ var port = server.bind('localhost:0', server_insecure_creds);
+ var Client = surface_client.makeProtobufClientConstructor(test_service);
+ client = new Client('localhost:' + port, grpc.credentials.createInsecure());
+ server.start();
+ });
+ after(function() {
+ server.forceShutdown();
+ });
+ it('should get an INTERNAL status with a unary call', function(done) {
+ client.unary({}, function(err, data) {
+ assert(err);
+ assert.strictEqual(err.code, grpc.status.INTERNAL);
+ done();
+ });
+ });
+ it('should get an INTERNAL status with a client stream call', function(done) {
+ var call = client.clientStream(function(err, data) {
+ assert(err);
+ assert.strictEqual(err.code, grpc.status.INTERNAL);
+ done();
+ });
+ call.write({});
+ call.end();
+ });
+ it('should get an INTERNAL status with a server stream call', function(done) {
+ var call = client.serverStream({});
+ call.on('data', function(){});
+ call.on('error', function(err) {
+ assert.strictEqual(err.code, grpc.status.INTERNAL);
+ done();
+ });
+ });
+ it('should get an INTERNAL status with a bidi stream call', function(done) {
+ var call = client.bidiStream();
+ call.on('data', function(){});
+ call.on('error', function(err) {
+ assert.strictEqual(err.code, grpc.status.INTERNAL);
+ done();
+ });
+ call.write({});
+ call.end();
+ });
+});
describe('Other conditions', function() {
var test_service;
var Client;