xds: moved shared matchers to internal/xds (#4441)

* Moved shared matchers to internal/xds
This commit is contained in:
Zach Reyes 2021-05-14 17:02:10 -04:00 коммит произвёл GitHub
Родитель 71a1ca6c7f
Коммит b759b408e8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
15 изменённых файлов: 347 добавлений и 307 удалений

Просмотреть файл

@ -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)
}