Skip to content

Commit 07678ca

Browse files
committed
grpc-native: Fix halfClose before message received behavior
Signed-off-by: Johannes Zottele <[email protected]>
1 parent 244c5bf commit 07678ca

File tree

2 files changed

+17
-4
lines changed

2 files changed

+17
-4
lines changed

grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/CoreClientTest.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,7 @@ class GrpcCoreClientTest {
193193
@Test
194194
fun halfCloseBeforeSendingMessage_errorWithoutCrashing() {
195195
val channel = createChannel()
196-
// val call = channel.newHelloCall()
197-
val call = channel.newHelloCall(fullName = "helloworld.Greeter/SayHello")
196+
val call = channel.newHelloCall()
198197
val listener = createClientCallListener<HelloReply>(
199198
onClose = { status, _ -> println("Status: ${status.statusCode}, Message: ${status.getDescription()}") }
200199
)

grpc/grpc-core/src/nativeMain/kotlin/kotlinx/rpc/grpc/internal/NativeServerCall.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ internal class NativeServerCall<Request, Response>(
5858
private var cancelled = false
5959
private var finalized = atomic(false)
6060

61+
// Tracks whether at least one request message has been received on this call.
62+
private var receivedFirstMessage = false
63+
6164
// we currently don't buffer messages, so after one `sendMessage` call, ready turns false. (KRPC-192)
6265
private val ready = atomic(true)
6366

@@ -184,8 +187,16 @@ internal class NativeServerCall<Request, Response>(
184187
// and thus the client half-closed.
185188
val buf = recvPtr.value
186189
if (buf == null) {
187-
callbackMutex.withLock {
188-
listener.onHalfClose()
190+
// end-of-stream observed. for UNARY, absence of any request is a protocol violation.
191+
if (methodDescriptor.type == MethodType.UNARY && !receivedFirstMessage) {
192+
cancelCall(
193+
grpc_status_code.GRPC_STATUS_INTERNAL,
194+
"Unary call half-closed before receiving a request message"
195+
)
196+
} else {
197+
callbackMutex.withLock {
198+
listener.onHalfClose()
199+
}
189200
}
190201
} else {
191202
val msg = methodDescriptor.getRequestMarshaller()
@@ -194,6 +205,9 @@ internal class NativeServerCall<Request, Response>(
194205
// destroy the buffer, we don't need it anymore
195206
grpc_byte_buffer_destroy(buf)
196207

208+
// Mark that we have received at least one request message
209+
receivedFirstMessage = true
210+
197211
callbackMutex.withLock {
198212
listener.onMessage(msg)
199213
}

0 commit comments

Comments
 (0)