diff --git a/ktor-client/ktor-client-jetty-jakarta/jvm/src/io/ktor/client/engine/jetty/jakarta/JettyHttp2Engine.kt b/ktor-client/ktor-client-jetty-jakarta/jvm/src/io/ktor/client/engine/jetty/jakarta/JettyHttp2Engine.kt index c6b29ac7633..9994d155666 100644 --- a/ktor-client/ktor-client-jetty-jakarta/jvm/src/io/ktor/client/engine/jetty/jakarta/JettyHttp2Engine.kt +++ b/ktor-client/ktor-client-jetty-jakarta/jvm/src/io/ktor/client/engine/jetty/jakarta/JettyHttp2Engine.kt @@ -6,6 +6,7 @@ package io.ktor.client.engine.jetty.jakarta import io.ktor.client.engine.* import io.ktor.client.plugins.* +import io.ktor.client.plugins.sse.* import io.ktor.client.request.* import io.ktor.util.* import io.ktor.utils.io.* @@ -17,7 +18,7 @@ internal class JettyHttp2Engine( override val config: JettyEngineConfig ) : HttpClientEngineBase("ktor-jetty") { - override val supportedCapabilities = setOf(HttpTimeoutCapability) + override val supportedCapabilities = setOf(HttpTimeoutCapability, SSECapability) /** * Cache that keeps least recently used [HTTP2Client] instances. Set "0" to avoid caching. @@ -28,7 +29,7 @@ internal class JettyHttp2Engine( val callContext = callContext() val jettyClient = getOrCreateClient(data) - return data.executeRequest(jettyClient, config, callContext) + return data.executeRequest(data, jettyClient, config, callContext) } /** Only for tests */ diff --git a/ktor-client/ktor-client-jetty-jakarta/jvm/src/io/ktor/client/engine/jetty/jakarta/JettyHttpRequest.kt b/ktor-client/ktor-client-jetty-jakarta/jvm/src/io/ktor/client/engine/jetty/jakarta/JettyHttpRequest.kt index a50372dbd5c..4834eeaa9b6 100644 --- a/ktor-client/ktor-client-jetty-jakarta/jvm/src/io/ktor/client/engine/jetty/jakarta/JettyHttpRequest.kt +++ b/ktor-client/ktor-client-jetty-jakarta/jvm/src/io/ktor/client/engine/jetty/jakarta/JettyHttpRequest.kt @@ -24,7 +24,9 @@ import java.net.* import java.nio.* import kotlin.coroutines.* +@OptIn(InternalAPI::class) internal suspend fun HttpRequestData.executeRequest( + data: HttpRequestData, client: HTTP2Client, config: JettyEngineConfig, callContext: CoroutineContext @@ -47,13 +49,16 @@ internal suspend fun HttpRequestData.executeRequest( sendRequestBody(jettyRequest, body, callContext) val (status, headers) = responseListener.awaitHeaders() + val responseBody: Any = data.attributes.getOrNull(ResponseAdapterAttributeKey) + ?.adapt(data, status, headers, responseChannel, data.body, callContext) + ?: responseChannel return HttpResponseData( status, requestTime, headers, HttpProtocolVersion.HTTP_2_0, - responseChannel, + responseBody, callContext ) } diff --git a/ktor-client/ktor-client-jetty/jvm/src/io/ktor/client/engine/jetty/JettyHttp2Engine.kt b/ktor-client/ktor-client-jetty/jvm/src/io/ktor/client/engine/jetty/JettyHttp2Engine.kt index 008f5e6c5dc..9a37f009d61 100644 --- a/ktor-client/ktor-client-jetty/jvm/src/io/ktor/client/engine/jetty/JettyHttp2Engine.kt +++ b/ktor-client/ktor-client-jetty/jvm/src/io/ktor/client/engine/jetty/JettyHttp2Engine.kt @@ -6,6 +6,7 @@ package io.ktor.client.engine.jetty import io.ktor.client.engine.* import io.ktor.client.plugins.* +import io.ktor.client.plugins.sse.* import io.ktor.client.request.* import io.ktor.util.* import io.ktor.utils.io.* @@ -17,7 +18,7 @@ internal class JettyHttp2Engine( override val config: JettyEngineConfig ) : HttpClientEngineBase("ktor-jetty") { - override val supportedCapabilities = setOf(HttpTimeoutCapability) + override val supportedCapabilities = setOf(HttpTimeoutCapability, SSECapability) /** * Cache that keeps least recently used [HTTP2Client] instances. Set "0" to avoid caching. @@ -28,7 +29,7 @@ internal class JettyHttp2Engine( val callContext = callContext() val jettyClient = getOrCreateClient(data) - return data.executeRequest(jettyClient, config, callContext) + return data.executeRequest(data, jettyClient, config, callContext) } /** Only for tests */ diff --git a/ktor-client/ktor-client-jetty/jvm/src/io/ktor/client/engine/jetty/JettyHttpRequest.kt b/ktor-client/ktor-client-jetty/jvm/src/io/ktor/client/engine/jetty/JettyHttpRequest.kt index 6609f6a0534..793c77df7ce 100644 --- a/ktor-client/ktor-client-jetty/jvm/src/io/ktor/client/engine/jetty/JettyHttpRequest.kt +++ b/ktor-client/ktor-client-jetty/jvm/src/io/ktor/client/engine/jetty/JettyHttpRequest.kt @@ -24,7 +24,9 @@ import java.net.* import java.nio.* import kotlin.coroutines.* +@OptIn(InternalAPI::class) internal suspend fun HttpRequestData.executeRequest( + data: HttpRequestData, client: HTTP2Client, config: JettyEngineConfig, callContext: CoroutineContext @@ -47,13 +49,16 @@ internal suspend fun HttpRequestData.executeRequest( sendRequestBody(jettyRequest, body, callContext) val (status, headers) = responseListener.awaitHeaders() + val responseBody: Any = data.attributes.getOrNull(ResponseAdapterAttributeKey) + ?.adapt(data, status, headers, responseChannel, data.body, callContext) + ?: responseChannel return HttpResponseData( status, requestTime, headers, HttpProtocolVersion.HTTP_2_0, - responseChannel, + responseBody, callContext ) } diff --git a/ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/plugins/ServerSentEventsTest.kt b/ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/plugins/ServerSentEventsTest.kt index 5d3fcfc5229..5d195189de6 100644 --- a/ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/plugins/ServerSentEventsTest.kt +++ b/ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/plugins/ServerSentEventsTest.kt @@ -420,6 +420,8 @@ class ServerSentEventsTest : ClientLoader(timeoutSeconds = 120) { } test { client -> + println(client.engine) + throw IllegalArgumentException() client.sse({ url("$TEST_SERVER/sse") method = HttpMethod.Post diff --git a/ktor-client/ktor-client-tests/jvm/src/io/ktor/client/tests/utils/ClientLoaderJvm.kt b/ktor-client/ktor-client-tests/jvm/src/io/ktor/client/tests/utils/ClientLoaderJvm.kt index 8bbb1ed9fe0..d07a46183bb 100644 --- a/ktor-client/ktor-client-tests/jvm/src/io/ktor/client/tests/utils/ClientLoaderJvm.kt +++ b/ktor-client/ktor-client-tests/jvm/src/io/ktor/client/tests/utils/ClientLoaderJvm.kt @@ -32,6 +32,7 @@ actual abstract class ClientLoader actual constructor(val timeoutSeconds: Int) { block: suspend TestClientBuilder.() -> Unit ) { DebugProbes.install() + println("ENGINES: $engines") for (engine in engines) { if (shouldSkip(engine, skipEngines, onlyWithEngine)) { continue