gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/internal/xds/matcher/matcher_header.go (about)

     1  /*
     2   *
     3   * Copyright 2020 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    18  
    19  package matcher
    20  
    21  import (
    22  	"fmt"
    23  	"regexp"
    24  	"strconv"
    25  	"strings"
    26  
    27  	"gitee.com/ks-custle/core-gm/grpc/internal/grpcutil"
    28  	"gitee.com/ks-custle/core-gm/grpc/metadata"
    29  )
    30  
    31  // HeaderMatcher is an interface for header matchers. These are
    32  // documented in (EnvoyProxy link here?). These matchers will match on different
    33  // aspects of HTTP header name/value pairs.
    34  type HeaderMatcher interface {
    35  	Match(metadata.MD) bool
    36  	String() string
    37  }
    38  
    39  // mdValuesFromOutgoingCtx retrieves metadata from context. If there are
    40  // multiple values, the values are concatenated with "," (comma and no space).
    41  //
    42  // All header matchers only match against the comma-concatenated string.
    43  func mdValuesFromOutgoingCtx(md metadata.MD, key string) (string, bool) {
    44  	vs, ok := md[key]
    45  	if !ok {
    46  		return "", false
    47  	}
    48  	return strings.Join(vs, ","), true
    49  }
    50  
    51  // HeaderExactMatcher matches on an exact match of the value of the header.
    52  type HeaderExactMatcher struct {
    53  	key    string
    54  	exact  string
    55  	invert bool
    56  }
    57  
    58  // NewHeaderExactMatcher returns a new HeaderExactMatcher.
    59  func NewHeaderExactMatcher(key, exact string, invert bool) *HeaderExactMatcher {
    60  	return &HeaderExactMatcher{key: key, exact: exact, invert: invert}
    61  }
    62  
    63  // Match returns whether the passed in HTTP Headers match according to the
    64  // HeaderExactMatcher.
    65  func (hem *HeaderExactMatcher) Match(md metadata.MD) bool {
    66  	v, ok := mdValuesFromOutgoingCtx(md, hem.key)
    67  	if !ok {
    68  		return false
    69  	}
    70  	return (v == hem.exact) != hem.invert
    71  }
    72  
    73  func (hem *HeaderExactMatcher) String() string {
    74  	return fmt.Sprintf("headerExact:%v:%v", hem.key, hem.exact)
    75  }
    76  
    77  // HeaderRegexMatcher matches on whether the entire request header value matches
    78  // the regex.
    79  type HeaderRegexMatcher struct {
    80  	key    string
    81  	re     *regexp.Regexp
    82  	invert bool
    83  }
    84  
    85  // NewHeaderRegexMatcher returns a new HeaderRegexMatcher.
    86  func NewHeaderRegexMatcher(key string, re *regexp.Regexp, invert bool) *HeaderRegexMatcher {
    87  	return &HeaderRegexMatcher{key: key, re: re, invert: invert}
    88  }
    89  
    90  // Match returns whether the passed in HTTP Headers match according to the
    91  // HeaderRegexMatcher.
    92  func (hrm *HeaderRegexMatcher) Match(md metadata.MD) bool {
    93  	v, ok := mdValuesFromOutgoingCtx(md, hrm.key)
    94  	if !ok {
    95  		return false
    96  	}
    97  	return grpcutil.FullMatchWithRegex(hrm.re, v) != hrm.invert
    98  }
    99  
   100  func (hrm *HeaderRegexMatcher) String() string {
   101  	return fmt.Sprintf("headerRegex:%v:%v", hrm.key, hrm.re.String())
   102  }
   103  
   104  // HeaderRangeMatcher matches on whether the request header value is within the
   105  // range. The header value must be an integer in base 10 notation.
   106  type HeaderRangeMatcher struct {
   107  	key        string
   108  	start, end int64 // represents [start, end).
   109  	invert     bool
   110  }
   111  
   112  // NewHeaderRangeMatcher returns a new HeaderRangeMatcher.
   113  func NewHeaderRangeMatcher(key string, start, end int64, invert bool) *HeaderRangeMatcher {
   114  	return &HeaderRangeMatcher{key: key, start: start, end: end, invert: invert}
   115  }
   116  
   117  // Match returns whether the passed in HTTP Headers match according to the
   118  // HeaderRangeMatcher.
   119  func (hrm *HeaderRangeMatcher) Match(md metadata.MD) bool {
   120  	v, ok := mdValuesFromOutgoingCtx(md, hrm.key)
   121  	if !ok {
   122  		return false
   123  	}
   124  	if i, err := strconv.ParseInt(v, 10, 64); err == nil && i >= hrm.start && i < hrm.end {
   125  		return !hrm.invert
   126  	}
   127  	return hrm.invert
   128  }
   129  
   130  func (hrm *HeaderRangeMatcher) String() string {
   131  	return fmt.Sprintf("headerRange:%v:[%d,%d)", hrm.key, hrm.start, hrm.end)
   132  }
   133  
   134  // HeaderPresentMatcher will match based on whether the header is present in the
   135  // whole request.
   136  type HeaderPresentMatcher struct {
   137  	key     string
   138  	present bool
   139  }
   140  
   141  // NewHeaderPresentMatcher returns a new HeaderPresentMatcher.
   142  func NewHeaderPresentMatcher(key string, present bool, invert bool) *HeaderPresentMatcher {
   143  	if invert {
   144  		present = !present
   145  	}
   146  	return &HeaderPresentMatcher{key: key, present: present}
   147  }
   148  
   149  // Match returns whether the passed in HTTP Headers match according to the
   150  // HeaderPresentMatcher.
   151  func (hpm *HeaderPresentMatcher) Match(md metadata.MD) bool {
   152  	vs, ok := mdValuesFromOutgoingCtx(md, hpm.key)
   153  	present := ok && len(vs) > 0 // TODO: Are we sure we need this len(vs) > 0?
   154  	return present == hpm.present
   155  }
   156  
   157  func (hpm *HeaderPresentMatcher) String() string {
   158  	return fmt.Sprintf("headerPresent:%v:%v", hpm.key, hpm.present)
   159  }
   160  
   161  // HeaderPrefixMatcher matches on whether the prefix of the header value matches
   162  // the prefix passed into this struct.
   163  type HeaderPrefixMatcher struct {
   164  	key    string
   165  	prefix string
   166  	invert bool
   167  }
   168  
   169  // NewHeaderPrefixMatcher returns a new HeaderPrefixMatcher.
   170  func NewHeaderPrefixMatcher(key string, prefix string, invert bool) *HeaderPrefixMatcher {
   171  	return &HeaderPrefixMatcher{key: key, prefix: prefix, invert: invert}
   172  }
   173  
   174  // Match returns whether the passed in HTTP Headers match according to the
   175  // HeaderPrefixMatcher.
   176  func (hpm *HeaderPrefixMatcher) Match(md metadata.MD) bool {
   177  	v, ok := mdValuesFromOutgoingCtx(md, hpm.key)
   178  	if !ok {
   179  		return false
   180  	}
   181  	return strings.HasPrefix(v, hpm.prefix) != hpm.invert
   182  }
   183  
   184  func (hpm *HeaderPrefixMatcher) String() string {
   185  	return fmt.Sprintf("headerPrefix:%v:%v", hpm.key, hpm.prefix)
   186  }
   187  
   188  // HeaderSuffixMatcher matches on whether the suffix of the header value matches
   189  // the suffix passed into this struct.
   190  type HeaderSuffixMatcher struct {
   191  	key    string
   192  	suffix string
   193  	invert bool
   194  }
   195  
   196  // NewHeaderSuffixMatcher returns a new HeaderSuffixMatcher.
   197  func NewHeaderSuffixMatcher(key string, suffix string, invert bool) *HeaderSuffixMatcher {
   198  	return &HeaderSuffixMatcher{key: key, suffix: suffix, invert: invert}
   199  }
   200  
   201  // Match returns whether the passed in HTTP Headers match according to the
   202  // HeaderSuffixMatcher.
   203  func (hsm *HeaderSuffixMatcher) Match(md metadata.MD) bool {
   204  	v, ok := mdValuesFromOutgoingCtx(md, hsm.key)
   205  	if !ok {
   206  		return false
   207  	}
   208  	return strings.HasSuffix(v, hsm.suffix) != hsm.invert
   209  }
   210  
   211  func (hsm *HeaderSuffixMatcher) String() string {
   212  	return fmt.Sprintf("headerSuffix:%v:%v", hsm.key, hsm.suffix)
   213  }
   214  
   215  // HeaderContainsMatcher matches on whether the header value contains the
   216  // value passed into this struct.
   217  type HeaderContainsMatcher struct {
   218  	key      string
   219  	contains string
   220  	invert   bool
   221  }
   222  
   223  // NewHeaderContainsMatcher returns a new HeaderContainsMatcher. key is the HTTP
   224  // Header key to match on, and contains is the value that the header should
   225  // should contain for a successful match. An empty contains string does not
   226  // work, use HeaderPresentMatcher in that case.
   227  func NewHeaderContainsMatcher(key string, contains string, invert bool) *HeaderContainsMatcher {
   228  	return &HeaderContainsMatcher{key: key, contains: contains, invert: invert}
   229  }
   230  
   231  // Match returns whether the passed in HTTP Headers match according to the
   232  // HeaderContainsMatcher.
   233  func (hcm *HeaderContainsMatcher) Match(md metadata.MD) bool {
   234  	v, ok := mdValuesFromOutgoingCtx(md, hcm.key)
   235  	if !ok {
   236  		return false
   237  	}
   238  	return strings.Contains(v, hcm.contains) != hcm.invert
   239  }
   240  
   241  func (hcm *HeaderContainsMatcher) String() string {
   242  	return fmt.Sprintf("headerContains:%v%v", hcm.key, hcm.contains)
   243  }