mirror of https://github.com/status-im/consul.git
Case sensitive route match (#19647)
Add case insensitive param on service route match This commit adds in a new feature that allows service routers to specify that paths and path prefixes should ignore upper / lower casing when matching URLs. Co-authored-by: Derek Menteer <105233703+hashi-derek@users.noreply.github.com>
This commit is contained in:
parent
34b343a980
commit
758ddf84e9
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
connect: Add `CaseInsensitive` flag to service-routers that allows paths and path prefixes to ignore URL upper and lower casing.
|
||||||
|
```
|
|
@ -372,9 +372,10 @@ func (m *ServiceRouteMatch) IsEmpty() bool {
|
||||||
|
|
||||||
// ServiceRouteHTTPMatch is a set of http-specific match criteria.
|
// ServiceRouteHTTPMatch is a set of http-specific match criteria.
|
||||||
type ServiceRouteHTTPMatch struct {
|
type ServiceRouteHTTPMatch struct {
|
||||||
PathExact string `json:",omitempty" alias:"path_exact"`
|
PathExact string `json:",omitempty" alias:"path_exact"`
|
||||||
PathPrefix string `json:",omitempty" alias:"path_prefix"`
|
PathPrefix string `json:",omitempty" alias:"path_prefix"`
|
||||||
PathRegex string `json:",omitempty" alias:"path_regex"`
|
PathRegex string `json:",omitempty" alias:"path_regex"`
|
||||||
|
CaseInsensitive bool `json:",omitempty" alias:"case_insensitive"`
|
||||||
|
|
||||||
Header []ServiceRouteHTTPMatchHeader `json:",omitempty"`
|
Header []ServiceRouteHTTPMatchHeader `json:",omitempty"`
|
||||||
QueryParam []ServiceRouteHTTPMatchQueryParam `json:",omitempty" alias:"query_param"`
|
QueryParam []ServiceRouteHTTPMatchQueryParam `json:",omitempty" alias:"query_param"`
|
||||||
|
@ -385,6 +386,7 @@ func (m *ServiceRouteHTTPMatch) IsEmpty() bool {
|
||||||
return m.PathExact == "" &&
|
return m.PathExact == "" &&
|
||||||
m.PathPrefix == "" &&
|
m.PathPrefix == "" &&
|
||||||
m.PathRegex == "" &&
|
m.PathRegex == "" &&
|
||||||
|
!m.CaseInsensitive &&
|
||||||
len(m.Header) == 0 &&
|
len(m.Header) == 0 &&
|
||||||
len(m.QueryParam) == 0 &&
|
len(m.QueryParam) == 0 &&
|
||||||
len(m.Methods) == 0
|
len(m.Methods) == 0
|
||||||
|
|
|
@ -2742,6 +2742,20 @@ func TestServiceRouterConfigEntry(t *testing.T) {
|
||||||
}),
|
}),
|
||||||
validateErr: "contains an invalid retry condition: \"invalid-retry-condition\"",
|
validateErr: "contains an invalid retry condition: \"invalid-retry-condition\"",
|
||||||
},
|
},
|
||||||
|
////////////////
|
||||||
|
{
|
||||||
|
name: "default route with case insensitive match",
|
||||||
|
entry: makerouter(routeMatch(httpMatch(&ServiceRouteHTTPMatch{
|
||||||
|
CaseInsensitive: true,
|
||||||
|
}))),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "route with path prefix and case insensitive match /apI",
|
||||||
|
entry: makerouter(routeMatch(httpMatch(&ServiceRouteHTTPMatch{
|
||||||
|
PathPrefix: "/apI",
|
||||||
|
CaseInsensitive: true,
|
||||||
|
}))),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
|
|
|
@ -889,6 +889,310 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "service-router: kitchen sink case insensitive",
|
||||||
|
snake: `
|
||||||
|
kind = "service-router"
|
||||||
|
name = "main"
|
||||||
|
meta {
|
||||||
|
"foo" = "bar"
|
||||||
|
"gir" = "zim"
|
||||||
|
}
|
||||||
|
routes = [
|
||||||
|
{
|
||||||
|
match {
|
||||||
|
http {
|
||||||
|
path_exact = "/foo"
|
||||||
|
case_insensitive = true
|
||||||
|
header = [
|
||||||
|
{
|
||||||
|
name = "debug1"
|
||||||
|
present = true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "debug2"
|
||||||
|
present = false
|
||||||
|
invert = true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "debug3"
|
||||||
|
exact = "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "debug4"
|
||||||
|
prefix = "aaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "debug5"
|
||||||
|
suffix = "bbb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "debug6"
|
||||||
|
regex = "a.*z"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
destination {
|
||||||
|
service = "carrot"
|
||||||
|
service_subset = "kale"
|
||||||
|
namespace = "leek"
|
||||||
|
prefix_rewrite = "/alternate"
|
||||||
|
request_timeout = "99s"
|
||||||
|
idle_timeout = "99s"
|
||||||
|
num_retries = 12345
|
||||||
|
retry_on_connect_failure = true
|
||||||
|
retry_on_status_codes = [401, 209]
|
||||||
|
request_headers {
|
||||||
|
add {
|
||||||
|
x-foo = "bar"
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
bar = "baz"
|
||||||
|
}
|
||||||
|
remove = ["qux"]
|
||||||
|
}
|
||||||
|
response_headers {
|
||||||
|
add {
|
||||||
|
x-foo = "bar"
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
bar = "baz"
|
||||||
|
}
|
||||||
|
remove = ["qux"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
match {
|
||||||
|
http {
|
||||||
|
path_prefix = "/foo"
|
||||||
|
methods = [ "GET", "DELETE" ]
|
||||||
|
query_param = [
|
||||||
|
{
|
||||||
|
name = "hack1"
|
||||||
|
present = true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "hack2"
|
||||||
|
exact = "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name = "hack3"
|
||||||
|
regex = "a.*z"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
match {
|
||||||
|
http {
|
||||||
|
path_regex = "/foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`,
|
||||||
|
camel: `
|
||||||
|
Kind = "service-router"
|
||||||
|
Name = "main"
|
||||||
|
Meta {
|
||||||
|
"foo" = "bar"
|
||||||
|
"gir" = "zim"
|
||||||
|
}
|
||||||
|
Routes = [
|
||||||
|
{
|
||||||
|
Match {
|
||||||
|
HTTP {
|
||||||
|
PathExact = "/foo"
|
||||||
|
CaseInsensitive = true
|
||||||
|
Header = [
|
||||||
|
{
|
||||||
|
Name = "debug1"
|
||||||
|
Present = true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name = "debug2"
|
||||||
|
Present = false
|
||||||
|
Invert = true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name = "debug3"
|
||||||
|
Exact = "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name = "debug4"
|
||||||
|
Prefix = "aaa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name = "debug5"
|
||||||
|
Suffix = "bbb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name = "debug6"
|
||||||
|
Regex = "a.*z"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Destination {
|
||||||
|
Service = "carrot"
|
||||||
|
ServiceSubset = "kale"
|
||||||
|
Namespace = "leek"
|
||||||
|
PrefixRewrite = "/alternate"
|
||||||
|
RequestTimeout = "99s"
|
||||||
|
IdleTimeout = "99s"
|
||||||
|
NumRetries = 12345
|
||||||
|
RetryOnConnectFailure = true
|
||||||
|
RetryOnStatusCodes = [401, 209]
|
||||||
|
RequestHeaders {
|
||||||
|
Add {
|
||||||
|
x-foo = "bar"
|
||||||
|
}
|
||||||
|
Set {
|
||||||
|
bar = "baz"
|
||||||
|
}
|
||||||
|
Remove = ["qux"]
|
||||||
|
}
|
||||||
|
ResponseHeaders {
|
||||||
|
Add {
|
||||||
|
x-foo = "bar"
|
||||||
|
}
|
||||||
|
Set {
|
||||||
|
bar = "baz"
|
||||||
|
}
|
||||||
|
Remove = ["qux"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Match {
|
||||||
|
HTTP {
|
||||||
|
PathPrefix = "/foo"
|
||||||
|
Methods = [ "GET", "DELETE" ]
|
||||||
|
QueryParam = [
|
||||||
|
{
|
||||||
|
Name = "hack1"
|
||||||
|
Present = true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name = "hack2"
|
||||||
|
Exact = "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name = "hack3"
|
||||||
|
Regex = "a.*z"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Match {
|
||||||
|
HTTP {
|
||||||
|
PathRegex = "/foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`,
|
||||||
|
expect: &ServiceRouterConfigEntry{
|
||||||
|
Kind: "service-router",
|
||||||
|
Name: "main",
|
||||||
|
Meta: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"gir": "zim",
|
||||||
|
},
|
||||||
|
Routes: []ServiceRoute{
|
||||||
|
{
|
||||||
|
Match: &ServiceRouteMatch{
|
||||||
|
HTTP: &ServiceRouteHTTPMatch{
|
||||||
|
PathExact: "/foo",
|
||||||
|
CaseInsensitive: true,
|
||||||
|
Header: []ServiceRouteHTTPMatchHeader{
|
||||||
|
{
|
||||||
|
Name: "debug1",
|
||||||
|
Present: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "debug2",
|
||||||
|
Present: false,
|
||||||
|
Invert: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "debug3",
|
||||||
|
Exact: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "debug4",
|
||||||
|
Prefix: "aaa",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "debug5",
|
||||||
|
Suffix: "bbb",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "debug6",
|
||||||
|
Regex: "a.*z",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Destination: &ServiceRouteDestination{
|
||||||
|
Service: "carrot",
|
||||||
|
ServiceSubset: "kale",
|
||||||
|
Namespace: "leek",
|
||||||
|
PrefixRewrite: "/alternate",
|
||||||
|
RequestTimeout: 99 * time.Second,
|
||||||
|
IdleTimeout: 99 * time.Second,
|
||||||
|
NumRetries: 12345,
|
||||||
|
RetryOnConnectFailure: true,
|
||||||
|
RetryOnStatusCodes: []uint32{401, 209},
|
||||||
|
RequestHeaders: &HTTPHeaderModifiers{
|
||||||
|
Add: map[string]string{"x-foo": "bar"},
|
||||||
|
Set: map[string]string{"bar": "baz"},
|
||||||
|
Remove: []string{"qux"},
|
||||||
|
},
|
||||||
|
ResponseHeaders: &HTTPHeaderModifiers{
|
||||||
|
Add: map[string]string{"x-foo": "bar"},
|
||||||
|
Set: map[string]string{"bar": "baz"},
|
||||||
|
Remove: []string{"qux"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Match: &ServiceRouteMatch{
|
||||||
|
HTTP: &ServiceRouteHTTPMatch{
|
||||||
|
PathPrefix: "/foo",
|
||||||
|
Methods: []string{"GET", "DELETE"},
|
||||||
|
QueryParam: []ServiceRouteHTTPMatchQueryParam{
|
||||||
|
{
|
||||||
|
Name: "hack1",
|
||||||
|
Present: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "hack2",
|
||||||
|
Exact: "1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "hack3",
|
||||||
|
Regex: "a.*z",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Match: &ServiceRouteMatch{
|
||||||
|
HTTP: &ServiceRouteHTTPMatch{
|
||||||
|
PathRegex: "/foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "service-splitter: kitchen sink",
|
name: "service-splitter: kitchen sink",
|
||||||
snake: `
|
snake: `
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/hashicorp/consul/agent/xds/response"
|
"github.com/hashicorp/consul/agent/xds/response"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"google.golang.org/protobuf/types/known/durationpb"
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// routesFromSnapshot returns the xDS API representation of the "routes" in the
|
// routesFromSnapshot returns the xDS API representation of the "routes" in the
|
||||||
|
@ -859,6 +860,10 @@ func makeRouteMatchForDiscoveryRoute(discoveryRoute *structs.DiscoveryRoute) *en
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if match.HTTP.CaseInsensitive {
|
||||||
|
em.CaseSensitive = wrapperspb.Bool(false)
|
||||||
|
}
|
||||||
|
|
||||||
if len(match.HTTP.Header) > 0 {
|
if len(match.HTTP.Header) > 0 {
|
||||||
em.Headers = make([]*envoy_route_v3.HeaderMatcher, 0, len(match.HTTP.Header))
|
em.Headers = make([]*envoy_route_v3.HeaderMatcher, 0, len(match.HTTP.Header))
|
||||||
for _, hdr := range match.HTTP.Header {
|
for _, hdr := range match.HTTP.Header {
|
||||||
|
|
|
@ -41,9 +41,10 @@ type ServiceRouteMatch struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceRouteHTTPMatch struct {
|
type ServiceRouteHTTPMatch struct {
|
||||||
PathExact string `json:",omitempty" alias:"path_exact"`
|
PathExact string `json:",omitempty" alias:"path_exact"`
|
||||||
PathPrefix string `json:",omitempty" alias:"path_prefix"`
|
PathPrefix string `json:",omitempty" alias:"path_prefix"`
|
||||||
PathRegex string `json:",omitempty" alias:"path_regex"`
|
PathRegex string `json:",omitempty" alias:"path_regex"`
|
||||||
|
CaseInsensitive bool `json:",omitempty" alias:"case_insensitive"`
|
||||||
|
|
||||||
Header []ServiceRouteHTTPMatchHeader `json:",omitempty"`
|
Header []ServiceRouteHTTPMatchHeader `json:",omitempty"`
|
||||||
QueryParam []ServiceRouteHTTPMatchQueryParam `json:",omitempty" alias:"query_param"`
|
QueryParam []ServiceRouteHTTPMatchQueryParam `json:",omitempty" alias:"query_param"`
|
||||||
|
|
|
@ -121,6 +121,7 @@ func TestAPI_ConfigEntry_DiscoveryChain(t *testing.T) {
|
||||||
"alternate",
|
"alternate",
|
||||||
"test-split",
|
"test-split",
|
||||||
"test-route",
|
"test-route",
|
||||||
|
"test-route-case-insensitive",
|
||||||
} {
|
} {
|
||||||
serviceDefaults := &ServiceConfigEntry{
|
serviceDefaults := &ServiceConfigEntry{
|
||||||
Kind: ServiceDefaults,
|
Kind: ServiceDefaults,
|
||||||
|
@ -306,6 +307,67 @@ func TestAPI_ConfigEntry_DiscoveryChain(t *testing.T) {
|
||||||
},
|
},
|
||||||
verify: verifyRouter,
|
verify: verifyRouter,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "mega router case insensitive", // use one mega object to avoid multiple trips
|
||||||
|
entry: &ServiceRouterConfigEntry{
|
||||||
|
Kind: ServiceRouter,
|
||||||
|
Name: "test-route-case-insensitive",
|
||||||
|
Partition: defaultPartition,
|
||||||
|
Namespace: defaultNamespace,
|
||||||
|
Routes: []ServiceRoute{
|
||||||
|
{
|
||||||
|
Match: &ServiceRouteMatch{
|
||||||
|
HTTP: &ServiceRouteHTTPMatch{
|
||||||
|
PathPrefix: "/prEfix",
|
||||||
|
CaseInsensitive: true,
|
||||||
|
Header: []ServiceRouteHTTPMatchHeader{
|
||||||
|
{Name: "x-debug", Exact: "1"},
|
||||||
|
},
|
||||||
|
QueryParam: []ServiceRouteHTTPMatchQueryParam{
|
||||||
|
{Name: "debug", Exact: "1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Destination: &ServiceRouteDestination{
|
||||||
|
Service: "test-failover",
|
||||||
|
ServiceSubset: "v2",
|
||||||
|
Namespace: defaultNamespace,
|
||||||
|
Partition: defaultPartition,
|
||||||
|
PrefixRewrite: "/",
|
||||||
|
RequestTimeout: 5 * time.Second,
|
||||||
|
NumRetries: 5,
|
||||||
|
RetryOnConnectFailure: true,
|
||||||
|
RetryOnStatusCodes: []uint32{500, 503, 401},
|
||||||
|
RetryOn: []string{
|
||||||
|
"gateway-error",
|
||||||
|
"reset",
|
||||||
|
"envoy-ratelimited",
|
||||||
|
"retriable-4xx",
|
||||||
|
"refused-stream",
|
||||||
|
"cancelled",
|
||||||
|
"deadline-exceeded",
|
||||||
|
"internal",
|
||||||
|
"resource-exhausted",
|
||||||
|
"unavailable",
|
||||||
|
},
|
||||||
|
RequestHeaders: &HTTPHeaderModifiers{
|
||||||
|
Set: map[string]string{
|
||||||
|
"x-foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ResponseHeaders: &HTTPHeaderModifiers{
|
||||||
|
Remove: []string{"x-foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Meta: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"gir": "zim",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
verify: verifyRouter,
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
tc := tc
|
tc := tc
|
||||||
name := fmt.Sprintf("%s:%s: %s", tc.entry.GetKind(), tc.entry.GetName(), tc.name)
|
name := fmt.Sprintf("%s:%s: %s", tc.entry.GetKind(), tc.entry.GetName(), tc.name)
|
||||||
|
|
|
@ -59,6 +59,17 @@ routes = [
|
||||||
prefix_rewrite = "/"
|
prefix_rewrite = "/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
match { http {
|
||||||
|
path_prefix = "/prefix-case-insensitive/"
|
||||||
|
case_insensitive = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
destination {
|
||||||
|
service_subset = "v1"
|
||||||
|
prefix_rewrite = "/"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
match { http {
|
match { http {
|
||||||
path_regex = "/deb[ug]{2}"
|
path_regex = "/deb[ug]{2}"
|
||||||
|
|
|
@ -56,6 +56,11 @@ load helpers
|
||||||
assert_expected_fortio_name s2-v1 localhost 5000 /prefix-alt
|
assert_expected_fortio_name s2-v1 localhost 5000 /prefix-alt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "test prefix path case insensitive" {
|
||||||
|
assert_expected_fortio_name s2-v1 localhost 5000 /prefix-case-Insensitive
|
||||||
|
assert_expected_fortio_name s2-v1 localhost 5000 /prefix-case-INSENSITIVE
|
||||||
|
}
|
||||||
|
|
||||||
@test "test regex path" {
|
@test "test regex path" {
|
||||||
assert_expected_fortio_name s2-v2 localhost 5000 "" regex-path
|
assert_expected_fortio_name s2-v2 localhost 5000 "" regex-path
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ The following list outlines field hierarchy, language-specific data types, and r
|
||||||
- [`PathExact`](#routes-match-http-pathexact): string
|
- [`PathExact`](#routes-match-http-pathexact): string
|
||||||
- [`PathPrefix`](#routes-match-http-pathprefix): string
|
- [`PathPrefix`](#routes-match-http-pathprefix): string
|
||||||
- [`PathRegex`](#routes-match-http-pathregex): string
|
- [`PathRegex`](#routes-match-http-pathregex): string
|
||||||
|
- [`CaseInsensitive`](#routes-match-http-caseinsensitive): boolean | `false`
|
||||||
- [`Methods`](#routes-match-http-methods): list
|
- [`Methods`](#routes-match-http-methods): list
|
||||||
- [`Header`](#routes-match-http-header): list
|
- [`Header`](#routes-match-http-header): list
|
||||||
- [`Name`](#routes-match-http-header-name): string
|
- [`Name`](#routes-match-http-header-name): string
|
||||||
|
@ -456,6 +457,15 @@ Specifies the path prefix to match on the HTTP request path. When using this fie
|
||||||
- Default: None
|
- Default: None
|
||||||
- Data type: String
|
- Data type: String
|
||||||
|
|
||||||
|
### `Routes[].Match{}.HTTP{}.CaseInsensitive`
|
||||||
|
|
||||||
|
Specifies the path prefix to match on the HTTP request path must be case insensitive or not.
|
||||||
|
|
||||||
|
#### Values
|
||||||
|
|
||||||
|
- Default: `false`
|
||||||
|
- Data type: Boolean
|
||||||
|
|
||||||
### `Routes[].Match{}.HTTP{}.PathRegex`
|
### `Routes[].Match{}.HTTP{}.PathRegex`
|
||||||
|
|
||||||
Specifies a regular expression to match on the HTTP request path. When using this field, do not configure `PathExact` or `PathPrefix` in the same HTTP map. The syntax for the regular expression field is proxy-specific. When [using Envoy](/consul/docs/connect/proxies/envoy), refer to [the documentation for Envoy v1.11.2 or newer](https://github.com/google/re2/wiki/Syntax) or [the documentation for Envoy v1.11.1 or older](https://en.cppreference.com/w/cpp/regex/ecmascript), depending on the version of Envoy you use.
|
Specifies a regular expression to match on the HTTP request path. When using this field, do not configure `PathExact` or `PathPrefix` in the same HTTP map. The syntax for the regular expression field is proxy-specific. When [using Envoy](/consul/docs/connect/proxies/envoy), refer to [the documentation for Envoy v1.11.2 or newer](https://github.com/google/re2/wiki/Syntax) or [the documentation for Envoy v1.11.1 or older](https://en.cppreference.com/w/cpp/regex/ecmascript), depending on the version of Envoy you use.
|
||||||
|
@ -1372,6 +1382,78 @@ spec:
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
|
### Path prefix matching with case insensitive
|
||||||
|
|
||||||
|
The following example routes HTTP requests for the `web` service to a service named `admin` when they have `/admin` or `/Admin` at the start of their path.
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<Tab heading="HCL" group="hcl">
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
Kind = "service-router"
|
||||||
|
Name = "web"
|
||||||
|
Routes = [
|
||||||
|
{
|
||||||
|
Match {
|
||||||
|
HTTP {
|
||||||
|
PathPrefix = "/Admin"
|
||||||
|
CaseInsensitive = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Destination {
|
||||||
|
Service = "admin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab heading="YAML" group="yaml">
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: consul.hashicorp.com/v1alpha1
|
||||||
|
kind: ServiceRouter
|
||||||
|
metadata:
|
||||||
|
name: web
|
||||||
|
spec:
|
||||||
|
routes:
|
||||||
|
- match:
|
||||||
|
http:
|
||||||
|
pathPrefix: /Admin
|
||||||
|
caseInsensitive: true
|
||||||
|
destination:
|
||||||
|
service: admin
|
||||||
|
```
|
||||||
|
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab heading="JSON" group="json">
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Kind": "service-router",
|
||||||
|
"Name": "web",
|
||||||
|
"Routes": [
|
||||||
|
{
|
||||||
|
"Match": {
|
||||||
|
"HTTP": {
|
||||||
|
"PathPrefix": "/Admin",
|
||||||
|
"CaseInsensitive": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Destination": {
|
||||||
|
"Service": "admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
### Match a header and query parameter
|
### Match a header and query parameter
|
||||||
|
|
||||||
The following example routes HTTP traffic to the `web` service to a subset of `canary` instances when the requests have `x-debug` in either the header or the URL parameter.
|
The following example routes HTTP traffic to the `web` service to a subset of `canary` instances when the requests have `x-debug` in either the header or the URL parameter.
|
||||||
|
|
Loading…
Reference in New Issue