Skip to content

Commit 5bc2ea7

Browse files
committed
GrpcServer should response with the UNIMPLEMENTED grpc status when the service is not deployed.
Motivation: GrpcServer behavior for unknown services is to send an HTTP 500 response, which is not the appropriate way to respond to a client for the application/grpc based protocols. Changes: Update GrpcServer to response with the UNIMPLEMENTED grpc-status and appropriate grpc-message trailers when a service is unknown.
1 parent a952c80 commit 5bc2ea7

File tree

7 files changed

+104
-2
lines changed

7 files changed

+104
-2
lines changed

vertx-grpc-it/src/test/java/io/vertx/grpc/it/TranscodingTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,27 @@ public void testUnaryCollisionWithoutOption(TestContext should) {
415415
grpcTest.awaitSuccess();
416416
}
417417

418+
@Test
419+
public void testUnknownService(TestContext should) {
420+
HttpClient client = vertx.createHttpClient();
421+
422+
Future<HttpServer> server = vertx.createHttpServer()
423+
.requestHandler(GrpcServer.server(vertx)).listen(8080, "localhost");
424+
425+
RequestOptions options = new RequestOptions().setHost("localhost").setPort(8080).setURI("/v1/hello").setMethod(HttpMethod.POST);
426+
Async test = should.async();
427+
428+
server.onComplete(should.asyncAssertSuccess(v -> client.request(options).compose(req -> {
429+
req.putHeader(HttpHeaders.CONTENT_TYPE, "application/json");
430+
req.putHeader(HttpHeaders.ACCEPT, "application/json");
431+
return req.send(Buffer.buffer(new JsonObject().put("name", "Julien").encode()));
432+
}).compose(resp -> {
433+
should.assertEquals(500, resp.statusCode());
434+
return resp.body();
435+
}).onComplete(should.asyncAssertSuccess(body -> test.complete()))));
436+
437+
test.awaitSuccess();
438+
}
418439
private String createRequest(String name) {
419440
return Json.encode(new JsonObject().put("name", name));
420441
}

vertx-grpc-server/src/main/java/io/vertx/grpc/server/impl/GrpcServerImpl.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.vertx.core.buffer.Buffer;
1919
import io.vertx.core.http.HttpHeaders;
2020
import io.vertx.core.http.HttpServerRequest;
21+
import io.vertx.core.http.HttpServerResponse;
2122
import io.vertx.core.internal.http.HttpServerRequestInternal;
2223
import io.vertx.core.internal.logging.Logger;
2324
import io.vertx.core.internal.logging.LoggerFactory;
@@ -111,7 +112,25 @@ public void handle(HttpServerRequest httpRequest) {
111112
if (handler != null) {
112113
handle(new MethodCallHandler<>(null, GrpcMessageDecoder.IDENTITY, GrpcMessageEncoder.IDENTITY, handler), httpRequest, methodCall, details.protocol, details.format);
113114
} else {
114-
httpRequest.response().setStatusCode(500).end();
115+
String msg = "Method not found: " + httpRequest.path().substring(1);
116+
HttpServerResponse response = httpRequest.response();
117+
boolean webText = true;
118+
switch (details.protocol) {
119+
case HTTP_2:
120+
case WEB:
121+
case WEB_TEXT:
122+
response.setStatusCode(200);
123+
response.putHeader(HttpHeaders.CONTENT_TYPE, details.protocol.mediaType());
124+
response.putHeader(GrpcHeaderNames.GRPC_STATUS, GrpcStatus.UNIMPLEMENTED.toString());
125+
response.putHeader(GrpcHeaderNames.GRPC_MESSAGE, msg);
126+
response.end();
127+
break;
128+
default:
129+
response
130+
.setStatusCode(500)
131+
.end();
132+
break;
133+
}
115134
}
116135
}
117136

vertx-grpc-server/src/main/java/io/vertx/grpc/server/impl/WebGrpcServerResponse.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727

2828
public class WebGrpcServerResponse<Req, Resp> extends GrpcServerResponseImpl<Req,Resp> {
2929

30+
public static Buffer grpcWebEncode(Buffer message) {
31+
return BufferInternal.buffer(Base64.encode(((BufferInternal)message).getByteBuf(), false));
32+
}
33+
3034
private final GrpcProtocol protocol;
3135
private final HttpServerResponse httpResponse;
3236
private Buffer trailers;
@@ -54,7 +58,7 @@ private void appendToTrailers(MultiMap entries) {
5458
protected Buffer encodeMessage(Buffer message, boolean compressed, boolean trailer) {
5559
message = super.encodeMessage(message, compressed, trailer);
5660
if (protocol == WEB_TEXT) {
57-
message = BufferInternal.buffer(Base64.encode(((BufferInternal)message).getByteBuf(), false));
61+
message = grpcWebEncode(message);
5862
}
5963
return message;
6064
}

vertx-grpc-server/src/test/java/io/vertx/tests/server/ServerRequestTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,14 @@ public void testBidiStreamingCompletedBeforeHalfClose(TestContext should) throws
232232
super.testBidiStreamingCompletedBeforeHalfClose(should);
233233
}
234234

235+
@Override
236+
public void testUnknownService(TestContext should) {
237+
238+
startServer(GrpcServer.server(vertx));
239+
240+
super.testUnknownService(should);
241+
}
242+
235243
@Test
236244
public void testMetadata(TestContext should) {
237245

vertx-grpc-server/src/test/java/io/vertx/tests/server/ServerTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,26 @@ public void onCompleted() {
273273

274274
protected AtomicInteger testMetadataStep;
275275

276+
@Test
277+
public void testUnknownService(TestContext should) {
278+
channel = ManagedChannelBuilder.forAddress("localhost", port)
279+
.usePlaintext()
280+
.build();
281+
TestServiceGrpc.TestServiceBlockingStub stub = TestServiceGrpc.newBlockingStub(channel);
282+
283+
try {
284+
Iterator<Reply> iterator = stub.source(Empty.newBuilder().build());
285+
// This is lazy
286+
while (iterator.hasNext()) {
287+
iterator.next();
288+
}
289+
should.fail();
290+
} catch (StatusRuntimeException e) {
291+
should.assertEquals(12, e.getStatus().getCode().value());
292+
should.assertEquals("Method not found: io.vertx.tests.common.grpc.tests.TestService/Source", e.getStatus().getDescription());
293+
}
294+
}
295+
276296
@Test
277297
public void testMetadata(TestContext should) {
278298

vertx-grpc-server/src/test/java/io/vertx/tests/server/web/ServerTestBase.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ public abstract class ServerTestBase extends GrpcTestBase {
7878
protected static final CharSequence TRUE = HttpHeaders.createOptimized("1");
7979

8080
private static final String GRPC_STATUS = "grpc-status";
81+
private static final String GRPC_MESSAGE = "grpc-message";
8182
private static final String STATUS_OK = GRPC_STATUS + ":" + 0 + "\r\n";
8283
private static final String TRAILERS_AND_STATUS = STATUS_OK +
8384
TRAILER_TEXT_KEY + ":" + TRAILER_TEXT_VALUE + "\r\n" +
@@ -477,6 +478,25 @@ public void testTrailersOnly(TestContext should) {
477478
}));
478479
}
479480

481+
@Test
482+
public void testUnknownService(TestContext should) {
483+
httpClient.request(HttpMethod.POST, TEST_SERVICE + "/U").compose(req -> {
484+
req.headers()
485+
.addAll(METADATA)
486+
.addAll(requestHeaders());
487+
return req.send(encode(EMPTY_DEFAULT_INSTANCE)).compose(response -> response.body().map(response));
488+
}).onComplete(should.asyncAssertSuccess(response -> {
489+
should.verify(v -> {
490+
assertEquals(200, response.statusCode());
491+
MultiMap headers = response.headers();
492+
assertTrue(headers.contains(CONTENT_TYPE, responseContentType(), true));
493+
assertTrue(headers.contains(CONTENT_LENGTH, "0", true));
494+
assertTrue(headers.contains(GRPC_STATUS, "12", false));
495+
assertTrue(headers.contains(GRPC_MESSAGE, "Method not found: io.vertx.grpcweb.TestService/U", false));
496+
});
497+
}));
498+
}
499+
480500
protected Buffer encode(Message message) {
481501
return GrpcMessageImpl.encode(GrpcMessage.message("identity", Buffer.buffer(message.toByteArray())));
482502
}

vertx-grpcio-server/src/test/java/io/vertx/tests/server/ServerBridgeTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.vertx.ext.unit.Async;
1919
import io.vertx.ext.unit.TestContext;
2020
import io.vertx.grpc.common.GrpcStatus;
21+
import io.vertx.grpc.server.GrpcServer;
2122
import io.vertx.grpcio.common.impl.Utils;
2223
import io.vertx.grpcio.server.GrpcIoServer;
2324
import io.vertx.grpcio.server.GrpcIoServiceBridge;
@@ -332,6 +333,15 @@ public void onCompleted() {
332333
super.testBidiStreamingCompletedBeforeHalfClose(should);
333334
}
334335

336+
@Override
337+
public void testUnknownService(TestContext should) {
338+
339+
GrpcIoServer server = GrpcIoServer.server(vertx);
340+
startServer(server);
341+
342+
super.testUnknownService(should);
343+
}
344+
335345
@Override
336346
public void testMetadata(TestContext should) {
337347

0 commit comments

Comments
 (0)