Skip to content

Commit ec0850b

Browse files
committed
track and return content bytes transferred
1 parent 747dafb commit ec0850b

File tree

3 files changed

+30
-7
lines changed

3 files changed

+30
-7
lines changed

runtime/auth/aws-signing-common/api/aws-signing-common.api

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ public final class aws/smithy/kotlin/runtime/auth/awssigning/AwsChunkedSource :
2323
public fun <init> (Laws/smithy/kotlin/runtime/io/SdkSource;Laws/smithy/kotlin/runtime/auth/awssigning/AwsSigner;Laws/smithy/kotlin/runtime/auth/awssigning/AwsSigningConfig;[BLaws/smithy/kotlin/runtime/http/DeferredHeaders;)V
2424
public synthetic fun <init> (Laws/smithy/kotlin/runtime/io/SdkSource;Laws/smithy/kotlin/runtime/auth/awssigning/AwsSigner;Laws/smithy/kotlin/runtime/auth/awssigning/AwsSigningConfig;[BLaws/smithy/kotlin/runtime/http/DeferredHeaders;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
2525
public fun close ()V
26+
public final fun getContentBytesTransferred ()J
2627
public fun read (Laws/smithy/kotlin/runtime/io/SdkBuffer;J)J
28+
public final fun setContentBytesTransferred (J)V
2729
}
2830

2931
public final class aws/smithy/kotlin/runtime/auth/awssigning/AwsSignatureType : java/lang/Enum {

runtime/auth/aws-signing-common/common/src/aws/smithy/kotlin/runtime/auth/awssigning/AwsChunkedSource.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,21 @@ public class AwsChunkedSource(
4040
trailingHeaders,
4141
)
4242

43+
// The number of bytes transferred without chunk metadata
44+
public var contentBytesTransferred: Long = 0L
45+
4346
override fun read(sink: SdkBuffer, limit: Long): Long {
4447
require(limit >= 0L) { "Invalid limit ($limit) must be >= 0L" }
4548
// COROUTINE SAFETY: runBlocking is allowed here because SdkSource is a synchronous blocking interface
4649
val isChunkValid = runBlocking {
4750
chunkReader.ensureValidChunk()
4851
}
4952
if (!isChunkValid) return -1L
50-
return chunkReader.chunk.read(sink, limit)
53+
54+
val actualBytesTransferred = chunkReader.chunk.read(sink, limit)
55+
contentBytesTransferred = actualBytesTransferred - chunkReader.chunkMetadataBytes
56+
57+
return actualBytesTransferred
5158
}
5259

5360
override fun close() {

runtime/auth/aws-signing-common/common/src/aws/smithy/kotlin/runtime/auth/awssigning/internal/AwsChunkedReader.kt

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ internal class AwsChunkedReader(
5757
*/
5858
internal var hasLastChunkBeenSent: Boolean = false
5959

60+
/**
61+
* Tracks the number of bytes used for chunk metadata.
62+
* This includes chunk headers, terminators (CRLF), and trailers.
63+
* Used to calculate the actual payload bytes transferred by subtracting metadata bytes from the total bytes read.
64+
*/
65+
internal var chunkMetadataBytes: Long = 0L
66+
6067
/**
6168
* Ensures that the internal [chunk] is valid for reading. If it's not valid, try to load the next chunk. Note that
6269
* this function will suspend until the whole chunk has been loaded.
@@ -65,7 +72,11 @@ internal class AwsChunkedReader(
6572
*/
6673
internal suspend fun ensureValidChunk(): Boolean {
6774
// check if the current chunk is still valid
68-
if (chunk.size > 0L) return true
75+
if (chunk.size > 0L) {
76+
// // Reset metadata bytes counter as only first read of a chunk contains metadata
77+
chunkMetadataBytes = 0L
78+
return true
79+
}
6980

7081
// if not, try to fetch a new chunk
7182
val nextChunk = when {
@@ -80,9 +91,10 @@ internal class AwsChunkedReader(
8091
next
8192
}
8293
}
83-
94+
val preTerminatorChunkSize = nextChunk?.size ?: 0L
8495
nextChunk?.writeUtf8("\r\n") // terminating CRLF to signal end of chunk
85-
96+
val chunkSizeWithTerminator = nextChunk?.size ?: 0L
97+
chunkMetadataBytes += chunkSizeWithTerminator - preTerminatorChunkSize
8698
// transfer all segments to the working chunk
8799
nextChunk?.let { chunk.writeAll(it) }
88100

@@ -96,12 +108,14 @@ internal class AwsChunkedReader(
96108
private suspend fun getFinalChunk(): SdkBuffer {
97109
// empty chunk
98110
val lastChunk = checkNotNull(if (signingConfig.isUnsigned) getUnsignedChunk(SdkBuffer()) else getSignedChunk(SdkBuffer()))
99-
111+
val preTrailerChunkSize = lastChunk.size
100112
// + any trailers
101113
if (!trailingHeaders.isEmpty()) {
102114
val trailingHeaderChunk = getTrailingHeadersChunk(trailingHeaders.toHeaders())
103115
lastChunk.writeAll(trailingHeaderChunk)
104116
}
117+
val trailersSize = lastChunk.size - preTrailerChunkSize
118+
chunkMetadataBytes += trailersSize
105119
return lastChunk
106120
}
107121

@@ -155,7 +169,7 @@ internal class AwsChunkedReader(
155169
write(chunkSignature)
156170
writeUtf8("\r\n")
157171
}
158-
172+
chunkMetadataBytes += signedChunk.size
159173
// append the body
160174
signedChunk.write(chunkBody)
161175

@@ -183,7 +197,7 @@ internal class AwsChunkedReader(
183197
writeUtf8("\r\n")
184198
writeAll(bodyBuffer) // append the body
185199
}
186-
200+
chunkMetadataBytes += unsignedChunk.size - bodyBuffer.size
187201
return unsignedChunk
188202
}
189203

0 commit comments

Comments
 (0)