Skip to content

Commit 4aa0376

Browse files
authored
fix: readAvailable fallback behavior (#620)
1 parent 4242fe6 commit 4aa0376

File tree

3 files changed

+66
-1
lines changed

3 files changed

+66
-1
lines changed

runtime/io/common/src/aws/smithy/kotlin/runtime/io/SdkByteReadChannel.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ internal suspend fun SdkByteReadChannel.readAvailableFallback(dest: SdkByteBuffe
158158
// channel was closed while waiting and no further content was made available
159159
if (availableForRead == 0 && isClosedForRead) return -1
160160
val tmp = ByteArray(minOf(availableForRead.toLong(), limit, Int.MAX_VALUE.toLong()).toInt())
161+
readFully(tmp)
161162
dest.writeFully(tmp)
162163
return tmp.size.toLong()
163164
}

runtime/io/common/test/aws/smithy/kotlin/runtime/io/SdkByteChannelOpsTest.kt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,36 @@ class SdkByteChannelOpsTest {
170170
}
171171
assertNull(chan.readUtf8CodePoint())
172172
}
173+
174+
private class ProxyChan(
175+
val ch: SdkByteReadChannel
176+
) : SdkByteReadChannel by ch {
177+
var proxyCalled = false
178+
override suspend fun readRemaining(limit: Int): ByteArray {
179+
proxyCalled = true
180+
return ch.readRemaining(limit)
181+
}
182+
override suspend fun readFully(sink: ByteArray, offset: Int, length: Int) {
183+
proxyCalled = true
184+
return ch.readFully(sink, offset, length)
185+
}
186+
override suspend fun readAvailable(sink: ByteArray, offset: Int, length: Int): Int {
187+
proxyCalled = true
188+
return ch.readAvailable(sink, offset, length)
189+
}
190+
}
191+
192+
@Test
193+
fun testReadAvailableSdkByteBufferFallback() = runTest {
194+
val content = "a".repeat(64).encodeToByteArray()
195+
val inner = SdkByteReadChannel(content)
196+
val chan = ProxyChan(inner)
197+
198+
val dest = SdkByteBuffer(32U)
199+
val rc = chan.readAvailable(dest)
200+
assertEquals(dest.readRemaining.toLong(), rc)
201+
val expected = "a".repeat(32)
202+
assertEquals(expected, dest.decodeToString())
203+
assertTrue(chan.proxyCalled)
204+
}
173205
}

runtime/protocol/http-client-engines/test-suite/common/test/aws/smithy/kotlin/runtime/http/test/UploadTest.kt

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
package aws.smithy.kotlin.runtime.http.test
77

8+
import aws.smithy.kotlin.runtime.content.ByteStream
89
import aws.smithy.kotlin.runtime.http.HttpBody
910
import aws.smithy.kotlin.runtime.http.HttpMethod
1011
import aws.smithy.kotlin.runtime.http.HttpStatusCode
@@ -14,6 +15,7 @@ import aws.smithy.kotlin.runtime.http.request.url
1415
import aws.smithy.kotlin.runtime.http.response.complete
1516
import aws.smithy.kotlin.runtime.http.test.util.AbstractEngineTest
1617
import aws.smithy.kotlin.runtime.http.test.util.test
18+
import aws.smithy.kotlin.runtime.http.toHttpBody
1719
import aws.smithy.kotlin.runtime.io.SdkByteChannel
1820
import aws.smithy.kotlin.runtime.io.SdkByteReadChannel
1921
import aws.smithy.kotlin.runtime.util.encodeToHex
@@ -29,7 +31,7 @@ class UploadTest : AbstractEngineTest() {
2931
fun testUploadIntegrity() = testEngines {
3032
// test that what we write the entire contents given to us
3133
test { env, client ->
32-
val data = ByteArray(16 * 1024 * 1023) { it.toByte() }
34+
val data = ByteArray(16 * 1024 * 1024) { it.toByte() }
3335
val sha = data.sha256().encodeToHex()
3436

3537
val req = HttpRequest {
@@ -80,4 +82,34 @@ class UploadTest : AbstractEngineTest() {
8082
}
8183
}
8284
}
85+
86+
@Test
87+
fun testUploadWithWrappedStream() = testEngines {
88+
// test custom ByteStream behavior
89+
// see https://github.com/awslabs/smithy-kotlin/issues/613
90+
test { env, client ->
91+
val data = ByteArray(1024 * 1024) { it.toByte() }
92+
val sha = data.sha256().encodeToHex()
93+
94+
val wrappedStream = object : ByteStream.ReplayableStream() {
95+
override val contentLength: Long = data.size.toLong()
96+
override fun newReader(): SdkByteReadChannel {
97+
val underlying = SdkByteReadChannel(data)
98+
return object : SdkByteReadChannel by underlying {}
99+
}
100+
}
101+
102+
val req = HttpRequest {
103+
method = HttpMethod.POST
104+
url(env.testServer)
105+
url.path = "/upload/content"
106+
body = wrappedStream.toHttpBody()
107+
}
108+
109+
val call = client.call(req)
110+
call.complete()
111+
assertEquals(HttpStatusCode.OK, call.response.status)
112+
assertEquals(sha, call.response.headers["content-sha256"], "sha mismatch for upload on ${client.engine}")
113+
}
114+
}
83115
}

0 commit comments

Comments
 (0)