Skip to content

PathPrefix / catch-all route takes precedence over RegularExpression routes #16

@MarcWort

Description

@MarcWort

Hi,

I am using version 0.9.0. When configuring a default/catch-all route using PathPrefix: /, it always matches, even when a more specific RegularExpression rule should have matched first.

The Migrating from Ingress guide explicitly recommends this pattern for implementing a default backend:

The Ingress default backend configures a backend that will respond to all unmatched HTTP requests related to that Ingress resource. Gateway API does not have a direct equivalent: it is necessary to define such a routing rule explicitly. For example, define a rule to route requests with the path prefix / to a Service that corresponds to the default backend.

PathPrefix: / is evaluated before RegularExpression rules, so the catch-all backend always serves the request and the regex rule is never reached.

I am unsure if the behavior is strictly defined in Gateway API.

Note this is not about HAProxy's internal default_backend backend_not_found.

Reproduction

The following HTTPRoute:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: helloworld
  labels:
    app: helloworld
    service: helloworld
spec:
  parentRefs:
  - name: sample-gateway
  hostnames: ["helloworld.sample.com"]
  rules:
  - matches:
    - path:
        type: RegularExpression
        value: "/[Hh]ell[oO]"
    backendRefs:
    - name: helloworld
      port: 5000
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: custom-error-pages
      port: 8080

generates this config:

http-request set-var(txn.route,ifnotexists) path,map_beg(/usr/local/hug/maps/hug_http_80/path_prefix.map) # {"hug":"any domain + path prefix"}
http-request set-var(txn.route,ifnotexists) var(txn.base),map_end(/usr/local/hug/maps/hug_http_80/domain_wildcard_path_exact.map) # {"hug":"domain wildcard + exact path"}
http-request set-var(txn.route,ifnotexists) path,map_reg(/usr/local/hug/maps/hug_http_80/path_regex.map) # {"hug":"any domain + path regex"}
http-request set-var(txn.route,ifnotexists) var(txn.base),map_reg(/usr/local/hug/maps/hug_http_80/path_regex.map) # {"hug":"domain wildcard + path prefix or regex, exact domain + path regex"}

with these map files:

==> hug_http_80/domain_wildcard_path_exact.map <==

==> hug_http_80/domain_wildcard_sni.map <==

==> hug_http_80/path_exact.map <==

==> hug_http_80/path_prefix.map <==
helloworld.sample.com/ hug_test-development_custom-error-pages_8080__

==> hug_http_80/path_regex.map <==
^helloworld\.sample\.com/[Hh]ell[oO] hug_test-development_helloworld_5000__

==> hug_http_80/sni.map <==

Because path_prefix.map is evaluated first and ifnotexists short-circuits further evaluation, path_regex.map is never consulted. The custom-error-pages backend always wins.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions