diff --git a/gradle.properties b/gradle.properties index 2fb2ff37b4..c70eaf7b20 100644 --- a/gradle.properties +++ b/gradle.properties @@ -52,7 +52,7 @@ apacheDirectoryServerVersion=1.5.7 commonsLangVersion=2.6 # gRPC -grpcVersion=1.24.2 +grpcVersion=1.25.0 protobufGradlePluginVersion=0.8.10 protobufVersion=3.10.0 protoGoogleCommonProtosVersion=1.17.0 diff --git a/servicetalk-grpc-api/src/main/java/io/servicetalk/grpc/api/GrpcUtils.java b/servicetalk-grpc-api/src/main/java/io/servicetalk/grpc/api/GrpcUtils.java index c615549b90..dbea97a49c 100644 --- a/servicetalk-grpc-api/src/main/java/io/servicetalk/grpc/api/GrpcUtils.java +++ b/servicetalk-grpc-api/src/main/java/io/servicetalk/grpc/api/GrpcUtils.java @@ -201,8 +201,9 @@ private static GrpcStatusException extractGrpcExceptionFromHeaders(final HttpHea if (statusCode != null) { final GrpcStatusCode grpcStatusCode = GrpcStatusCode.fromCodeValue(statusCode); if (grpcStatusCode.value() != GrpcStatusCode.OK.value()) { - return new GrpcStatus(grpcStatusCode, null, headers.get(GRPC_STATUS_MESSAGE_TRAILER)) - .asException(new StatusSupplier(headers)); + final GrpcStatus grpcStatus = + new GrpcStatus(grpcStatusCode, null, headers.get(GRPC_STATUS_MESSAGE_TRAILER)); + return grpcStatus.asException(new StatusSupplier(headers, grpcStatus)); } } return null; @@ -234,11 +235,13 @@ static T uncheckedCast(Object o) { private static final class StatusSupplier implements Supplier { private final HttpHeaders headers; + private final GrpcStatus fallbackStatus; @Nullable private volatile StatusHolder statusHolder; - StatusSupplier(HttpHeaders headers) { + StatusSupplier(HttpHeaders headers, final GrpcStatus fallbackStatus) { this.headers = headers; + this.fallbackStatus = fallbackStatus; } @Nullable @@ -248,7 +251,16 @@ public Status get() { if (statusHolder == null) { // Cache the status (we don't bother caching any errors tho). Also its fine to only use a volatile here // as at worse this will just update to the "same" status again. - this.statusHolder = statusHolder = new StatusHolder(getStatusDetails(headers)); + final Status statusFromHeaders = getStatusDetails(headers); + if (statusFromHeaders == null) { + final Status.Builder builder = Status.newBuilder().setCode(fallbackStatus.code().value()); + if (fallbackStatus.description() != null) { + builder.setMessage(fallbackStatus.description()); + } + this.statusHolder = statusHolder = new StatusHolder(builder.build()); + } else { + this.statusHolder = statusHolder = new StatusHolder(statusFromHeaders); + } } return statusHolder.status; } diff --git a/servicetalk-grpc-netty/src/test/java/io/servicetalk/grpc/netty/ProtocolCompatibilityTest.java b/servicetalk-grpc-netty/src/test/java/io/servicetalk/grpc/netty/ProtocolCompatibilityTest.java index cc99d47b43..630efb3a9c 100644 --- a/servicetalk-grpc-netty/src/test/java/io/servicetalk/grpc/netty/ProtocolCompatibilityTest.java +++ b/servicetalk-grpc-netty/src/test/java/io/servicetalk/grpc/netty/ProtocolCompatibilityTest.java @@ -95,7 +95,6 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; @RunWith(Theories.class) @@ -542,11 +541,11 @@ private static void assertGrpcStatusException(final GrpcStatusException statusEx final GrpcStatus grpcStatus = statusException.status(); assertEquals(CUSTOM_ERROR_MESSAGE, grpcStatus.description()); final com.google.rpc.Status status = statusException.applicationStatus(); + assertNotNull(status); if (withStatus) { - assertNotNull(status); assertStatus(status, grpcStatus.code().value(), grpcStatus.description()); } else { - assertNull(status); + assertFallbackStatus(status, grpcStatus.code().value(), grpcStatus.description()); } } @@ -556,11 +555,11 @@ private static void assertStatusRuntimeException(final StatusRuntimeException st final Status grpcStatus = statusException.getStatus(); assertEquals(CUSTOM_ERROR_MESSAGE, grpcStatus.getDescription()); final com.google.rpc.Status status = StatusProto.fromThrowable(statusException); + assertNotNull(status); if (withStatus) { - assertNotNull(status); assertStatus(status, grpcStatus.getCode().value(), grpcStatus.getDescription()); } else { - assertNull(status); + assertFallbackStatus(status, grpcStatus.getCode().value(), grpcStatus.getDescription()); } } @@ -575,6 +574,14 @@ private static void assertStatus(final com.google.rpc.Status status, assertEquals(999, detail.getId()); } + private static void assertFallbackStatus(final com.google.rpc.Status status, final int expectedCode, + @Nullable final String expectedMessage) { + assertEquals(expectedCode, status.getCode()); + assertEquals(expectedMessage, status.getMessage()); + final List anyList = status.getDetailsList(); + assertEquals(0, anyList.size()); + } + private static com.google.rpc.Status newStatus() { // We just use CompatResponse as part of the status to keep it simple. return com.google.rpc.Status.newBuilder()