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

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions