You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When handling the connection, all body data chunks should be collected into the requestBody buffer from the inbound stream for processing.
Actual behavior
The requestBody buffer is repeatedly reset to the last chunk received, so that only the last chunk is sent for processing.
Steps to reproduce
Create a sample StreamingLambdaHandler and run it locally.
Feed a decent amount of data to the invoke endpoint (my test data is around 260KB, but I don't think it needs to be anywhere near that large to get split into chunks).
Log the event data.
Observe that only the last chunk of body data is processed.
If possible, minimal yet complete reproducer code (or URL to code)
/// This method handles individual TCP connections
private func handleConnection(
channel: NIOAsyncChannel<HTTPServerRequestPart, HTTPServerResponsePart>
) async {
var requestHead: HTTPRequestHead!
var requestBody: ByteBuffer?
// Note that this method is non-throwing and we are catching any error.
// We do this since we don't want to tear down the whole server when a single connection
// encounters an error.
do {
try await channel.executeThenClose { inbound, outbound in
for try await inboundData in inbound {
if case .head(let head) = inboundData {
requestHead = head
}
if case .body(let body) = inboundData {
requestBody = body
}
if case .end = inboundData {
precondition(requestHead != nil, "Received .end without .head")
// process the request
let response = try await self.processRequest(
head: requestHead,
body: requestBody
)
// send the responses
try await self.sendResponse(
response: response,
outbound: outbound
)
requestHead = nil
requestBody = nil
}
}
}
} catch {
logger.error("Hit error: \(error)")
}
}
Within the closure for executeThenClose, each inboundData chunk arrives, and if it is determined to be .body data, the requestBody variable is reassigned to the newest chunk. When the .end case is reached, only the last chunk of body data has been captured for processing.
Recommendation
An easy change would be to replace requestBody = body with requestBody.setOrWriteImmutableBuffer(body). This would allow the body chunks to accumulate in the requestBody buffer.
I've not spent much time evaluating potential edge cases, but the following modification works without issue in my own environment:
/// This method handles individual TCP connections
///
/// - Note: This method is non-throwing and we are catching any error. This
/// was done so that we don't tear down the whole server when a single
/// connection encounters an error.
private func handleConnection(channel: NIOAsyncChannel<HTTPServerRequestPart, HTTPServerResponsePart>) async {
var requestHead: HTTPRequestHead!
var requestBody: ByteBuffer?
do {
try await channel.executeThenClose { inbound, outbound in
for try await inboundData in inbound {
switch inboundData {
case .head(let head): requestHead = head
case .body(let body): requestBody.setOrWriteImmutableBuffer(body)
case .end:
precondition(requestHead != nil, "Received .end without .head")
// Process the request and send the responses.
let response = try await self.processRequest(head: requestHead, body: requestBody)
try await self.sendResponse(response: response, outbound: outbound)
requestHead = nil
requestBody = nil
}
}
}
} catch {
logger.error("Hit error: \(error)")
}
}
swift-aws-lambda-runtime version
main@40e2291532fdc0cf2e54f285bf33dc37b740646f
Swift version
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.9 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0
Darwin XYHY90YH44 24.3.0 Darwin Kernel Version 24.3.0: Thu Jan 2 20:24:23 PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6020 arm64
Amazon Linux 2 docker image version
6.0-amazonlinux2
Thanks
I'm tremendously grateful to this project's contributors for their time spent evaluating this issue, and for the great work they've done as a whole. As part of my efforts to promote Swift as a general-purpose language beyond it's iOS-app-shaped pigeonhole, the swift-aws-lambda-runtime package has allowed me to deliver a particularly simple and impactful demonstration of the benefits and possibilities afforded by the language.
The text was updated successfully, but these errors were encountered:
Expected behavior
When handling the connection, all body data chunks should be collected into the
requestBody
buffer from the inbound stream for processing.Actual behavior
The
requestBody
buffer is repeatedly reset to the last chunk received, so that only the last chunk is sent for processing.Steps to reproduce
StreamingLambdaHandler
and run it locally.invoke
endpoint (my test data is around 260KB, but I don't think it needs to be anywhere near that large to get split into chunks).If possible, minimal yet complete reproducer code (or URL to code)
Sample
StreamingLambdaHandler
Invocation with
curl
cat ./TestData.json | curl --json '@-' 'http://localhost:7000/invoke'
Root Cause
The issue seems to reside in the
handleConnection()
function in /Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift:163–204:Within the closure for
executeThenClose
, eachinboundData
chunk arrives, and if it is determined to be.body
data, therequestBody
variable is reassigned to the newest chunk. When the.end
case is reached, only the last chunk of body data has been captured for processing.Recommendation
An easy change would be to replace
requestBody = body
withrequestBody.setOrWriteImmutableBuffer(body)
. This would allow the body chunks to accumulate in therequestBody
buffer.I've not spent much time evaluating potential edge cases, but the following modification works without issue in my own environment:
swift-aws-lambda-runtime
versionmain@40e2291532fdc0cf2e54f285bf33dc37b740646f
Swift version
Amazon Linux 2 docker image version
6.0-amazonlinux2
Thanks
I'm tremendously grateful to this project's contributors for their time spent evaluating this issue, and for the great work they've done as a whole. As part of my efforts to promote Swift as a general-purpose language beyond it's iOS-app-shaped pigeonhole, the
swift-aws-lambda-runtime
package has allowed me to deliver a particularly simple and impactful demonstration of the benefits and possibilities afforded by the language.The text was updated successfully, but these errors were encountered: