Skip to content

Commit b1600be

Browse files
committed
KTOR-8528 Fix race condition when Netty removes headers for some responses
1 parent bd41f80 commit b1600be

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

ktor-server/ktor-server-netty/jvm/src/io/ktor/server/netty/NettyApplicationResponse.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import io.ktor.server.engine.*
1111
import io.ktor.utils.io.*
1212
import io.netty.channel.*
1313
import io.netty.handler.codec.http.*
14+
import kotlinx.coroutines.CompletableDeferred
15+
import java.util.concurrent.CancellationException
1416
import kotlin.coroutines.*
1517

1618
public abstract class NettyApplicationResponse(
@@ -32,6 +34,8 @@ public abstract class NettyApplicationResponse(
3234

3335
internal var responseChannel: ByteReadChannel = ByteReadChannel.Empty
3436

37+
internal val sendCompleted: CompletableDeferred<Unit> by lazy { CompletableDeferred() }
38+
3539
override suspend fun respondOutgoingContent(content: OutgoingContent) {
3640
try {
3741
super.respondOutgoingContent(content)
@@ -60,6 +64,17 @@ public abstract class NettyApplicationResponse(
6064
responseMessage = message
6165
responseReady.setSuccess()
6266
responseMessageSent = true
67+
68+
if (isInfoOrNoContentStatus()) {
69+
sendCompleted.await()
70+
}
71+
}
72+
73+
internal fun isInfoOrNoContentStatus(): Boolean {
74+
val status = status()
75+
if (status == null) return false
76+
77+
return status == HttpStatusCode.NoContent || (status.value >= 100 && status.value < 200)
6378
}
6479

6580
override suspend fun responseChannel(): ByteWriteChannel {
@@ -122,7 +137,7 @@ public abstract class NettyApplicationResponse(
122137
public fun cancel() {
123138
if (!responseMessageSent) {
124139
responseChannel = ByteReadChannel.Empty
125-
responseReady.setFailure(java.util.concurrent.CancellationException("Response was cancelled"))
140+
responseReady.setFailure(CancellationException("Response was cancelled"))
126141
responseMessageSent = true
127142
}
128143
}

ktor-server/ktor-server-netty/jvm/src/io/ktor/server/netty/cio/NettyHttpResponsePipeline.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ internal class NettyHttpResponsePipeline(
7171
respondWithFailure(call, actualException)
7272
} finally {
7373
call.responseWriteJob.cancel()
74+
if (call.response.isInfoOrNoContentStatus()) {
75+
call.response.sendCompleted.complete(Unit)
76+
}
7477
}
7578
}
7679

0 commit comments

Comments
 (0)