Skip to content

fix: normalize the case of hosts carried on a service - #13781

Merged
AlinsRan merged 1 commit into
apache:masterfrom
AlinsRan:fix/service-hosts-lowercase
Aug 7, 2026
Merged

fix: normalize the case of hosts carried on a service#13781
AlinsRan merged 1 commit into
apache:masterfrom
AlinsRan:fix/service-hosts-lowercase

Conversation

@AlinsRan

@AlinsRan AlinsRan commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Description

Hostnames are case-insensitive, and route matching runs against $host, which nginx always lowercases (ngx_http_validate_host()). apisix/router.lua normalizes this on the route object:

if route.value.host then
    route.value.host = str_lower(route.value.host)
elseif route.value.hosts then
    for i, v in ipairs(route.value.hosts) do
        route.value.hosts[i] = str_lower(v)
    end
end

apisix/http/service.lua has no equivalent, so service.hosts is stored verbatim. radixtree_host_uri — the default router — builds its host buckets itself, keyed on the raw reversed host string:

-- apisix/http/router/radixtree_host_uri.lua
for i, host in ipairs(hosts) do
    local host_rev = host:reverse()

A service host containing an uppercase character therefore ends up in a bucket keyed on e.g. moc.elpmaxe.esaCdexiM, which the lowercase $host can never reach. The route falls through to only_uri_router, and if nothing host-agnostic matches, the request 404s — for every path and every casing of the request Host, so the host is silently unroutable.

radixtree_uri is not affected, because it passes hosts to lua-resty-radixtree, which lowercases on both the config side and the request side.

Reproduced on 3.16.0 in standalone mode, with service.hosts: ["MixedCase.example.com"] and a route with no hosts of its own:

request Host radixtree_host_uri (default) radixtree_uri after this patch
MixedCase.example.com 404 200 200
mixedcase.example.com 404 200 200
MIXEDCASE.EXAMPLE.COM 404 200 200

This patch lowercases the hosts in the service filter(), mirroring what router.lua already does for routes.

The new t/router/radixtree-host-uri3.t TEST 10 covers it — its functional assertions pass with the patch and fail without it:

# with the fix
ok 29 - TEST 10: hosts in services are matched case-insensitively - status code ok
ok 30 - TEST 10: hosts in services are matched case-insensitively - response_body - response is expected

# with apisix/http/service.lua reverted
not ok 30 - TEST 10: hosts in services are matched case-insensitively - response_body - response is expected

Found via apache/apisix-ingress-controller#2822: the controller carries the host constraint on the service object, so an ingress route with an uppercase hostname is unroutable.

Which issue(s) this PR fixes:

N/A

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible (If not, please discuss on the APISIX mailing list first)

Hostnames are case-insensitive and are matched against `$host`, which nginx
always lowercases. `apisix/router.lua` lowercases route-level hosts, but
service-level hosts were stored verbatim, and `radixtree_host_uri` buckets
routes by the raw reversed host string. A service host containing an
uppercase character therefore landed in a bucket no request could ever
reach, and every request for that host returned 404.

`radixtree_uri` was not affected: lua-resty-radixtree lowercases hosts on
both the config and the request side.

@membphis membphis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@AlinsRan
AlinsRan merged commit 78800ae into apache:master Aug 7, 2026
17 checks passed
@AlinsRan
AlinsRan deleted the fix/service-hosts-lowercase branch August 7, 2026 05:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants