parent
67f3da61af
commit
bd4a2d7be2
|
@ -3119,6 +3119,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
||||||
"match": {
|
"match": {
|
||||||
"http": {
|
"http": {
|
||||||
"path_prefix": "/foo",
|
"path_prefix": "/foo",
|
||||||
|
"methods": [ "GET", "DELETE" ],
|
||||||
"query_param": [
|
"query_param": [
|
||||||
{
|
{
|
||||||
"name": "hack1",
|
"name": "hack1",
|
||||||
|
@ -3202,6 +3203,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
||||||
match {
|
match {
|
||||||
http {
|
http {
|
||||||
path_prefix = "/foo"
|
path_prefix = "/foo"
|
||||||
|
methods = [ "GET", "DELETE" ]
|
||||||
query_param = [
|
query_param = [
|
||||||
{
|
{
|
||||||
name = "hack1"
|
name = "hack1"
|
||||||
|
@ -3284,6 +3286,7 @@ func TestConfigFlagsAndEdgecases(t *testing.T) {
|
||||||
Match: &structs.ServiceRouteMatch{
|
Match: &structs.ServiceRouteMatch{
|
||||||
HTTP: &structs.ServiceRouteHTTPMatch{
|
HTTP: &structs.ServiceRouteHTTPMatch{
|
||||||
PathPrefix: "/foo",
|
PathPrefix: "/foo",
|
||||||
|
Methods: []string{"GET", "DELETE"},
|
||||||
QueryParam: []structs.ServiceRouteHTTPMatchQueryParam{
|
QueryParam: []structs.ServiceRouteHTTPMatchQueryParam{
|
||||||
{
|
{
|
||||||
Name: "hack1",
|
Name: "hack1",
|
||||||
|
|
|
@ -58,6 +58,21 @@ func (e *ServiceRouterConfigEntry) Normalize() error {
|
||||||
|
|
||||||
e.Kind = ServiceRouter
|
e.Kind = ServiceRouter
|
||||||
|
|
||||||
|
for _, route := range e.Routes {
|
||||||
|
if route.Match == nil || route.Match.HTTP == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
httpMatch := route.Match.HTTP
|
||||||
|
if len(httpMatch.Methods) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for j := 0; j < len(httpMatch.Methods); j++ {
|
||||||
|
httpMatch.Methods[j] = strings.ToUpper(httpMatch.Methods[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +154,16 @@ func (e *ServiceRouterConfigEntry) Validate() error {
|
||||||
return fmt.Errorf("Route[%d] QueryParam[%d] should only contain one of Present, Exact, or Regex", i, j)
|
return fmt.Errorf("Route[%d] QueryParam[%d] should only contain one of Present, Exact, or Regex", i, j)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(route.Match.HTTP.Methods) > 0 {
|
||||||
|
found := make(map[string]struct{})
|
||||||
|
for _, m := range route.Match.HTTP.Methods {
|
||||||
|
if _, ok := found[m]; ok {
|
||||||
|
return fmt.Errorf("Route[%d] Methods contains %q more than once", i, m)
|
||||||
|
}
|
||||||
|
found[m] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if route.Destination != nil {
|
if route.Destination != nil {
|
||||||
|
@ -218,9 +243,7 @@ type ServiceRouteHTTPMatch struct {
|
||||||
|
|
||||||
Header []ServiceRouteHTTPMatchHeader `json:",omitempty"`
|
Header []ServiceRouteHTTPMatchHeader `json:",omitempty"`
|
||||||
QueryParam []ServiceRouteHTTPMatchQueryParam `json:",omitempty"`
|
QueryParam []ServiceRouteHTTPMatchQueryParam `json:",omitempty"`
|
||||||
|
Methods []string `json:",omitempty"`
|
||||||
// TODO(rb): reenable Methods
|
|
||||||
// Methods []string `json:",omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ServiceRouteHTTPMatch) IsEmpty() bool {
|
func (m *ServiceRouteHTTPMatch) IsEmpty() bool {
|
||||||
|
@ -228,8 +251,8 @@ func (m *ServiceRouteHTTPMatch) IsEmpty() bool {
|
||||||
m.PathPrefix == "" &&
|
m.PathPrefix == "" &&
|
||||||
m.PathRegex == "" &&
|
m.PathRegex == "" &&
|
||||||
len(m.Header) == 0 &&
|
len(m.Header) == 0 &&
|
||||||
len(m.QueryParam) == 0
|
len(m.QueryParam) == 0 &&
|
||||||
// && len(m.Methods) == 0
|
len(m.Methods) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceRouteHTTPMatchHeader struct {
|
type ServiceRouteHTTPMatchHeader struct {
|
||||||
|
|
|
@ -1099,6 +1099,28 @@ func TestServiceRouterConfigEntry(t *testing.T) {
|
||||||
}),
|
}),
|
||||||
validateErr: "cannot make use of PrefixRewrite without configuring either PathExact or PathPrefix",
|
validateErr: "cannot make use of PrefixRewrite without configuring either PathExact or PathPrefix",
|
||||||
},
|
},
|
||||||
|
////////////////
|
||||||
|
{
|
||||||
|
name: "route with method matches",
|
||||||
|
entry: makerouter(routeMatch(httpMatch(&ServiceRouteHTTPMatch{
|
||||||
|
Methods: []string{
|
||||||
|
"get", "POST", "dElEtE",
|
||||||
|
},
|
||||||
|
}))),
|
||||||
|
check: func(t *testing.T, entry *ServiceRouterConfigEntry) {
|
||||||
|
m := entry.Routes[0].Match.HTTP.Methods
|
||||||
|
require.Equal(t, []string{"GET", "POST", "DELETE"}, m)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "route with method matches repeated",
|
||||||
|
entry: makerouter(routeMatch(httpMatch(&ServiceRouteHTTPMatch{
|
||||||
|
Methods: []string{
|
||||||
|
"GET", "DELETE", "get",
|
||||||
|
},
|
||||||
|
}))),
|
||||||
|
validateErr: "Methods contains \"GET\" more than once",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
|
|
|
@ -168,6 +168,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
match {
|
match {
|
||||||
http {
|
http {
|
||||||
path_prefix = "/foo"
|
path_prefix = "/foo"
|
||||||
|
methods = [ "GET", "DELETE" ]
|
||||||
query_param = [
|
query_param = [
|
||||||
{
|
{
|
||||||
name = "hack1"
|
name = "hack1"
|
||||||
|
@ -246,6 +247,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
Match {
|
Match {
|
||||||
HTTP {
|
HTTP {
|
||||||
PathPrefix = "/foo"
|
PathPrefix = "/foo"
|
||||||
|
Methods = [ "GET", "DELETE" ]
|
||||||
QueryParam = [
|
QueryParam = [
|
||||||
{
|
{
|
||||||
Name = "hack1"
|
Name = "hack1"
|
||||||
|
@ -324,6 +326,7 @@ func TestDecodeConfigEntry(t *testing.T) {
|
||||||
Match: &ServiceRouteMatch{
|
Match: &ServiceRouteMatch{
|
||||||
HTTP: &ServiceRouteHTTPMatch{
|
HTTP: &ServiceRouteHTTPMatch{
|
||||||
PathPrefix: "/foo",
|
PathPrefix: "/foo",
|
||||||
|
Methods: []string{"GET", "DELETE"},
|
||||||
QueryParam: []ServiceRouteHTTPMatchQueryParam{
|
QueryParam: []ServiceRouteHTTPMatchQueryParam{
|
||||||
{
|
{
|
||||||
Name: "hack1",
|
Name: "hack1",
|
||||||
|
|
|
@ -3,6 +3,7 @@ package xds
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
|
|
||||||
|
@ -252,6 +253,18 @@ func makeRouteMatchForDiscoveryRoute(discoveryRoute *structs.DiscoveryRoute, pro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(match.HTTP.Methods) > 0 {
|
||||||
|
methodHeaderRegex := strings.Join(match.HTTP.Methods, "|")
|
||||||
|
|
||||||
|
eh := &envoyroute.HeaderMatcher{
|
||||||
|
Name: ":method",
|
||||||
|
HeaderMatchSpecifier: &envoyroute.HeaderMatcher_RegexMatch{
|
||||||
|
RegexMatch: methodHeaderRegex,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
em.Headers = append(em.Headers, eh)
|
||||||
|
}
|
||||||
|
|
||||||
if len(match.HTTP.QueryParam) > 0 {
|
if len(match.HTTP.QueryParam) > 0 {
|
||||||
em.QueryParameters = make([]*envoyroute.QueryParameterMatcher, 0, len(match.HTTP.QueryParam))
|
em.QueryParameters = make([]*envoyroute.QueryParameterMatcher, 0, len(match.HTTP.QueryParam))
|
||||||
for _, qm := range match.HTTP.QueryParam {
|
for _, qm := range match.HTTP.QueryParam {
|
||||||
|
|
|
@ -190,6 +190,24 @@ func TestRoutesFromSnapshot(t *testing.T) {
|
||||||
}),
|
}),
|
||||||
Destination: toService("hdr-regex"),
|
Destination: toService("hdr-regex"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Match: httpMatch(&structs.ServiceRouteHTTPMatch{
|
||||||
|
Methods: []string{"GET", "PUT"},
|
||||||
|
}),
|
||||||
|
Destination: toService("just-methods"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Match: httpMatch(&structs.ServiceRouteHTTPMatch{
|
||||||
|
Header: []structs.ServiceRouteHTTPMatchHeader{
|
||||||
|
{
|
||||||
|
Name: "x-debug",
|
||||||
|
Exact: "exact",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Methods: []string{"GET", "PUT"},
|
||||||
|
}),
|
||||||
|
Destination: toService("hdr-exact-with-method"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Match: httpMatchParam(structs.ServiceRouteHTTPMatchQueryParam{
|
Match: httpMatchParam(structs.ServiceRouteHTTPMatchQueryParam{
|
||||||
Name: "secretparam1",
|
Name: "secretparam1",
|
||||||
|
|
|
@ -120,6 +120,38 @@
|
||||||
"cluster": "hdr-regex.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
"cluster": "hdr-regex.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/",
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"name": ":method",
|
||||||
|
"regexMatch": "GET|PUT"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"cluster": "just-methods.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/",
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"name": "x-debug",
|
||||||
|
"exactMatch": "exact"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ":method",
|
||||||
|
"regexMatch": "GET|PUT"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"cluster": "hdr-exact-with-method.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"match": {
|
"match": {
|
||||||
"prefix": "/",
|
"prefix": "/",
|
||||||
|
|
|
@ -33,9 +33,7 @@ type ServiceRouteHTTPMatch struct {
|
||||||
|
|
||||||
Header []ServiceRouteHTTPMatchHeader `json:",omitempty"`
|
Header []ServiceRouteHTTPMatchHeader `json:",omitempty"`
|
||||||
QueryParam []ServiceRouteHTTPMatchQueryParam `json:",omitempty"`
|
QueryParam []ServiceRouteHTTPMatchQueryParam `json:",omitempty"`
|
||||||
|
Methods []string `json:",omitempty"`
|
||||||
// TODO(rb): reenable Methods
|
|
||||||
// Methods []string `json:",omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceRouteHTTPMatchHeader struct {
|
type ServiceRouteHTTPMatchHeader struct {
|
||||||
|
|
|
@ -262,6 +262,7 @@ func TestParseConfigEntry(t *testing.T) {
|
||||||
match {
|
match {
|
||||||
http {
|
http {
|
||||||
path_prefix = "/foo"
|
path_prefix = "/foo"
|
||||||
|
methods = [ "GET", "DELETE" ]
|
||||||
query_param = [
|
query_param = [
|
||||||
{
|
{
|
||||||
name = "hack1"
|
name = "hack1"
|
||||||
|
@ -340,6 +341,7 @@ func TestParseConfigEntry(t *testing.T) {
|
||||||
Match {
|
Match {
|
||||||
HTTP {
|
HTTP {
|
||||||
PathPrefix = "/foo"
|
PathPrefix = "/foo"
|
||||||
|
Methods = [ "GET", "DELETE" ]
|
||||||
QueryParam = [
|
QueryParam = [
|
||||||
{
|
{
|
||||||
Name = "hack1"
|
Name = "hack1"
|
||||||
|
@ -418,6 +420,7 @@ func TestParseConfigEntry(t *testing.T) {
|
||||||
Match: &api.ServiceRouteMatch{
|
Match: &api.ServiceRouteMatch{
|
||||||
HTTP: &api.ServiceRouteHTTPMatch{
|
HTTP: &api.ServiceRouteHTTPMatch{
|
||||||
PathPrefix: "/foo",
|
PathPrefix: "/foo",
|
||||||
|
Methods: []string{"GET", "DELETE"},
|
||||||
QueryParam: []api.ServiceRouteHTTPMatchQueryParam{
|
QueryParam: []api.ServiceRouteHTTPMatchQueryParam{
|
||||||
{
|
{
|
||||||
Name: "hack1",
|
Name: "hack1",
|
||||||
|
|
|
@ -193,6 +193,9 @@ routes = [
|
||||||
|
|
||||||
At most only one of `Exact`, `Regex`, or `Present` may be configured.
|
At most only one of `Exact`, `Regex`, or `Present` may be configured.
|
||||||
|
|
||||||
|
- `Methods` `(array<string>)` - A list of HTTP methods for which this match
|
||||||
|
applies. If unspecified all http methods are matched.
|
||||||
|
|
||||||
- `Destination` `(ServiceRouteDestination: <optional>)` - Controls how to
|
- `Destination` `(ServiceRouteDestination: <optional>)` - Controls how to
|
||||||
proxy the actual matching request to a service.
|
proxy the actual matching request to a service.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue