Skip to content

Normalize The HTTP Method When Building The Route Table#178

Merged
stevehu merged 1 commit into
masterfrom
175-http-method-case-mismatch-causes-configured-routes-to-never-match
Jul 21, 2026
Merged

Normalize The HTTP Method When Building The Route Table#178
stevehu merged 1 commit into
masterfrom
175-http-method-case-mismatch-causes-configured-routes-to-never-match

Conversation

@stevehu

@stevehu stevehu commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Fixes #175.

Stacked on #177. The base branch is #177, not master, because the #175 fix cannot be tested without the seam #177 introduces — LambdaProxyMiddleware's only constructor builds a real LambdaAsyncClient. Please merge #177 first; GitHub will retarget this to master automatically. The diff shown here is only this change.

The bug

The route table was keyed by the raw method from configuration, while lookups used the lower cased request method:

var method = exchange.getRequest().getHttpMethod().toLowerCase();  // lookup: "get"
var method = endpoint[1];                                          // registration: "GET"

So /v1/pets@GET registered a route that no request could ever reach. Before #174 this surfaced as an NPE; since #174 it fails as a clean ERR10086, which is correct handling for a routing miss but makes the misconfiguration silent — the route is simply dead.

Changes

  • normalizeMethod applied on both registration and lookup, so the two sides cannot drift again.
  • Locale.ROOT rather than the default locale. OPTIONS contains an I, so under a Turkish default locale toLowerCase() yields optıons with a dotless i and the route breaks. This is why the helper exists rather than just adding .toLowerCase() at the registration site.
  • Split on the last @ instead of every @, so a path containing the separator still parses.
  • Malformed keys are skipped with a logged error instead of throwing ArrayIndexOutOfBoundsException during construction. A single bad entry taking down every invocation of the proxy seemed the worse failure mode, but say the word if you would rather fail fast at startup.
  • Dropped the redundant putcomputeIfAbsent already inserts and the matcher is mutated in place.

Verification

The five new tests were run against the pre-fix source and all fail with exactly the reported symptoms:

testUpperCaseConfiguredMethodStillRoutes:104            expected: <PetsGetFunction> but was: <null>
testMixedCaseConfiguredMethodStillRoutes:110            expected: <PetsDeleteFunction> but was: <null>
testUpperCaseConfiguredMethodIsReachableByAnUpperCaseRequest:122
                                                        expected: <PetsPostFunction> but was: <null>
testMalformedConfigurationKeysAreSkippedWithoutFailingStartup:144
                            ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
testPathContainingSeparatorIsSplitOnTheLastSeparator:132 » Runtime

With the fix: Tests run: 84, Failures: 0, Errors: 0, Skipped: 4 — 79 from #177, 5 added. BUILD SUCCESS, git diff --check clean.

Compatibility

Existing all-lowercase configurations are unaffected — values.yml in the test resources already uses lowercase, and the full suite passes unchanged. Configurations that currently use upper or mixed case will start routing where they previously returned ERR10086. That is the intent of the fix, but it is a behaviour change worth calling out.

🤖 Generated with Claude Code

The route table was keyed by the raw method from the configuration while
lookups used the lower cased request method, so a key written as
/v1/pets@GET registered a route that no request could reach. Since #174
that failed as a clean ERR10086 instead of an NPE, which made the
misconfiguration silent.

Normalize both sides through a single normalizeMethod helper using
Locale.ROOT, so an OPTIONS route is not broken by the Turkish dotless i
under a non-ROOT default locale.

Also split the configuration key on the last '@' rather than every '@', so
a path containing the separator still parses, and skip a malformed key with
a logged error instead of throwing ArrayIndexOutOfBoundsException during
construction. Drop the redundant put; computeIfAbsent already inserts and
the matcher is mutated in place.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Base automatically changed from 176-add-regression-test-coverage-for-lambdaproxymiddleware-route-miss to master July 21, 2026 19:11
@stevehu

stevehu commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

The patch consistently normalizes configured and incoming HTTP methods with Locale.ROOT, safely parses endpoint keys using the final separator, and adds targeted regression coverage. No actionable correctness issue was identified.

@stevehu
stevehu merged commit 0bc6252 into master Jul 21, 2026
@stevehu
stevehu deleted the 175-http-method-case-mismatch-causes-configured-routes-to-never-match branch July 21, 2026 19:16
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.

HTTP Method Case Mismatch Causes Configured Routes To Never Match

1 participant