diff --git a/.changes/4855cecf-6a96-4622-b7ff-5d09e54f6564.json b/.changes/4855cecf-6a96-4622-b7ff-5d09e54f6564.json new file mode 100644 index 0000000000..6c781606fe --- /dev/null +++ b/.changes/4855cecf-6a96-4622-b7ff-5d09e54f6564.json @@ -0,0 +1,5 @@ +{ + "id": "4855cecf-6a96-4622-b7ff-5d09e54f6564", + "type": "bugfix", + "description": "Overwrite `Content-Length` header rather than appending in `CrtHttpEngine`" +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4d2c857514..8b60cc05ea 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ kotlin-version = "2.2.0" dokka-version = "2.0.0" -aws-kotlin-repo-tools-version = "0.4.55" +aws-kotlin-repo-tools-version = "0.4.56" # libs coroutines-version = "1.10.2" diff --git a/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/src/aws/smithy/kotlin/runtime/http/engine/crt/RequestUtil.kt b/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/src/aws/smithy/kotlin/runtime/http/engine/crt/RequestUtil.kt index 5708f111b0..73f7d605a3 100644 --- a/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/src/aws/smithy/kotlin/runtime/http/engine/crt/RequestUtil.kt +++ b/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/src/aws/smithy/kotlin/runtime/http/engine/crt/RequestUtil.kt @@ -68,7 +68,7 @@ internal fun HttpRequest.toCrtRequest(callContext: CoroutineContext): aws.sdk.ko } val contentLength = body.contentLength?.takeIf { it >= 0 }?.toString() ?: headers[CONTENT_LENGTH_HEADER] - contentLength?.let { crtHeaders.append(CONTENT_LENGTH_HEADER, it) } + contentLength?.let { crtHeaders[CONTENT_LENGTH_HEADER] = it } return aws.sdk.kotlin.crt.http.HttpRequest(method.name, url.requestRelativePath, crtHeaders.build(), bodyStream) } diff --git a/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/test/aws/smithy/kotlin/runtime/http/engine/crt/RequestUtilTest.kt b/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/test/aws/smithy/kotlin/runtime/http/engine/crt/RequestUtilTest.kt index 25db47c70f..cb2d338588 100644 --- a/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/test/aws/smithy/kotlin/runtime/http/engine/crt/RequestUtilTest.kt +++ b/runtime/protocol/http-client-engines/http-client-engine-crt/jvm/test/aws/smithy/kotlin/runtime/http/engine/crt/RequestUtilTest.kt @@ -4,7 +4,15 @@ */ package aws.smithy.kotlin.runtime.http.engine.crt +import aws.smithy.kotlin.runtime.content.ByteStream +import aws.smithy.kotlin.runtime.http.Headers +import aws.smithy.kotlin.runtime.http.HttpMethod +import aws.smithy.kotlin.runtime.http.request.HttpRequest +import aws.smithy.kotlin.runtime.http.toHttpBody +import aws.smithy.kotlin.runtime.net.url.Url +import kotlinx.coroutines.test.runTest import kotlin.test.Test +import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue @@ -42,4 +50,19 @@ class RequestUtilTest { assertFalse(isRetryable(code, name), "Expected $name to not be retryable!") } } + + @Test + fun testContentLengthHeader() = runTest { + val data = "a".repeat(100) + + val request = HttpRequest( + HttpMethod.POST, + url = Url.parse("https://notarealurl.com"), + headers = Headers { set("Content-Length", data.length.toString()) }, + body = ByteStream.fromString(data).toHttpBody(), + ) + + val crtRequest = request.toCrtRequest(coroutineContext) + assertEquals(listOf(data.length.toString()), crtRequest.headers.getAll("Content-Length")) + } } diff --git a/runtime/protocol/http-client-engines/http-client-engine-okhttp/jvm/test/aws/smithy/kotlin/runtime/http/engine/okhttp/OkHttpRequestTest.kt b/runtime/protocol/http-client-engines/http-client-engine-okhttp/jvm/test/aws/smithy/kotlin/runtime/http/engine/okhttp/OkHttpRequestTest.kt index 16f6773008..760a947308 100644 --- a/runtime/protocol/http-client-engines/http-client-engine-okhttp/jvm/test/aws/smithy/kotlin/runtime/http/engine/okhttp/OkHttpRequestTest.kt +++ b/runtime/protocol/http-client-engines/http-client-engine-okhttp/jvm/test/aws/smithy/kotlin/runtime/http/engine/okhttp/OkHttpRequestTest.kt @@ -5,6 +5,7 @@ package aws.smithy.kotlin.runtime.http.engine.okhttp +import aws.smithy.kotlin.runtime.content.ByteStream import aws.smithy.kotlin.runtime.http.* import aws.smithy.kotlin.runtime.http.engine.internal.HttpClientMetrics import aws.smithy.kotlin.runtime.http.request.HttpRequest @@ -71,6 +72,22 @@ class OkHttpRequestTest { assertEquals(listOf("bar", "baz"), actual.headers("FoO")) } + @Test + fun itConvertsContentLengthHeader() { + val data = "a".repeat(100) + val url = Url.parse("https://aws.amazon.com") + val headers = Headers { + append("Content-Length", data.length.toString()) + } + val request = HttpRequest(HttpMethod.POST, url, headers, ByteStream.fromString(data).toHttpBody()) + + val execContext = ExecutionContext() + val actual = request.toOkHttpRequest(execContext, EmptyCoroutineContext, testMetrics) + + assertTrue(actual.headers.size >= 1) + assertEquals(listOf(data.length.toString()), actual.headers("Content-Length")) + } + @Test fun itSupportsNonAsciiHeaderValues() { val url = Url.parse("https://aws.amazon.com")