diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a3a6b2ec9..dfc7be76b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,7 +27,7 @@ kotlin-compile-testing-version = "1.6.0" kotlinx-benchmark-version = "0.4.12" kotlinx-serialization-version = "1.7.3" docker-java-version = "3.4.0" -ktor-version = "2.3.12" +ktor-version = "3.0.0" kaml-version = "0.55.0" jsoup-version = "1.18.1" diff --git a/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/test/aws/smithy/kotlin/runtime/http/engine/crt/AsyncStressTest.kt b/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/test/aws/smithy/kotlin/runtime/http/engine/crt/AsyncStressTest.kt index 7f04debea..7ad57fa1a 100644 --- a/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/test/aws/smithy/kotlin/runtime/http/engine/crt/AsyncStressTest.kt +++ b/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/test/aws/smithy/kotlin/runtime/http/engine/crt/AsyncStressTest.kt @@ -14,7 +14,6 @@ import aws.smithy.kotlin.runtime.httptest.TestWithLocalServer import aws.smithy.kotlin.runtime.net.Host import aws.smithy.kotlin.runtime.net.Scheme import aws.smithy.kotlin.runtime.testing.IgnoreWindows -import io.ktor.server.application.* import io.ktor.server.cio.* import io.ktor.server.engine.* import io.ktor.server.response.* diff --git a/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/suite/Downloads.kt b/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/suite/Downloads.kt index a6cd6d310..dd495edf2 100644 --- a/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/suite/Downloads.kt +++ b/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/suite/Downloads.kt @@ -8,42 +8,35 @@ package aws.smithy.kotlin.runtime.http.test.suite import aws.smithy.kotlin.runtime.hashing.sha256 import aws.smithy.kotlin.runtime.text.encoding.encodeToHex import io.ktor.http.* -import io.ktor.http.content.* import io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.utils.io.* import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import java.io.ByteArrayOutputStream import java.util.zip.GZIPOutputStream import kotlin.random.Random +internal const val DOWNLOAD_SIZE = 16L * 1024 * 1024 // 16MB + internal fun Application.downloadTests() { routing { route("/download") { get("/integrity") { // writer is setup to write random lengths and delay to cause the reader to enter a suspend loop - val data = ByteArray(16 * 1024 * 1024) { it.toByte() } + val data = ByteArray(DOWNLOAD_SIZE.toInt()) { it.toByte() } val writeSha = data.sha256().encodeToHex() call.response.header("expected-sha256", writeSha) val chunked = call.request.queryParameters["chunked-response"]?.toBoolean() ?: false - val ch = ByteChannel(autoFlush = true) - val content = object : OutgoingContent.ReadChannelContent() { - override val contentLength: Long? = if (chunked) null else data.size.toLong() - override fun readFrom(): ByteReadChannel = ch - override val contentType: ContentType = ContentType.Application.OctetStream - } - - launch { + call.respondBytesWriter(contentLength = DOWNLOAD_SIZE.takeUnless { chunked }) { var wcRemaining = data.size var offset = 0 while (wcRemaining > 0) { // random write sizes val wc = minOf(wcRemaining, Random.nextInt(256, 8 * 1024)) val slice = data.sliceArray(offset until offset + wc) - ch.writeFully(slice) + writeFully(slice) offset += wc wcRemaining -= wc @@ -51,11 +44,7 @@ internal fun Application.downloadTests() { delay(Random.nextLong(0, 10)) } } - }.invokeOnCompletion { cause -> - ch.close(cause) } - - call.respond(content) } get("/empty") { diff --git a/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/suite/Uploads.kt b/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/suite/Uploads.kt index aeea40bd9..091064733 100644 --- a/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/suite/Uploads.kt +++ b/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/suite/Uploads.kt @@ -11,6 +11,8 @@ import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* +import io.ktor.utils.io.availableForRead +import io.ktor.utils.io.readAvailable private const val CHUNK_SIZE = 1024 * 8 diff --git a/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/util/TestServers.kt b/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/util/TestServers.kt index 84fa80905..2afff67c2 100644 --- a/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/util/TestServers.kt +++ b/runtime/protocol/http-client-engines/test-suite/jvm/src/aws/smithy/kotlin/runtime/http/test/util/TestServers.kt @@ -88,10 +88,13 @@ internal fun startServers(sslConfigPath: String): Closeable { return servers } -private fun tlsServer(instance: TestServer, sslConfig: SslConfig): ApplicationEngine { +private fun tlsServer(instance: TestServer, sslConfig: SslConfig): EmbeddedServer<*, *> { val description = "${instance.type.name} server on port ${instance.port}" println("Starting $description...") - val environment = applicationEngineEnvironment { + val rootConfig = serverConfig { + module(instance.initializer) + } + val engineConfig: ApplicationEngine.Configuration.() -> Unit = { when (instance.type) { ConnectorType.HTTP -> connector { port = instance.port } @@ -106,11 +109,10 @@ private fun tlsServer(instance: TestServer, sslConfig: SslConfig): ApplicationEn enabledProtocols = instance.protocolName?.let(::listOf) } } - - modules.add(instance.initializer) } + return try { - embeddedServer(Jetty, environment).start() + embeddedServer(Jetty, rootConfig, engineConfig).start() } catch (e: Exception) { println("$description failed to start with exception $e") throw e diff --git a/runtime/protocol/http-client-engines/test-suite/jvm/test/aws/smithy/kotlin/runtime/http/test/FileUploadDownloadTest.kt b/runtime/protocol/http-client-engines/test-suite/jvm/test/aws/smithy/kotlin/runtime/http/test/FileUploadDownloadTest.kt index 2561b9e18..302c8c857 100644 --- a/runtime/protocol/http-client-engines/test-suite/jvm/test/aws/smithy/kotlin/runtime/http/test/FileUploadDownloadTest.kt +++ b/runtime/protocol/http-client-engines/test-suite/jvm/test/aws/smithy/kotlin/runtime/http/test/FileUploadDownloadTest.kt @@ -12,6 +12,7 @@ import aws.smithy.kotlin.runtime.hashing.sha256 import aws.smithy.kotlin.runtime.http.* import aws.smithy.kotlin.runtime.http.complete import aws.smithy.kotlin.runtime.http.request.HttpRequest +import aws.smithy.kotlin.runtime.http.test.suite.DOWNLOAD_SIZE import aws.smithy.kotlin.runtime.http.test.util.AbstractEngineTest import aws.smithy.kotlin.runtime.http.test.util.test import aws.smithy.kotlin.runtime.http.test.util.testSetup @@ -62,16 +63,17 @@ class FileUploadDownloadTest : AbstractEngineTest() { val expectedSha256 = call.response.headers["expected-sha256"] ?: fail("missing expected-sha256 header") val contentLength = call.response.body.contentLength ?: fail("expected Content-Length") - check(contentLength < Int.MAX_VALUE) + assertEquals(DOWNLOAD_SIZE, contentLength) val body = call.response.body val stream = checkNotNull(body.toByteStream()) val file = RandomTempFile(0) stream.writeToFile(file) + assertEquals(DOWNLOAD_SIZE, file.length()) + val readSha256 = file.readBytes().sha256().encodeToHex() assertEquals(expectedSha256, readSha256) - assertEquals(contentLength, file.length()) } finally { call.complete() } diff --git a/runtime/protocol/http-test/jvm/src/aws/smithy/kotlin/runtime/httptest/TestWithLocalServer.kt b/runtime/protocol/http-test/jvm/src/aws/smithy/kotlin/runtime/httptest/TestWithLocalServer.kt index 305e9fe05..3ffc1a868 100644 --- a/runtime/protocol/http-test/jvm/src/aws/smithy/kotlin/runtime/httptest/TestWithLocalServer.kt +++ b/runtime/protocol/http-test/jvm/src/aws/smithy/kotlin/runtime/httptest/TestWithLocalServer.kt @@ -22,7 +22,7 @@ public abstract class TestWithLocalServer { protected val serverPort: Int = ServerSocket(0).use { it.localPort } protected val testHost: String = "localhost" - public abstract val server: ApplicationEngine + public abstract val server: EmbeddedServer<*, *> @BeforeTest public fun startServer(): Unit = runBlocking { diff --git a/tests/benchmarks/http-benchmarks/jvm/src/aws/smithy/kotlin/benchmarks/http/HttpEngineBenchmarks.kt b/tests/benchmarks/http-benchmarks/jvm/src/aws/smithy/kotlin/benchmarks/http/HttpEngineBenchmarks.kt index 532feb487..ab6ad163f 100644 --- a/tests/benchmarks/http-benchmarks/jvm/src/aws/smithy/kotlin/benchmarks/http/HttpEngineBenchmarks.kt +++ b/tests/benchmarks/http-benchmarks/jvm/src/aws/smithy/kotlin/benchmarks/http/HttpEngineBenchmarks.kt @@ -19,11 +19,12 @@ import aws.smithy.kotlin.runtime.io.SdkSource import aws.smithy.kotlin.runtime.io.source import aws.smithy.kotlin.runtime.net.Host import aws.smithy.kotlin.runtime.net.Scheme -import io.ktor.server.application.* import io.ktor.server.engine.* import io.ktor.server.netty.* import io.ktor.server.response.* import io.ktor.server.routing.* +import io.ktor.utils.io.core.remaining +import io.ktor.utils.io.readRemaining import kotlinx.benchmark.Blackhole import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking