Skip to content

Commit ddc62d9

Browse files
Fix over-sized response handling (#33)
1 parent 235ac2d commit ddc62d9

File tree

6 files changed

+26
-9
lines changed

6 files changed

+26
-9
lines changed

Diff for: cmd/localstack/custom_interop.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package main
66
import (
77
"bytes"
88
"encoding/json"
9+
"errors"
910
"fmt"
1011
"github.com/go-chi/chi"
1112
log "github.com/sirupsen/logrus"
@@ -117,8 +118,8 @@ func NewCustomInteropServer(lsOpts *LsOpts, delegate interop.Server, logCollecto
117118
timeout := int(server.delegate.GetInvokeTimeout().Seconds())
118119
isErr := false
119120
if err != nil {
120-
switch err {
121-
case rapidcore.ErrInvokeTimeout:
121+
switch {
122+
case errors.Is(err, rapidcore.ErrInvokeTimeout):
122123
log.Debugf("Got invoke timeout")
123124
isErr = true
124125
errorResponse := ErrorResponse{
@@ -137,6 +138,8 @@ func NewCustomInteropServer(lsOpts *LsOpts, delegate interop.Server, logCollecto
137138
if err != nil {
138139
log.Fatalln("unable to write to response")
139140
}
141+
case errors.Is(err, rapidcore.ErrInvokeDoneFailed):
142+
// we can actually just continue here, error message is sent below
140143
default:
141144
log.Fatalln(err)
142145
}

Diff for: cmd/localstack/main.go

+11
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package main
55
import (
66
"context"
77
log "github.com/sirupsen/logrus"
8+
"go.amzn.com/lambda/interop"
89
"go.amzn.com/lambda/rapidcore"
910
"os"
1011
"runtime/debug"
@@ -28,6 +29,7 @@ type LsOpts struct {
2829
EdgePort string
2930
EnableXRayTelemetry string
3031
PostInvokeWaitMS string
32+
MaxPayloadSize string
3133
}
3234

3335
func GetEnvOrDie(env string) string {
@@ -50,6 +52,7 @@ func InitLsOpts() *LsOpts {
5052
User: GetenvWithDefault("LOCALSTACK_USER", "sbx_user1051"),
5153
InitLogLevel: GetenvWithDefault("LOCALSTACK_INIT_LOG_LEVEL", "warn"),
5254
EdgePort: GetenvWithDefault("EDGE_PORT", "4566"),
55+
MaxPayloadSize: GetenvWithDefault("LOCALSTACK_MAX_PAYLOAD_SIZE", "6291556"),
5356
// optional or empty
5457
CodeArchives: os.Getenv("LOCALSTACK_CODE_ARCHIVES"),
5558
HotReloadingPaths: strings.Split(GetenvWithDefault("LOCALSTACK_HOT_RELOADING_PATHS", ""), ","),
@@ -77,6 +80,7 @@ func UnsetLsEnvs() {
7780
"LOCALSTACK_INIT_LOG_LEVEL",
7881
"LOCALSTACK_POST_INVOKE_WAIT_MS",
7982
"LOCALSTACK_FUNCTION_ACCOUNT_ID",
83+
"LOCALSTACK_MAX_PAYLOAD_SIZE",
8084

8185
// Docker container ID
8286
"HOSTNAME",
@@ -128,6 +132,13 @@ func main() {
128132
log.Fatal("Invalid value for LOCALSTACK_INIT_LOG_LEVEL")
129133
}
130134

135+
// patch MaxPayloadSize
136+
payloadSize, err := strconv.Atoi(lsOpts.MaxPayloadSize)
137+
if err != nil {
138+
log.Panicln("Please specify a number for LOCALSTACK_MAX_PAYLOAD_SIZE")
139+
}
140+
interop.MaxPayloadSize = payloadSize
141+
131142
// enable dns server
132143
dnsServerContext, stopDnsServer := context.WithCancel(context.Background())
133144
go RunDNSRewriter(lsOpts, dnsServerContext)

Diff for: debugging/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Golang EOL overview: https://endoflife.date/go
2-
DOCKER_GOLANG_IMAGE ?= golang:1.19
2+
DOCKER_GOLANG_IMAGE ?= golang:1.20-bullseye
33

44
# On ARM hosts, use: make ARCH=arm64 build-init
55
# Check host architecture: uname -m

Diff for: lambda/core/directinvoke/directinvoke.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3+
// LOCALSTACK CHANGES 2024-02-13: casting of MaxPayloadSize
34

45
package directinvoke
56

@@ -51,7 +52,7 @@ var ResetReasonMap = map[string]fatalerror.ErrorType{
5152
"timeout": fatalerror.SandboxTimeout,
5253
}
5354

54-
var MaxDirectResponseSize int64 = interop.MaxPayloadSize // this is intentionally not a constant so we can configure it via CLI
55+
var MaxDirectResponseSize = int64(interop.MaxPayloadSize) // this is intentionally not a constant so we can configure it via CLI
5556
var ResponseBandwidthRate int64 = interop.ResponseBandwidthRate
5657
var ResponseBandwidthBurstSize int64 = interop.ResponseBandwidthBurstSize
5758

@@ -104,7 +105,7 @@ func ReceiveDirectInvoke(w http.ResponseWriter, r *http.Request, token interop.T
104105

105106
now := metering.Monotime()
106107

107-
MaxDirectResponseSize = interop.MaxPayloadSize
108+
MaxDirectResponseSize = int64(interop.MaxPayloadSize)
108109
if maxPayloadSize := r.Header.Get(MaxPayloadSizeHeader); maxPayloadSize != "" {
109110
if n, err := strconv.ParseInt(maxPayloadSize, 10, 64); err == nil && n >= -1 {
110111
MaxDirectResponseSize = n

Diff for: lambda/interop/model.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3+
// LOCALSTACK CHANGES 2024-02-13: adjust error message for ErrorResponseTooLarge to be in parity with what AWS returns; make MaxPayloadSize adjustable
34

45
package interop
56

@@ -18,10 +19,10 @@ import (
1819
log "github.com/sirupsen/logrus"
1920
)
2021

22+
var MaxPayloadSize int = 6*1024*1024 + 100 // 6 MiB + 100 bytes
23+
2124
// MaxPayloadSize max event body size declared as LAMBDA_EVENT_BODY_SIZE
2225
const (
23-
MaxPayloadSize = 6*1024*1024 + 100 // 6 MiB + 100 bytes
24-
2526
ResponseBandwidthRate = 2 * 1024 * 1024 // default average rate of 2 MiB/s
2627
ResponseBandwidthBurstSize = 6 * 1024 * 1024 // default burst size of 6 MiB
2728

@@ -355,7 +356,7 @@ type ErrorResponseTooLargeDI struct {
355356

356357
// ErrorResponseTooLarge is returned when response provided by Runtime does not fit into shared memory buffer
357358
func (s *ErrorResponseTooLarge) Error() string {
358-
return fmt.Sprintf("Response payload size (%d bytes) exceeded maximum allowed payload size (%d bytes).", s.ResponseSize, s.MaxResponseSize)
359+
return fmt.Sprintf("Response payload size exceeded maximum allowed payload size (%d bytes).", s.MaxResponseSize)
359360
}
360361

361362
// AsErrorResponse generates ErrorInvokeResponse from ErrorResponseTooLarge

Diff for: lambda/rapi/rendering/rendering.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3+
// LOCALSTACK CHANGES 2024-02-13: casting of MaxPayloadSize
34

45
package rendering
56

@@ -174,7 +175,7 @@ func (s *InvokeRenderer) bufferInvokeRequest() error {
174175
defer s.requestMutex.Unlock()
175176
var err error = nil
176177
if s.requestBuffer.Len() == 0 {
177-
reader := io.LimitReader(s.invoke.Payload, interop.MaxPayloadSize)
178+
reader := io.LimitReader(s.invoke.Payload, int64(interop.MaxPayloadSize))
178179
start := time.Now()
179180
_, err = s.requestBuffer.ReadFrom(reader)
180181
s.metrics = InvokeRendererMetrics{

0 commit comments

Comments
 (0)