• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #20337

26 Jun 2026 11:37AM UTC coverage: 89.06% (+0.2%) from 88.876%
#20337

push

github

web-flow
Ext_proc filter and client interceptor (#12792)

Implements ext_proc filter from [grfc A93](https://github.com/grpc/proposal/pull/484)  (internal [design doc](http://go/ext-proc-design-java)).

37585 of 42202 relevant lines covered (89.06%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.29
/../xds/src/main/java/io/grpc/xds/internal/MatcherParser.java
1
/*
2
 * Copyright 2021 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.xds.internal;
18

19
import com.google.common.collect.ImmutableList;
20
import com.google.re2j.Pattern;
21
import com.google.re2j.PatternSyntaxException;
22

23
// TODO(zivy@): may reuse common matchers parsers.
24
public final class MatcherParser {
×
25
  /** Translate ListStringMatcher envoy proto to a list of internal StringMatcher. */
26
  public static ImmutableList<Matchers.StringMatcher> parseListStringMatcher(
27
          io.envoyproxy.envoy.type.matcher.v3.ListStringMatcher proto) {
28
    ImmutableList.Builder<Matchers.StringMatcher> matchers = ImmutableList.builder();
1✔
29
    for (io.envoyproxy.envoy.type.matcher.v3.StringMatcher matcherProto : proto.getPatternsList()) {
1✔
30
      matchers.add(parseStringMatcher(matcherProto));
1✔
31
    }
1✔
32
    return matchers.build();
1✔
33
  }
34

35
  /** Translates envoy proto HeaderMatcher to internal HeaderMatcher.*/
36
  public static Matchers.HeaderMatcher parseHeaderMatcher(
37
          io.envoyproxy.envoy.config.route.v3.HeaderMatcher proto) {
38
    switch (proto.getHeaderMatchSpecifierCase()) {
1✔
39
      case EXACT_MATCH:
40
        @SuppressWarnings("deprecation") // gRFC A63: support indefinitely
41
        String exactMatch = proto.getExactMatch();
1✔
42
        return Matchers.HeaderMatcher.forExactValue(
1✔
43
                        proto.getName(), exactMatch, proto.getInvertMatch());
1✔
44
      case SAFE_REGEX_MATCH:
45
        @SuppressWarnings("deprecation") // gRFC A63: support indefinitely
46
        String rawPattern = proto.getSafeRegexMatch().getRegex();
1✔
47
        Pattern safeRegExMatch;
48
        try {
49
          safeRegExMatch = Pattern.compile(rawPattern);
1✔
50
        } catch (PatternSyntaxException e) {
1✔
51
          throw new IllegalArgumentException(
1✔
52
                "HeaderMatcher [" + proto.getName() + "] contains malformed safe regex pattern: "
1✔
53
                        + e.getMessage());
1✔
54
        }
1✔
55
        return Matchers.HeaderMatcher.forSafeRegEx(
1✔
56
              proto.getName(), safeRegExMatch, proto.getInvertMatch());
1✔
57
      case RANGE_MATCH:
58
        Matchers.HeaderMatcher.Range rangeMatch = Matchers.HeaderMatcher.Range.create(
1✔
59
              proto.getRangeMatch().getStart(), proto.getRangeMatch().getEnd());
1✔
60
        return Matchers.HeaderMatcher.forRange(
1✔
61
              proto.getName(), rangeMatch, proto.getInvertMatch());
1✔
62
      case PRESENT_MATCH:
63
        return Matchers.HeaderMatcher.forPresent(
1✔
64
              proto.getName(), proto.getPresentMatch(), proto.getInvertMatch());
1✔
65
      case PREFIX_MATCH:
66
        @SuppressWarnings("deprecation") // gRFC A63: support indefinitely
67
        String prefixMatch = proto.getPrefixMatch();
1✔
68
        return Matchers.HeaderMatcher.forPrefix(
1✔
69
              proto.getName(), prefixMatch, proto.getInvertMatch());
1✔
70
      case SUFFIX_MATCH:
71
        @SuppressWarnings("deprecation") // gRFC A63: support indefinitely
72
        String suffixMatch = proto.getSuffixMatch();
1✔
73
        return Matchers.HeaderMatcher.forSuffix(
1✔
74
              proto.getName(), suffixMatch, proto.getInvertMatch());
1✔
75
      case CONTAINS_MATCH:
76
        @SuppressWarnings("deprecation") // gRFC A63: support indefinitely
77
        String containsMatch = proto.getContainsMatch();
×
78
        return Matchers.HeaderMatcher.forContains(
×
79
              proto.getName(), containsMatch, proto.getInvertMatch());
×
80
      case STRING_MATCH:
81
        return Matchers.HeaderMatcher.forString(
1✔
82
          proto.getName(), parseStringMatcher(proto.getStringMatch()), proto.getInvertMatch());
1✔
83
      case HEADERMATCHSPECIFIER_NOT_SET:
84
      default:
85
        throw new IllegalArgumentException(
×
86
                "Unknown header matcher type: " + proto.getHeaderMatchSpecifierCase());
×
87
    }
88
  }
89

90
  /** Translate StringMatcher envoy proto to internal StringMatcher. */
91
  public static Matchers.StringMatcher parseStringMatcher(
92
            io.envoyproxy.envoy.type.matcher.v3.StringMatcher proto) {
93
    switch (proto.getMatchPatternCase()) {
1✔
94
      case EXACT:
95
        return Matchers.StringMatcher.forExact(proto.getExact(), proto.getIgnoreCase());
1✔
96
      case PREFIX:
97
        return Matchers.StringMatcher.forPrefix(proto.getPrefix(), proto.getIgnoreCase());
1✔
98
      case SUFFIX:
99
        return Matchers.StringMatcher.forSuffix(proto.getSuffix(), proto.getIgnoreCase());
1✔
100
      case SAFE_REGEX:
101
        return Matchers.StringMatcher.forSafeRegEx(
1✔
102
                Pattern.compile(proto.getSafeRegex().getRegex()));
1✔
103
      case CONTAINS:
104
        return Matchers.StringMatcher.forContains(proto.getContains());
1✔
105
      case MATCHPATTERN_NOT_SET:
106
      default:
107
        throw new IllegalArgumentException(
1✔
108
                "Unknown StringMatcher match pattern: " + proto.getMatchPatternCase());
1✔
109
    }
110
  }
111

112
  /** Translates envoy proto FractionalPercent to internal FractionMatcher. */
113
  public static Matchers.FractionMatcher parseFractionMatcher(
114
      io.envoyproxy.envoy.type.v3.FractionalPercent proto) {
115
    int denominator;
116
    switch (proto.getDenominator()) {
1✔
117
      case HUNDRED:
118
        denominator = 100;
1✔
119
        break;
1✔
120
      case TEN_THOUSAND:
121
        denominator = 10_000;
1✔
122
        break;
1✔
123
      case MILLION:
124
        denominator = 1_000_000;
1✔
125
        break;
1✔
126
      case UNRECOGNIZED:
127
      default:
128
        throw new IllegalArgumentException("Unknown denominator type: " + proto.getDenominator());
1✔
129
    }
130
    return Matchers.FractionMatcher.create(proto.getNumerator(), denominator);
1✔
131
  }
132
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc