Skip to content

fix(aws-lambda): combine ALB multi-value headers per RFC 9110#4902

Open
rokasta12 wants to merge 1 commit into
honojs:mainfrom
rokasta12:fix/aws-lambda-alb-multi-value-separator
Open

fix(aws-lambda): combine ALB multi-value headers per RFC 9110#4902
rokasta12 wants to merge 1 commit into
honojs:mainfrom
rokasta12:fix/aws-lambda-alb-multi-value-separator

Conversation

@rokasta12
Copy link
Copy Markdown
Contributor

Problem

`ALBProcessor.getHeaders` (`src/adapter/aws-lambda/handler.ts:511-518`) joined every multi-valued header with `'; '`:

```ts
if (event.multiValueHeaders) {
for (const [key, values] of Object.entries(event.multiValueHeaders)) {
if (values && Array.isArray(values)) {
const sanitizedValue = sanitizeHeaderValue(values.join('; '))
headers.set(key, sanitizedValue)
}
}
}
```

RFC 9110 §5.3 requires `, ` as the separator when combining field-line values; `; ` is only correct for the `Cookie` request header (RFC 6265 §5.4) and a handful of structured headers using parameters.

A real client sending:

```
Accept: text/html
Accept: application/json
```

is delivered to ALB as `multiValueHeaders: { accept: ['text/html', 'application/json'] }` and reaches the Hono handler as the single value `text/html; application/json`. Content-negotiation libraries (and Hono's own `c.req.header('accept')` consumers) interpret that as one media range with a parameter, not two distinct ranges. The same flaw affects `Cache-Control`, `Forwarded`, `If-None-Match`, `Accept-Language`, `Vary`, `Link`, etc.

Fix

Append each value individually so the WHATWG `Headers` combine them with `, ` automatically. Special-case `cookie` (case-insensitive) to keep the `; ` join, matching the existing test expectation and RFC 6265.

```ts
if (key.toLowerCase() === 'cookie') {
headers.set(key, sanitizeHeaderValue(values.join('; ')))
} else {
for (const value of values) {
headers.append(key, sanitizeHeaderValue(value))
}
}
```

Test

Added two tests under `EventProcessor.createRequest > ALBProcessor multi-value header handling`:

  1. Non-cookie multi-value — sends two `Accept` values plus two `Cache-Control` values via `multiValueHeaders`, asserts `request.headers.get('accept')` returns `'text/html, application/json'` and `cache-control` returns `'no-cache, no-store'`. Fails on `main` (returns `'text/html; application/json'`); passes with the fix.

  2. Cookie still uses `; ` — confirms the special case continues to behave correctly per RFC 6265.

  • Add tests
  • Run tests (`bun run test` — 31/31 passes)
  • `bun run format:fix && bun run lint:fix`
  • Add TSDoc/JSDoc — no API surface change

`ALBProcessor.getHeaders` joined every multi-valued header with `'; '`,
but RFC 9110 §5.3 specifies `, ` as the separator for combining
field-line values. The previous behavior turned a request with two
`Accept` values into the single non-conformant value
`text/html; application/json`, which downstream content negotiation
treats as one media range with a parameter rather than two distinct
ranges. The same misjoin affected `Cache-Control`, `Forwarded`,
`If-None-Match`, `Accept-Language`, etc.

Now the loop appends each value individually, so the WHATWG Headers
combine them with `, ` automatically. The Cookie header keeps its
existing `'; '` join because RFC 6265 §5.4 requires that separator
for cookies inside a single Cookie request header.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant