xds: moved shared matchers to internal/xds (#4441)
* Moved shared matchers to internal/xds
This commit is contained in:
Родитель
71a1ca6c7f
Коммит
b759b408e8
|
@ -38,7 +38,7 @@ import (
|
|||
xdsinternal "google.golang.org/grpc/internal/credentials/xds"
|
||||
"google.golang.org/grpc/internal/grpctest"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
"google.golang.org/grpc/internal/xds"
|
||||
"google.golang.org/grpc/internal/xds/matcher"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/testdata"
|
||||
)
|
||||
|
@ -223,7 +223,7 @@ func newTestContextWithHandshakeInfo(parent context.Context, root, identity cert
|
|||
// NewSubConn().
|
||||
info := xdsinternal.NewHandshakeInfo(root, identity)
|
||||
if sanExactMatch != "" {
|
||||
info.SetSANMatchers([]xds.StringMatcher{xds.StringMatcherForTesting(newStringP(sanExactMatch), nil, nil, nil, nil, false)})
|
||||
info.SetSANMatchers([]matcher.StringMatcher{matcher.StringMatcherForTesting(newStringP(sanExactMatch), nil, nil, nil, nil, false)})
|
||||
}
|
||||
addr := xdsinternal.SetHandshakeInfo(resolver.Address{}, info)
|
||||
|
||||
|
@ -536,7 +536,7 @@ func (s) TestClientCredsProviderSwitch(t *testing.T) {
|
|||
// use the correct trust roots.
|
||||
root1 := makeRootProvider(t, "x509/client_ca_cert.pem")
|
||||
handshakeInfo := xdsinternal.NewHandshakeInfo(root1, nil)
|
||||
handshakeInfo.SetSANMatchers([]xds.StringMatcher{xds.StringMatcherForTesting(newStringP(defaultTestCertSAN), nil, nil, nil, nil, false)})
|
||||
handshakeInfo.SetSANMatchers([]matcher.StringMatcher{matcher.StringMatcherForTesting(newStringP(defaultTestCertSAN), nil, nil, nil, nil, false)})
|
||||
|
||||
// We need to repeat most of what newTestContextWithHandshakeInfo() does
|
||||
// here because we need access to the underlying HandshakeInfo so that we
|
||||
|
|
|
@ -31,7 +31,7 @@ import (
|
|||
"google.golang.org/grpc/attributes"
|
||||
"google.golang.org/grpc/credentials/tls/certprovider"
|
||||
"google.golang.org/grpc/internal"
|
||||
xdsinternal "google.golang.org/grpc/internal/xds"
|
||||
"google.golang.org/grpc/internal/xds/matcher"
|
||||
"google.golang.org/grpc/resolver"
|
||||
)
|
||||
|
||||
|
@ -66,8 +66,8 @@ type HandshakeInfo struct {
|
|||
mu sync.Mutex
|
||||
rootProvider certprovider.Provider
|
||||
identityProvider certprovider.Provider
|
||||
sanMatchers []xdsinternal.StringMatcher // Only on the client side.
|
||||
requireClientCert bool // Only on server side.
|
||||
sanMatchers []matcher.StringMatcher // Only on the client side.
|
||||
requireClientCert bool // Only on server side.
|
||||
}
|
||||
|
||||
// SetRootCertProvider updates the root certificate provider.
|
||||
|
@ -85,7 +85,7 @@ func (hi *HandshakeInfo) SetIdentityCertProvider(identity certprovider.Provider)
|
|||
}
|
||||
|
||||
// SetSANMatchers updates the list of SAN matchers.
|
||||
func (hi *HandshakeInfo) SetSANMatchers(sanMatchers []xdsinternal.StringMatcher) {
|
||||
func (hi *HandshakeInfo) SetSANMatchers(sanMatchers []matcher.StringMatcher) {
|
||||
hi.mu.Lock()
|
||||
hi.sanMatchers = sanMatchers
|
||||
hi.mu.Unlock()
|
||||
|
@ -113,10 +113,10 @@ func (hi *HandshakeInfo) UseFallbackCreds() bool {
|
|||
|
||||
// GetSANMatchersForTesting returns the SAN matchers stored in HandshakeInfo.
|
||||
// To be used only for testing purposes.
|
||||
func (hi *HandshakeInfo) GetSANMatchersForTesting() []xdsinternal.StringMatcher {
|
||||
func (hi *HandshakeInfo) GetSANMatchersForTesting() []matcher.StringMatcher {
|
||||
hi.mu.Lock()
|
||||
defer hi.mu.Unlock()
|
||||
return append([]xdsinternal.StringMatcher{}, hi.sanMatchers...)
|
||||
return append([]matcher.StringMatcher{}, hi.sanMatchers...)
|
||||
}
|
||||
|
||||
// ClientSideTLSConfig constructs a tls.Config to be used in a client-side
|
||||
|
|
|
@ -25,7 +25,7 @@ import (
|
|||
"regexp"
|
||||
"testing"
|
||||
|
||||
xdsinternal "google.golang.org/grpc/internal/xds"
|
||||
"google.golang.org/grpc/internal/xds/matcher"
|
||||
)
|
||||
|
||||
func TestDNSMatch(t *testing.T) {
|
||||
|
@ -143,45 +143,45 @@ func TestMatchingSANExists_FailureCases(t *testing.T) {
|
|||
|
||||
tests := []struct {
|
||||
desc string
|
||||
sanMatchers []xdsinternal.StringMatcher
|
||||
sanMatchers []matcher.StringMatcher
|
||||
}{
|
||||
{
|
||||
desc: "exact match",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(newStringP("abcd.test.com"), nil, nil, nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(newStringP("http://golang"), nil, nil, nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(newStringP("HTTP://GOLANG.ORG"), nil, nil, nil, nil, false),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(newStringP("abcd.test.com"), nil, nil, nil, nil, false),
|
||||
matcher.StringMatcherForTesting(newStringP("http://golang"), nil, nil, nil, nil, false),
|
||||
matcher.StringMatcherForTesting(newStringP("HTTP://GOLANG.ORG"), nil, nil, nil, nil, false),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "prefix match",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(nil, newStringP("i-aint-the-one"), nil, nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, newStringP("192.168.1.1"), nil, nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, newStringP("FOO.BAR"), nil, nil, nil, false),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(nil, newStringP("i-aint-the-one"), nil, nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, newStringP("192.168.1.1"), nil, nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, newStringP("FOO.BAR"), nil, nil, nil, false),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "suffix match",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, newStringP("i-aint-the-one"), nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, newStringP("1::68"), nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, newStringP(".COM"), nil, nil, false),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(nil, nil, newStringP("i-aint-the-one"), nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, newStringP("1::68"), nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, newStringP(".COM"), nil, nil, false),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "regex match",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`.*\.examples\.com`), false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`192\.[0-9]{1,3}\.1\.1`), false),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`.*\.examples\.com`), false),
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`192\.[0-9]{1,3}\.1\.1`), false),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "contains match",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, newStringP("i-aint-the-one"), nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, newStringP("2001:db8:1:1::68"), nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, newStringP("GRPC"), nil, false),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, newStringP("i-aint-the-one"), nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, newStringP("2001:db8:1:1::68"), nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, newStringP("GRPC"), nil, false),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -216,73 +216,73 @@ func TestMatchingSANExists_Success(t *testing.T) {
|
|||
|
||||
tests := []struct {
|
||||
desc string
|
||||
sanMatchers []xdsinternal.StringMatcher
|
||||
sanMatchers []matcher.StringMatcher
|
||||
}{
|
||||
{
|
||||
desc: "no san matchers",
|
||||
},
|
||||
{
|
||||
desc: "exact match dns wildcard",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(nil, newStringP("192.168.1.1"), nil, nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(newStringP("https://github.com/grpc/grpc-java"), nil, nil, nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(newStringP("abc.example.com"), nil, nil, nil, nil, false),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(nil, newStringP("192.168.1.1"), nil, nil, nil, false),
|
||||
matcher.StringMatcherForTesting(newStringP("https://github.com/grpc/grpc-java"), nil, nil, nil, nil, false),
|
||||
matcher.StringMatcherForTesting(newStringP("abc.example.com"), nil, nil, nil, nil, false),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "exact match ignore case",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(newStringP("FOOBAR@EXAMPLE.COM"), nil, nil, nil, nil, true),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(newStringP("FOOBAR@EXAMPLE.COM"), nil, nil, nil, nil, true),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "prefix match",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, newStringP(".co.in"), nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, newStringP("192.168.1.1"), nil, nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, newStringP("baz.test"), nil, nil, nil, false),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(nil, nil, newStringP(".co.in"), nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, newStringP("192.168.1.1"), nil, nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, newStringP("baz.test"), nil, nil, nil, false),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "prefix match ignore case",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(nil, newStringP("BAZ.test"), nil, nil, nil, true),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(nil, newStringP("BAZ.test"), nil, nil, nil, true),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "suffix match",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`192\.[0-9]{1,3}\.1\.1`), false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, newStringP("192.168.1.1"), nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, newStringP("@test.com"), nil, nil, false),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`192\.[0-9]{1,3}\.1\.1`), false),
|
||||
matcher.StringMatcherForTesting(nil, nil, newStringP("192.168.1.1"), nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, newStringP("@test.com"), nil, nil, false),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "suffix match ignore case",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, newStringP("@test.COM"), nil, nil, true),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(nil, nil, newStringP("@test.COM"), nil, nil, true),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "regex match",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, newStringP("https://github.com/grpc/grpc-java"), nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`192\.[0-9]{1,3}\.1\.1`), false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`.*\.test\.com`), false),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, newStringP("https://github.com/grpc/grpc-java"), nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`192\.[0-9]{1,3}\.1\.1`), false),
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`.*\.test\.com`), false),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "contains match",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(newStringP("https://github.com/grpc/grpc-java"), nil, nil, nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, newStringP("2001:68::db8"), nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, newStringP("192.0.0"), nil, false),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(newStringP("https://github.com/grpc/grpc-java"), nil, nil, nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, newStringP("2001:68::db8"), nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, newStringP("192.0.0"), nil, false),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "contains match ignore case",
|
||||
sanMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, newStringP("GRPC"), nil, true),
|
||||
sanMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, newStringP("GRPC"), nil, true),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
// Package xds contains types that need to be shared between code under
|
||||
// google.golang.org/grpc/xds/... and the rest of gRPC.
|
||||
package xds
|
||||
|
||||
import (
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2020 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package matcher
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
// HeaderMatcherInterface is an interface for header matchers. These are
|
||||
// documented in (EnvoyProxy link here?). These matchers will match on different
|
||||
// aspects of HTTP header name/value pairs.
|
||||
type HeaderMatcherInterface interface {
|
||||
Match(metadata.MD) bool
|
||||
String() string
|
||||
}
|
||||
|
||||
// mdValuesFromOutgoingCtx retrieves metadata from context. If there are
|
||||
// multiple values, the values are concatenated with "," (comma and no space).
|
||||
//
|
||||
// All header matchers only match against the comma-concatenated string.
|
||||
func mdValuesFromOutgoingCtx(md metadata.MD, key string) (string, bool) {
|
||||
vs, ok := md[key]
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return strings.Join(vs, ","), true
|
||||
}
|
||||
|
||||
// HeaderExactMatcher matches on an exact match of the value of the header.
|
||||
type HeaderExactMatcher struct {
|
||||
key string
|
||||
exact string
|
||||
}
|
||||
|
||||
// NewHeaderExactMatcher returns a new HeaderExactMatcher.
|
||||
func NewHeaderExactMatcher(key, exact string) *HeaderExactMatcher {
|
||||
return &HeaderExactMatcher{key: key, exact: exact}
|
||||
}
|
||||
|
||||
// Match returns whether the passed in HTTP Headers match according to the
|
||||
// HeaderExactMatcher.
|
||||
func (hem *HeaderExactMatcher) Match(md metadata.MD) bool {
|
||||
v, ok := mdValuesFromOutgoingCtx(md, hem.key)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return v == hem.exact
|
||||
}
|
||||
|
||||
func (hem *HeaderExactMatcher) String() string {
|
||||
return fmt.Sprintf("headerExact:%v:%v", hem.key, hem.exact)
|
||||
}
|
||||
|
||||
// HeaderRegexMatcher matches on whether the entire request header value matches
|
||||
// the regex.
|
||||
type HeaderRegexMatcher struct {
|
||||
key string
|
||||
re *regexp.Regexp
|
||||
}
|
||||
|
||||
// NewHeaderRegexMatcher returns a new HeaderRegexMatcher.
|
||||
func NewHeaderRegexMatcher(key string, re *regexp.Regexp) *HeaderRegexMatcher {
|
||||
return &HeaderRegexMatcher{key: key, re: re}
|
||||
}
|
||||
|
||||
// Match returns whether the passed in HTTP Headers match according to the
|
||||
// HeaderRegexMatcher.
|
||||
func (hrm *HeaderRegexMatcher) Match(md metadata.MD) bool {
|
||||
v, ok := mdValuesFromOutgoingCtx(md, hrm.key)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return hrm.re.MatchString(v)
|
||||
}
|
||||
|
||||
func (hrm *HeaderRegexMatcher) String() string {
|
||||
return fmt.Sprintf("headerRegex:%v:%v", hrm.key, hrm.re.String())
|
||||
}
|
||||
|
||||
// HeaderRangeMatcher matches on whether the request header value is within the
|
||||
// range. The header value must be an integer in base 10 notation.
|
||||
type HeaderRangeMatcher struct {
|
||||
key string
|
||||
start, end int64 // represents [start, end).
|
||||
}
|
||||
|
||||
// NewHeaderRangeMatcher returns a new HeaderRangeMatcher.
|
||||
func NewHeaderRangeMatcher(key string, start, end int64) *HeaderRangeMatcher {
|
||||
return &HeaderRangeMatcher{key: key, start: start, end: end}
|
||||
}
|
||||
|
||||
// Match returns whether the passed in HTTP Headers match according to the
|
||||
// HeaderRangeMatcher.
|
||||
func (hrm *HeaderRangeMatcher) Match(md metadata.MD) bool {
|
||||
v, ok := mdValuesFromOutgoingCtx(md, hrm.key)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if i, err := strconv.ParseInt(v, 10, 64); err == nil && i >= hrm.start && i < hrm.end {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (hrm *HeaderRangeMatcher) String() string {
|
||||
return fmt.Sprintf("headerRange:%v:[%d,%d)", hrm.key, hrm.start, hrm.end)
|
||||
}
|
||||
|
||||
// HeaderPresentMatcher will match based on whether the header is present in the
|
||||
// whole request.
|
||||
type HeaderPresentMatcher struct {
|
||||
key string
|
||||
present bool
|
||||
}
|
||||
|
||||
// NewHeaderPresentMatcher returns a new HeaderPresentMatcher.
|
||||
func NewHeaderPresentMatcher(key string, present bool) *HeaderPresentMatcher {
|
||||
return &HeaderPresentMatcher{key: key, present: present}
|
||||
}
|
||||
|
||||
// Match returns whether the passed in HTTP Headers match according to the
|
||||
// HeaderPresentMatcher.
|
||||
func (hpm *HeaderPresentMatcher) Match(md metadata.MD) bool {
|
||||
vs, ok := mdValuesFromOutgoingCtx(md, hpm.key)
|
||||
present := ok && len(vs) > 0
|
||||
return present == hpm.present
|
||||
}
|
||||
|
||||
func (hpm *HeaderPresentMatcher) String() string {
|
||||
return fmt.Sprintf("headerPresent:%v:%v", hpm.key, hpm.present)
|
||||
}
|
||||
|
||||
// HeaderPrefixMatcher matches on whether the prefix of the header value matches
|
||||
// the prefix passed into this struct.
|
||||
type HeaderPrefixMatcher struct {
|
||||
key string
|
||||
prefix string
|
||||
}
|
||||
|
||||
// NewHeaderPrefixMatcher returns a new HeaderPrefixMatcher.
|
||||
func NewHeaderPrefixMatcher(key string, prefix string) *HeaderPrefixMatcher {
|
||||
return &HeaderPrefixMatcher{key: key, prefix: prefix}
|
||||
}
|
||||
|
||||
// Match returns whether the passed in HTTP Headers match according to the
|
||||
// HeaderPrefixMatcher.
|
||||
func (hpm *HeaderPrefixMatcher) Match(md metadata.MD) bool {
|
||||
v, ok := mdValuesFromOutgoingCtx(md, hpm.key)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return strings.HasPrefix(v, hpm.prefix)
|
||||
}
|
||||
|
||||
func (hpm *HeaderPrefixMatcher) String() string {
|
||||
return fmt.Sprintf("headerPrefix:%v:%v", hpm.key, hpm.prefix)
|
||||
}
|
||||
|
||||
// HeaderSuffixMatcher matches on whether the suffix of the header value matches
|
||||
// the suffix passed into this struct.
|
||||
type HeaderSuffixMatcher struct {
|
||||
key string
|
||||
suffix string
|
||||
}
|
||||
|
||||
// NewHeaderSuffixMatcher returns a new HeaderSuffixMatcher.
|
||||
func NewHeaderSuffixMatcher(key string, suffix string) *HeaderSuffixMatcher {
|
||||
return &HeaderSuffixMatcher{key: key, suffix: suffix}
|
||||
}
|
||||
|
||||
// Match returns whether the passed in HTTP Headers match according to the
|
||||
// HeaderSuffixMatcher.
|
||||
func (hsm *HeaderSuffixMatcher) Match(md metadata.MD) bool {
|
||||
v, ok := mdValuesFromOutgoingCtx(md, hsm.key)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return strings.HasSuffix(v, hsm.suffix)
|
||||
}
|
||||
|
||||
func (hsm *HeaderSuffixMatcher) String() string {
|
||||
return fmt.Sprintf("headerSuffix:%v:%v", hsm.key, hsm.suffix)
|
||||
}
|
||||
|
||||
// InvertMatcher inverts the match result of the underlying header matcher.
|
||||
type InvertMatcher struct {
|
||||
m HeaderMatcherInterface
|
||||
}
|
||||
|
||||
// NewInvertMatcher returns a new InvertMatcher.
|
||||
func NewInvertMatcher(m HeaderMatcherInterface) *InvertMatcher {
|
||||
return &InvertMatcher{m: m}
|
||||
}
|
||||
|
||||
// Match returns whether the passed in HTTP Headers match according to the
|
||||
// InvertMatcher.
|
||||
func (i *InvertMatcher) Match(md metadata.MD) bool {
|
||||
return !i.m.Match(md)
|
||||
}
|
||||
|
||||
func (i *InvertMatcher) String() string {
|
||||
return fmt.Sprintf("invert{%s}", i.m)
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
package resolver
|
||||
package matcher
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
@ -66,8 +66,8 @@ func TestHeaderExactMatcherMatch(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
hem := newHeaderExactMatcher(tt.key, tt.exact)
|
||||
if got := hem.match(tt.md); got != tt.want {
|
||||
hem := NewHeaderExactMatcher(tt.key, tt.exact)
|
||||
if got := hem.Match(tt.md); got != tt.want {
|
||||
t.Errorf("match() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
@ -112,8 +112,8 @@ func TestHeaderRegexMatcherMatch(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
hrm := newHeaderRegexMatcher(tt.key, regexp.MustCompile(tt.regexStr))
|
||||
if got := hrm.match(tt.md); got != tt.want {
|
||||
hrm := NewHeaderRegexMatcher(tt.key, regexp.MustCompile(tt.regexStr))
|
||||
if got := hrm.Match(tt.md); got != tt.want {
|
||||
t.Errorf("match() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
@ -159,8 +159,8 @@ func TestHeaderRangeMatcherMatch(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
hrm := newHeaderRangeMatcher(tt.key, tt.start, tt.end)
|
||||
if got := hrm.match(tt.md); got != tt.want {
|
||||
hrm := NewHeaderRangeMatcher(tt.key, tt.start, tt.end)
|
||||
if got := hrm.Match(tt.md); got != tt.want {
|
||||
t.Errorf("match() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
@ -206,8 +206,8 @@ func TestHeaderPresentMatcherMatch(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
hpm := newHeaderPresentMatcher(tt.key, tt.present)
|
||||
if got := hpm.match(tt.md); got != tt.want {
|
||||
hpm := NewHeaderPresentMatcher(tt.key, tt.present)
|
||||
if got := hpm.Match(tt.md); got != tt.want {
|
||||
t.Errorf("match() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
@ -252,8 +252,8 @@ func TestHeaderPrefixMatcherMatch(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
hpm := newHeaderPrefixMatcher(tt.key, tt.prefix)
|
||||
if got := hpm.match(tt.md); got != tt.want {
|
||||
hpm := NewHeaderPrefixMatcher(tt.key, tt.prefix)
|
||||
if got := hpm.Match(tt.md); got != tt.want {
|
||||
t.Errorf("match() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
@ -298,8 +298,8 @@ func TestHeaderSuffixMatcherMatch(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
hsm := newHeaderSuffixMatcher(tt.key, tt.suffix)
|
||||
if got := hsm.match(tt.md); got != tt.want {
|
||||
hsm := NewHeaderSuffixMatcher(tt.key, tt.suffix)
|
||||
if got := hsm.Match(tt.md); got != tt.want {
|
||||
t.Errorf("match() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
|
@ -309,24 +309,24 @@ func TestHeaderSuffixMatcherMatch(t *testing.T) {
|
|||
func TestInvertMatcherMatch(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
m headerMatcherInterface
|
||||
m HeaderMatcherInterface
|
||||
md metadata.MD
|
||||
}{
|
||||
{
|
||||
name: "true->false",
|
||||
m: newHeaderExactMatcher("th", "tv"),
|
||||
m: NewHeaderExactMatcher("th", "tv"),
|
||||
md: metadata.Pairs("th", "tv"),
|
||||
},
|
||||
{
|
||||
name: "false->true",
|
||||
m: newHeaderExactMatcher("th", "abc"),
|
||||
m: NewHeaderExactMatcher("th", "abc"),
|
||||
md: metadata.Pairs("th", "tv"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := newInvertMatcher(tt.m).match(tt.md)
|
||||
want := !tt.m.match(tt.md)
|
||||
got := NewInvertMatcher(tt.m).Match(tt.md)
|
||||
want := !tt.m.Match(tt.md)
|
||||
if got != want {
|
||||
t.Errorf("match() = %v, want %v", got, want)
|
||||
}
|
|
@ -16,9 +16,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
// Package xds contains types that need to be shared between code under
|
||||
// Package matcher contains types that need to be shared between code under
|
||||
// google.golang.org/grpc/xds/... and the rest of gRPC.
|
||||
package xds
|
||||
package matcher
|
||||
|
||||
import (
|
||||
"errors"
|
|
@ -16,7 +16,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
package xds
|
||||
package matcher
|
||||
|
||||
import (
|
||||
"regexp"
|
|
@ -34,7 +34,7 @@ import (
|
|||
"google.golang.org/grpc/internal"
|
||||
xdscredsinternal "google.golang.org/grpc/internal/credentials/xds"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
xdsinternal "google.golang.org/grpc/internal/xds"
|
||||
"google.golang.org/grpc/internal/xds/matcher"
|
||||
"google.golang.org/grpc/resolver"
|
||||
xdsclient "google.golang.org/grpc/xds/internal/client"
|
||||
"google.golang.org/grpc/xds/internal/client/bootstrap"
|
||||
|
@ -50,12 +50,12 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
testSANMatchers = []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(newStringP(testSAN), nil, nil, nil, nil, true),
|
||||
xdsinternal.StringMatcherForTesting(nil, newStringP(testSAN), nil, nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, newStringP(testSAN), nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(testSAN), false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, newStringP(testSAN), nil, false),
|
||||
testSANMatchers = []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(newStringP(testSAN), nil, nil, nil, nil, true),
|
||||
matcher.StringMatcherForTesting(nil, newStringP(testSAN), nil, nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, newStringP(testSAN), nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(testSAN), false),
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, newStringP(testSAN), nil, false),
|
||||
}
|
||||
fpb1, fpb2 *fakeProviderBuilder
|
||||
bootstrapConfig *bootstrap.Config
|
||||
|
|
|
@ -35,8 +35,8 @@ import (
|
|||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"google.golang.org/grpc/internal/testutils"
|
||||
xdsinternal "google.golang.org/grpc/internal/xds"
|
||||
"google.golang.org/grpc/internal/xds/env"
|
||||
"google.golang.org/grpc/internal/xds/matcher"
|
||||
"google.golang.org/grpc/xds/internal/version"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
@ -764,12 +764,12 @@ func (s) TestValidateClusterWithSecurityConfig(t *testing.T) {
|
|||
RootCertName: rootCertName,
|
||||
IdentityInstanceName: identityPluginInstance,
|
||||
IdentityCertName: identityCertName,
|
||||
SubjectAltNameMatchers: []xdsinternal.StringMatcher{
|
||||
xdsinternal.StringMatcherForTesting(newStringP(sanExact), nil, nil, nil, nil, true),
|
||||
xdsinternal.StringMatcherForTesting(nil, newStringP(sanPrefix), nil, nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, newStringP(sanSuffix), nil, nil, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, nil, sanRE, false),
|
||||
xdsinternal.StringMatcherForTesting(nil, nil, nil, newStringP(sanContains), nil, false),
|
||||
SubjectAltNameMatchers: []matcher.StringMatcher{
|
||||
matcher.StringMatcherForTesting(newStringP(sanExact), nil, nil, nil, nil, true),
|
||||
matcher.StringMatcherForTesting(nil, newStringP(sanPrefix), nil, nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, newStringP(sanSuffix), nil, nil, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, nil, sanRE, false),
|
||||
matcher.StringMatcherForTesting(nil, nil, nil, newStringP(sanContains), nil, false),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -33,7 +33,7 @@ import (
|
|||
"github.com/golang/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
|
||||
"google.golang.org/grpc/internal/xds"
|
||||
"google.golang.org/grpc/internal/xds/matcher"
|
||||
"google.golang.org/grpc/xds/internal/client/load"
|
||||
"google.golang.org/grpc/xds/internal/httpfilter"
|
||||
|
||||
|
@ -351,7 +351,7 @@ type SecurityConfig struct {
|
|||
// - If the peer certificate contains a wildcard DNS SAN, and an `exact`
|
||||
// matcher is configured, a wildcard DNS match is performed instead of a
|
||||
// regular string comparison.
|
||||
SubjectAltNameMatchers []xds.StringMatcher
|
||||
SubjectAltNameMatchers []matcher.StringMatcher
|
||||
// RequireClientCert indicates if the server handshake process expects the
|
||||
// client to present a certificate. Set to true when performing mTLS. Used
|
||||
// only on the server-side.
|
||||
|
|
|
@ -40,10 +40,10 @@ import (
|
|||
"github.com/golang/protobuf/proto"
|
||||
"github.com/golang/protobuf/ptypes"
|
||||
"google.golang.org/grpc/internal/pretty"
|
||||
"google.golang.org/grpc/internal/xds/matcher"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
|
||||
"google.golang.org/grpc/internal/grpclog"
|
||||
"google.golang.org/grpc/internal/xds"
|
||||
"google.golang.org/grpc/internal/xds/env"
|
||||
"google.golang.org/grpc/xds/internal"
|
||||
"google.golang.org/grpc/xds/internal/httpfilter"
|
||||
|
@ -689,10 +689,10 @@ func securityConfigFromCommonTLSContext(common *v3tlspb.CommonTlsContext) (*Secu
|
|||
switch t := common.GetValidationContextType().(type) {
|
||||
case *v3tlspb.CommonTlsContext_CombinedValidationContext:
|
||||
combined := common.GetCombinedValidationContext()
|
||||
var matchers []xds.StringMatcher
|
||||
var matchers []matcher.StringMatcher
|
||||
if def := combined.GetDefaultValidationContext(); def != nil {
|
||||
for _, m := range def.GetMatchSubjectAltNames() {
|
||||
matcher, err := xds.StringMatcherFromProto(m)
|
||||
matcher, err := matcher.StringMatcherFromProto(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"google.golang.org/grpc/internal/grpcrand"
|
||||
"google.golang.org/grpc/internal/grpcutil"
|
||||
iresolver "google.golang.org/grpc/internal/resolver"
|
||||
"google.golang.org/grpc/internal/xds/matcher"
|
||||
"google.golang.org/grpc/metadata"
|
||||
xdsclient "google.golang.org/grpc/xds/internal/client"
|
||||
)
|
||||
|
@ -42,27 +43,27 @@ func routeToMatcher(r *xdsclient.Route) (*compositeMatcher, error) {
|
|||
return nil, fmt.Errorf("illegal route: missing path_matcher")
|
||||
}
|
||||
|
||||
var headerMatchers []headerMatcherInterface
|
||||
var headerMatchers []matcher.HeaderMatcherInterface
|
||||
for _, h := range r.Headers {
|
||||
var matcherT headerMatcherInterface
|
||||
var matcherT matcher.HeaderMatcherInterface
|
||||
switch {
|
||||
case h.ExactMatch != nil && *h.ExactMatch != "":
|
||||
matcherT = newHeaderExactMatcher(h.Name, *h.ExactMatch)
|
||||
matcherT = matcher.NewHeaderExactMatcher(h.Name, *h.ExactMatch)
|
||||
case h.RegexMatch != nil:
|
||||
matcherT = newHeaderRegexMatcher(h.Name, h.RegexMatch)
|
||||
matcherT = matcher.NewHeaderRegexMatcher(h.Name, h.RegexMatch)
|
||||
case h.PrefixMatch != nil && *h.PrefixMatch != "":
|
||||
matcherT = newHeaderPrefixMatcher(h.Name, *h.PrefixMatch)
|
||||
matcherT = matcher.NewHeaderPrefixMatcher(h.Name, *h.PrefixMatch)
|
||||
case h.SuffixMatch != nil && *h.SuffixMatch != "":
|
||||
matcherT = newHeaderSuffixMatcher(h.Name, *h.SuffixMatch)
|
||||
matcherT = matcher.NewHeaderSuffixMatcher(h.Name, *h.SuffixMatch)
|
||||
case h.RangeMatch != nil:
|
||||
matcherT = newHeaderRangeMatcher(h.Name, h.RangeMatch.Start, h.RangeMatch.End)
|
||||
matcherT = matcher.NewHeaderRangeMatcher(h.Name, h.RangeMatch.Start, h.RangeMatch.End)
|
||||
case h.PresentMatch != nil:
|
||||
matcherT = newHeaderPresentMatcher(h.Name, *h.PresentMatch)
|
||||
matcherT = matcher.NewHeaderPresentMatcher(h.Name, *h.PresentMatch)
|
||||
default:
|
||||
return nil, fmt.Errorf("illegal route: missing header_match_specifier")
|
||||
}
|
||||
if h.InvertMatch != nil && *h.InvertMatch {
|
||||
matcherT = newInvertMatcher(matcherT)
|
||||
matcherT = matcher.NewInvertMatcher(matcherT)
|
||||
}
|
||||
headerMatchers = append(headerMatchers, matcherT)
|
||||
}
|
||||
|
@ -77,11 +78,11 @@ func routeToMatcher(r *xdsclient.Route) (*compositeMatcher, error) {
|
|||
// compositeMatcher.match returns true if all matchers return true.
|
||||
type compositeMatcher struct {
|
||||
pm pathMatcherInterface
|
||||
hms []headerMatcherInterface
|
||||
hms []matcher.HeaderMatcherInterface
|
||||
fm *fractionMatcher
|
||||
}
|
||||
|
||||
func newCompositeMatcher(pm pathMatcherInterface, hms []headerMatcherInterface, fm *fractionMatcher) *compositeMatcher {
|
||||
func newCompositeMatcher(pm pathMatcherInterface, hms []matcher.HeaderMatcherInterface, fm *fractionMatcher) *compositeMatcher {
|
||||
return &compositeMatcher{pm: pm, hms: hms, fm: fm}
|
||||
}
|
||||
|
||||
|
@ -107,7 +108,7 @@ func (a *compositeMatcher) match(info iresolver.RPCInfo) bool {
|
|||
}
|
||||
}
|
||||
for _, m := range a.hms {
|
||||
if !m.match(md) {
|
||||
if !m.Match(md) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright 2020 gRPC authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package resolver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
type headerMatcherInterface interface {
|
||||
match(metadata.MD) bool
|
||||
String() string
|
||||
}
|
||||
|
||||
// mdValuesFromOutgoingCtx retrieves metadata from context. If there are
|
||||
// multiple values, the values are concatenated with "," (comma and no space).
|
||||
//
|
||||
// All header matchers only match against the comma-concatenated string.
|
||||
func mdValuesFromOutgoingCtx(md metadata.MD, key string) (string, bool) {
|
||||
vs, ok := md[key]
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return strings.Join(vs, ","), true
|
||||
}
|
||||
|
||||
type headerExactMatcher struct {
|
||||
key string
|
||||
exact string
|
||||
}
|
||||
|
||||
func newHeaderExactMatcher(key, exact string) *headerExactMatcher {
|
||||
return &headerExactMatcher{key: key, exact: exact}
|
||||
}
|
||||
|
||||
func (hem *headerExactMatcher) match(md metadata.MD) bool {
|
||||
v, ok := mdValuesFromOutgoingCtx(md, hem.key)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return v == hem.exact
|
||||
}
|
||||
|
||||
func (hem *headerExactMatcher) String() string {
|
||||
return fmt.Sprintf("headerExact:%v:%v", hem.key, hem.exact)
|
||||
}
|
||||
|
||||
type headerRegexMatcher struct {
|
||||
key string
|
||||
re *regexp.Regexp
|
||||
}
|
||||
|
||||
func newHeaderRegexMatcher(key string, re *regexp.Regexp) *headerRegexMatcher {
|
||||
return &headerRegexMatcher{key: key, re: re}
|
||||
}
|
||||
|
||||
func (hrm *headerRegexMatcher) match(md metadata.MD) bool {
|
||||
v, ok := mdValuesFromOutgoingCtx(md, hrm.key)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return hrm.re.MatchString(v)
|
||||
}
|
||||
|
||||
func (hrm *headerRegexMatcher) String() string {
|
||||
return fmt.Sprintf("headerRegex:%v:%v", hrm.key, hrm.re.String())
|
||||
}
|
||||
|
||||
type headerRangeMatcher struct {
|
||||
key string
|
||||
start, end int64 // represents [start, end).
|
||||
}
|
||||
|
||||
func newHeaderRangeMatcher(key string, start, end int64) *headerRangeMatcher {
|
||||
return &headerRangeMatcher{key: key, start: start, end: end}
|
||||
}
|
||||
|
||||
func (hrm *headerRangeMatcher) match(md metadata.MD) bool {
|
||||
v, ok := mdValuesFromOutgoingCtx(md, hrm.key)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if i, err := strconv.ParseInt(v, 10, 64); err == nil && i >= hrm.start && i < hrm.end {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (hrm *headerRangeMatcher) String() string {
|
||||
return fmt.Sprintf("headerRange:%v:[%d,%d)", hrm.key, hrm.start, hrm.end)
|
||||
}
|
||||
|
||||
type headerPresentMatcher struct {
|
||||
key string
|
||||
present bool
|
||||
}
|
||||
|
||||
func newHeaderPresentMatcher(key string, present bool) *headerPresentMatcher {
|
||||
return &headerPresentMatcher{key: key, present: present}
|
||||
}
|
||||
|
||||
func (hpm *headerPresentMatcher) match(md metadata.MD) bool {
|
||||
vs, ok := mdValuesFromOutgoingCtx(md, hpm.key)
|
||||
present := ok && len(vs) > 0
|
||||
return present == hpm.present
|
||||
}
|
||||
|
||||
func (hpm *headerPresentMatcher) String() string {
|
||||
return fmt.Sprintf("headerPresent:%v:%v", hpm.key, hpm.present)
|
||||
}
|
||||
|
||||
type headerPrefixMatcher struct {
|
||||
key string
|
||||
prefix string
|
||||
}
|
||||
|
||||
func newHeaderPrefixMatcher(key string, prefix string) *headerPrefixMatcher {
|
||||
return &headerPrefixMatcher{key: key, prefix: prefix}
|
||||
}
|
||||
|
||||
func (hpm *headerPrefixMatcher) match(md metadata.MD) bool {
|
||||
v, ok := mdValuesFromOutgoingCtx(md, hpm.key)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return strings.HasPrefix(v, hpm.prefix)
|
||||
}
|
||||
|
||||
func (hpm *headerPrefixMatcher) String() string {
|
||||
return fmt.Sprintf("headerPrefix:%v:%v", hpm.key, hpm.prefix)
|
||||
}
|
||||
|
||||
type headerSuffixMatcher struct {
|
||||
key string
|
||||
suffix string
|
||||
}
|
||||
|
||||
func newHeaderSuffixMatcher(key string, suffix string) *headerSuffixMatcher {
|
||||
return &headerSuffixMatcher{key: key, suffix: suffix}
|
||||
}
|
||||
|
||||
func (hsm *headerSuffixMatcher) match(md metadata.MD) bool {
|
||||
v, ok := mdValuesFromOutgoingCtx(md, hsm.key)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return strings.HasSuffix(v, hsm.suffix)
|
||||
}
|
||||
|
||||
func (hsm *headerSuffixMatcher) String() string {
|
||||
return fmt.Sprintf("headerSuffix:%v:%v", hsm.key, hsm.suffix)
|
||||
}
|
||||
|
||||
type invertMatcher struct {
|
||||
m headerMatcherInterface
|
||||
}
|
||||
|
||||
func newInvertMatcher(m headerMatcherInterface) *invertMatcher {
|
||||
return &invertMatcher{m: m}
|
||||
}
|
||||
|
||||
func (i *invertMatcher) match(md metadata.MD) bool {
|
||||
return !i.m.match(md)
|
||||
}
|
||||
|
||||
func (i *invertMatcher) String() string {
|
||||
return fmt.Sprintf("invert{%s}", i.m)
|
||||
}
|
|
@ -27,6 +27,7 @@ import (
|
|||
"google.golang.org/grpc/internal/grpcrand"
|
||||
"google.golang.org/grpc/internal/grpcutil"
|
||||
iresolver "google.golang.org/grpc/internal/resolver"
|
||||
"google.golang.org/grpc/internal/xds/matcher"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
|
@ -34,14 +35,14 @@ func TestAndMatcherMatch(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
pm pathMatcherInterface
|
||||
hm headerMatcherInterface
|
||||
hm matcher.HeaderMatcherInterface
|
||||
info iresolver.RPCInfo
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "both match",
|
||||
pm: newPathExactMatcher("/a/b", false),
|
||||
hm: newHeaderExactMatcher("th", "tv"),
|
||||
hm: matcher.NewHeaderExactMatcher("th", "tv"),
|
||||
info: iresolver.RPCInfo{
|
||||
Method: "/a/b",
|
||||
Context: metadata.NewOutgoingContext(context.Background(), metadata.Pairs("th", "tv")),
|
||||
|
@ -51,7 +52,7 @@ func TestAndMatcherMatch(t *testing.T) {
|
|||
{
|
||||
name: "both match with path case insensitive",
|
||||
pm: newPathExactMatcher("/A/B", true),
|
||||
hm: newHeaderExactMatcher("th", "tv"),
|
||||
hm: matcher.NewHeaderExactMatcher("th", "tv"),
|
||||
info: iresolver.RPCInfo{
|
||||
Method: "/a/b",
|
||||
Context: metadata.NewOutgoingContext(context.Background(), metadata.Pairs("th", "tv")),
|
||||
|
@ -61,7 +62,7 @@ func TestAndMatcherMatch(t *testing.T) {
|
|||
{
|
||||
name: "only one match",
|
||||
pm: newPathExactMatcher("/a/b", false),
|
||||
hm: newHeaderExactMatcher("th", "tv"),
|
||||
hm: matcher.NewHeaderExactMatcher("th", "tv"),
|
||||
info: iresolver.RPCInfo{
|
||||
Method: "/z/y",
|
||||
Context: metadata.NewOutgoingContext(context.Background(), metadata.Pairs("th", "tv")),
|
||||
|
@ -71,7 +72,7 @@ func TestAndMatcherMatch(t *testing.T) {
|
|||
{
|
||||
name: "both not match",
|
||||
pm: newPathExactMatcher("/z/y", false),
|
||||
hm: newHeaderExactMatcher("th", "abc"),
|
||||
hm: matcher.NewHeaderExactMatcher("th", "abc"),
|
||||
info: iresolver.RPCInfo{
|
||||
Method: "/a/b",
|
||||
Context: metadata.NewOutgoingContext(context.Background(), metadata.Pairs("th", "tv")),
|
||||
|
@ -81,7 +82,7 @@ func TestAndMatcherMatch(t *testing.T) {
|
|||
{
|
||||
name: "fake header",
|
||||
pm: newPathPrefixMatcher("/", false),
|
||||
hm: newHeaderExactMatcher("content-type", "fake"),
|
||||
hm: matcher.NewHeaderExactMatcher("content-type", "fake"),
|
||||
info: iresolver.RPCInfo{
|
||||
Method: "/a/b",
|
||||
Context: grpcutil.WithExtraMetadata(context.Background(), metadata.Pairs(
|
||||
|
@ -93,7 +94,7 @@ func TestAndMatcherMatch(t *testing.T) {
|
|||
{
|
||||
name: "binary header",
|
||||
pm: newPathPrefixMatcher("/", false),
|
||||
hm: newHeaderPresentMatcher("t-bin", true),
|
||||
hm: matcher.NewHeaderPresentMatcher("t-bin", true),
|
||||
info: iresolver.RPCInfo{
|
||||
Method: "/a/b",
|
||||
Context: grpcutil.WithExtraMetadata(
|
||||
|
@ -107,7 +108,7 @@ func TestAndMatcherMatch(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := newCompositeMatcher(tt.pm, []headerMatcherInterface{tt.hm}, nil)
|
||||
a := newCompositeMatcher(tt.pm, []matcher.HeaderMatcherInterface{tt.hm}, nil)
|
||||
if got := a.match(tt.info); got != tt.want {
|
||||
t.Errorf("match() = %v, want %v", got, tt.want)
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче