From 3f3cc9b04aec8d2bee0fd327a45c4c361bada932 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Fri, 31 Oct 2025 17:59:58 +0100 Subject: [PATCH 1/2] Log a warning when hitting the HTTP headers max size --- src/Event/Http/HttpHandler.php | 4 ++-- src/Event/Http/HttpResponse.php | 38 +++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/Event/Http/HttpHandler.php b/src/Event/Http/HttpHandler.php index ebd7092d5..6e61793c1 100644 --- a/src/Event/Http/HttpHandler.php +++ b/src/Event/Http/HttpHandler.php @@ -25,9 +25,9 @@ public function handle($event, Context $context): array $response = $this->handleRequest($httpEvent, $context); if ($httpEvent->isFormatV2()) { - return $response->toApiGatewayFormatV2(); + return $response->toApiGatewayFormatV2($context->getAwsRequestId()); } - return $response->toApiGatewayFormat($httpEvent->hasMultiHeader()); + return $response->toApiGatewayFormat($httpEvent->hasMultiHeader(), $context->getAwsRequestId()); } } diff --git a/src/Event/Http/HttpResponse.php b/src/Event/Http/HttpResponse.php index 80a679bc2..eda186c62 100644 --- a/src/Event/Http/HttpResponse.php +++ b/src/Event/Http/HttpResponse.php @@ -21,7 +21,7 @@ public function __construct(string $body, array $headers = [], int $statusCode = $this->statusCode = $statusCode; } - public function toApiGatewayFormat(bool $multiHeaders = false): array + public function toApiGatewayFormat(bool $multiHeaders = false, ?string $awsRequestId = null): array { $base64Encoding = (bool) getenv('BREF_BINARY_RESPONSES'); @@ -38,6 +38,8 @@ public function toApiGatewayFormat(bool $multiHeaders = false): array } } + $this->checkHeadersSize($headers, $awsRequestId); + // The headers must be a JSON object. If the PHP array is empty it is // serialized to `[]` (we want `{}`) so we force it to an empty object. $headers = empty($headers) ? new \stdClass : $headers; @@ -58,7 +60,7 @@ public function toApiGatewayFormat(bool $multiHeaders = false): array /** * See https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.response */ - public function toApiGatewayFormatV2(): array + public function toApiGatewayFormatV2(?string $awsRequestId = null): array { $base64Encoding = (bool) getenv('BREF_BINARY_RESPONSES'); @@ -76,6 +78,11 @@ public function toApiGatewayFormatV2(): array } } + $this->checkHeadersSize([ + ...$headers, + 'Set-Cookie' => $cookies, // include cookies in the size check + ], $awsRequestId); + // The headers must be a JSON object. If the PHP array is empty it is // serialized to `[]` (we want `{}`) so we force it to an empty object. $headers = empty($headers) ? new \stdClass : $headers; @@ -98,4 +105,31 @@ private function capitalizeHeaderName(string $name): string $name = ucwords($name); return str_replace(' ', '-', $name); } + + /** + * API Gateway v1 and v2 have a headers total max size of 10 KB. + * ALB has a max size of 32 KB. + * It's hard to calculate the exact size of headers here, so we just + * estimate it roughly: if above 9.5 KB we log a warning. + * + * @param array $headers + */ + private function checkHeadersSize(array $headers, ?string $awsRequestId): void + { + $estimatedHeadersSize = 0; + foreach ($headers as $name => $values) { + $estimatedHeadersSize += strlen($name); + if (is_array($values)) { + foreach ($values as $value) { + $estimatedHeadersSize += strlen($value); + } + } else { + $estimatedHeadersSize += strlen($values); + } + } + + if ($estimatedHeadersSize > 9_500) { + echo "$awsRequestId\tWARNING\tThe total size of HTTP response headers is estimated to be above 10 KB, which is the API Gateway limit. If the limit is reached, the HTTP response will be a 500 error.\n"; + } + } } From 9ee905678decfa93d66e0a6ef26506ad0cd424d1 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Fri, 31 Oct 2025 18:05:59 +0100 Subject: [PATCH 2/2] Fix --- src/Event/Http/HttpResponse.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Event/Http/HttpResponse.php b/src/Event/Http/HttpResponse.php index eda186c62..76c24d5d7 100644 --- a/src/Event/Http/HttpResponse.php +++ b/src/Event/Http/HttpResponse.php @@ -78,10 +78,10 @@ public function toApiGatewayFormatV2(?string $awsRequestId = null): array } } - $this->checkHeadersSize([ - ...$headers, - 'Set-Cookie' => $cookies, // include cookies in the size check - ], $awsRequestId); + $this->checkHeadersSize(array_merge( + $headers, + ['Set-Cookie' => $cookies], // include cookies in the size check + ), $awsRequestId); // The headers must be a JSON object. If the PHP array is empty it is // serialized to `[]` (we want `{}`) so we force it to an empty object.